asset inventory design

design_3.0_asset_inventory_module
WaseemAbbasi22 4 weeks ago
parent 88f64e2297
commit e5775019a4

@ -10,7 +10,7 @@ class AppAsset {
static String maintenanceIcon = 'maintenance_icon';
static String retiredAssetIcon = 'assets/images/retired_asset_icon.svg';
static String sparePartIcon = 'spare_part_icon';
static String editIcon = 'assets/images/edit_icon.svg';
static String deleteIcon = 'assets/images/delete_icon.svg';
static String editIcon = 'assets/images/edit_icon';
static String deleteIcon = 'assets/images/delete_icon';
static String overDueIcon = 'assets/images/overdue.svg';
}

@ -0,0 +1,144 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/app_style/sizing.dart';
class AutoCompleteGenericField<T extends Object> extends StatefulWidget {
final String? label;
final String initialValue;
final bool clearAfterPick;
final Future<List<T>> Function(String query) onSearch;
final String Function(T item) displayString;
final Function(T item) onPick;
const AutoCompleteGenericField({
Key? key,
this.label,
required this.initialValue,
required this.onSearch,
required this.displayString,
required this.onPick,
this.clearAfterPick = true,
}) : super(key: key);
@override
State<AutoCompleteGenericField<T>> createState() => _AutoCompleteGenericFieldState<T>();
}
class _AutoCompleteGenericFieldState<T extends Object> extends State<AutoCompleteGenericField<T>> {
late TextEditingController _controller;
List<T> _options = [];
bool _isLoading = false;
@override
void initState() {
_controller = TextEditingController(text: widget.initialValue);
super.initState();
}
@override
void didUpdateWidget(covariant AutoCompleteGenericField<T> oldWidget) {
if (widget.initialValue != oldWidget.initialValue) {
_controller.text = widget.initialValue;
}
super.didUpdateWidget(oldWidget);
}
Future<void> _search(String query) async {
if (query.isEmpty) {
setState(() => _options = []);
return;
}
setState(() => _isLoading = true);
try {
final results = await widget.onSearch(query);
setState(() => _options = results);
} finally {
setState(() => _isLoading = false);
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10));
return Container(
decoration: BoxDecoration(
color: AppColor.background(context),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
),
child: RawAutocomplete<T>(
// textEditingController: _controller,
optionsBuilder: (TextEditingValue textEditingValue) => _options,
displayStringForOption: widget.displayString,
fieldViewBuilder: (context, fieldTextEditingController, fieldFocusNode, onFieldSubmitted) {
return TextField(
controller: _controller,
focusNode: fieldFocusNode,
style: AppTextStyles.bodyText.copyWith(color: AppColor.black10),
textAlign: TextAlign.start,
decoration: InputDecoration(
border: border,
disabledBorder: border,
focusedBorder: border,
enabledBorder: border,
errorBorder: border,
contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth),
// suffixIcon: _isLoading
// ? const Padding(
// padding: EdgeInsets.all(8.0),
// child: SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2)),
// )
// : const Icon(Icons.search, size: 18),
filled: true,
fillColor: AppColor.fieldBgColor(context),
labelText: widget.label,
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
),
textInputAction: TextInputAction.search,
onChanged: (text) => _search(text),
onSubmitted: (_) => onFieldSubmitted(),
);
},
onSelected: (T selection) {
if (widget.clearAfterPick) {
_controller.clear();
} else {
_controller.text = widget.displayString(selection);
}
widget.onPick(selection);
},
optionsViewBuilder: (context, onSelected, options) {
return Align(
alignment: Alignment.topLeft,
child: Material(
elevation: 4,
borderRadius: BorderRadius.circular(10),
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 200, minWidth: 200),
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: options.length,
itemBuilder: (context, index) {
final option = options.elementAt(index);
return ListTile(
title: Text(widget.displayString(option)),
onTap: () => onSelected(option),
);
},
),
),
),
);
},
),
);
}
}

@ -4,12 +4,12 @@ class URLs {
static const String appReleaseBuildNumber = "26";
// static const host1 = "https://atomsm.hmg.com"; // production url
// static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
// static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
// static String _baseUrl = "$_host/mobile";
// static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
static final String _baseUrl = "$_host/mobile"; // host local UAT
static final String _baseUrl = "$_host/v3/mobile"; // new V3 apis
// static final String _baseUrl = "$_host/mobile"; // host local UAT
// static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM
static String _host = host1;
@ -295,4 +295,8 @@ class URLs {
static get addComment => "$_baseUrl/CallRequest/AddHistoryComment"; // add
static get getSiteContactInfo => "$_baseUrl/AssetGroupSiteContactInfo"; // add
// asset inventory Urls.
static get getAssetInventoryById => '$_baseUrl/AssetInventory/GetAssetInventoryById';
// AssetInventory/GetAssetInventoryById
}

@ -143,7 +143,7 @@ class AllRequestsProvider extends ChangeNotifier {
}
final type = typeTransaction == null
? search?.typeTransaction == null || (search?.typeTransaction?.isEmpty ?? false)
? [1, 2, 3, 4, 5, 6,7]
? [1, 2, 3, 4, 5, 6,7,8]
: search!.typeTransaction
: [typeTransaction];
List<int> status = (search?.statuses == null || (search?.statuses?.isEmpty ?? false)) ? (((search?.isArchived ?? false) ? [3] : [1, 2, 4])) : search!.statuses!;

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/inventory_seession_card.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart';
@ -48,6 +49,10 @@ class RequestCategoryList extends StatelessWidget {
return RecurrentWoItemView(requestData: request);
case 6:
return TaskRequestItemView(requestData: request);
case 7:
return TaskRequestItemView(requestData: request);
case 8:
return InventorySessionCard(requestData: request);
default:
return Container(
height: 100,

@ -25,6 +25,7 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart';
import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart';
import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart';
@ -280,6 +281,7 @@ class MyApp extends StatelessWidget {
//ChangeNotifierProvider(create: (_) => RequestStatusProvider()),
ChangeNotifierProvider(create: (_) => VendorProvider()),
ChangeNotifierProvider(create: (_) => PpmChecklistStatusProvider()),
ChangeNotifierProvider(create: (_) => AssetInventoryProvider()),
],
child: GestureDetector(
onTap: () {

@ -0,0 +1,225 @@
class SessionModel {
int? id;
String? sessionName;
int? sessionTypeId;
String? sessionTypeName;
int? statusId;
String? statusName;
String? startDate;
String? endDate;
List<AssetInventorySite> assetInventorySites = [];
List<AssetInventoryAssignedEmployee> assetInventoryAssignedEmployee = [];
SessionModel({
this.id,
this.sessionName,
this.sessionTypeId,
this.sessionTypeName,
this.statusId,
this.statusName,
this.startDate,
this.endDate,
List<AssetInventorySite>? 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'];
sessionTypeName = json['sessionTypeName'];
statusId = json['statusId'];
statusName = json['statusName'];
startDate = json['startDate'];
endDate = json['endDate'];
if (json['assetInventorySites'] != null) {
assetInventorySites = (json['assetInventorySites'] as List).map((e) => AssetInventorySite.fromJson(e)).toList();
}
if (json['assetInventoryAssignedEmployee'] != null) {
assetInventoryAssignedEmployee = (json['assetInventoryAssignedEmployee'] as List).map((e) => AssetInventoryAssignedEmployee.fromJson(e)).toList();
}
}
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['id'] = id;
map['sessionName'] = sessionName;
map['sessionTypeId'] = sessionTypeId;
map['sessionTypeName'] = sessionTypeName;
map['statusId'] = statusId;
map['statusName'] = statusName;
map['startDate'] = startDate;
map['endDate'] = endDate;
map['assetInventorySites'] = assetInventorySites.map((e) => e.toJson()).toList();
map['assetInventoryAssignedEmployee'] = assetInventoryAssignedEmployee.map((e) => e.toJson()).toList();
return map;
}
}
class AssetInventorySite {
int? siteId;
String? siteName;
List<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,95 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/work_order_detail_model.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
class AssetDetailCardView extends StatelessWidget {
WorkOrderData workOrder;
AssetDetailCardView({super.key,required this.workOrder});
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StatusLabel(
label: workOrder.priority?.name,
id: workOrder.priority!.id!,
radius: 4,
textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!),
backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!),
),
8.height,
Text(
context.translation.assetInformation,
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
// 8.height,
Text(
'${context.translation.serialNo}: ${workOrder.workOrderContactPerson[0].name ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.manufacture}: ${workOrder.workOrderContactPerson[0].name}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.model}: ${workOrder.workOrderContactPerson[0].name}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.site}: ${workOrder.workOrderContactPerson[0].name}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.department}: ${workOrder.workOrderContactPerson[0].name}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),Text(
'${context.translation.supplier}: ${workOrder.workOrderContactPerson[0].name}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),Text(
'${'Remarks'.addTranslation}: ${workOrder.workOrderContactPerson[0].name}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
],
).expanded,
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'edit_icon'.toSvgAsset().onPress((){
//Handle edit...
}),
20.width,
'delete_icon'.toSvgAsset().onPress((){
//handle delete..
})
],
),
20.height,
Container(
height: 100,
width:100,
color: Colors.red,
child: 'edit_icon'.toSvgAsset().center,
)
],)
],
).toShadowContainer(context);
}
}

@ -0,0 +1,163 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/work_order_detail_model.dart';
import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart';
import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
class AssetInventoryDetailView extends StatefulWidget {
SessionModel sessionModel;
AssetInventoryDetailView({Key? key, required this.sessionModel}) : super(key: key);
@override
State<AssetInventoryDetailView> createState() => _AssetInventoryDetailViewState();
}
class _AssetInventoryDetailViewState extends State<AssetInventoryDetailView> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
//TODO remove this provider and loading obj as well don't need here ...
return Consumer<ServiceRequestDetailProvider>(builder: (pContext, requestProvider, _) {
return requestProvider.isLoading
? const CircularProgressIndicator(color: AppColor.primary10).center
: requestProvider.currentWorkOrder == null
? const NoDataFound()
: Column(
children: [
SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
requestDetailCard(context, requestProvider.currentWorkOrder!.data!),
12.height,
siteListCard(context, requestProvider.currentWorkOrder!.data!),
// 20.height,
],
),
).expanded,
],
);
});
}
TextStyle infoTextStyle(context) => AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120);
Widget requestDetailCard(BuildContext context, WorkOrderData workOrder) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Wrap(
runSpacing: 8,
children: [
StatusLabel(
label: workOrder.priority?.name,
id: workOrder.priority!.id!,
radius: 4,
textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!),
backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!),
),
8.width,
StatusLabel(
radius: 4,
label: workOrder.status!.name,
textColor: AppColor.getHistoryLogStatusTextColorByName(workOrder.status!.name!),
backgroundColor: AppColor.getHistoryLogStatusColorByName(workOrder.status!.name!),
),
],
).expanded,
Text(
workOrder.requestedDate!.toString().toServiceRequestCardFormat,
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
)
],
),
8.height,
Text(
context.translation.requestDetails,
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
8.height,
Text(
'${'Session Name'.addTranslation}: ${workOrder.assetNdModel!.name?.cleanupWhitespace.capitalizeFirstOfEach}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
// 8.height,
Text(
'${'Session Typ'.addTranslation}: ${workOrder.asset!.assetNumber}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${'Start Date:'.addTranslation}: ${workOrder.asset!.assetSerialNo}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${'End Date:'.addTranslation}: ${workOrder.asset!.assetSerialNo}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
],
).paddingOnly(start: 16, end: 16, top: 16, bottom: 8).toShadowContainer(context, padding: 0);
}
Widget siteListCard(BuildContext context, WorkOrderData workOrder) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
itemBuilder: (cxt, index) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${workOrder.workOrderContactPerson[0].name ?? '-'}',
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
Text(
'${context.translation.building}: ${workOrder.workOrderContactPerson[0].employeeId ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.floor}: ${workOrder.workOrderContactPerson[0].mobilePhone ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.department} ${workOrder.workOrderContactPerson[0].position ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
Text(
'${context.translation.room}: ${workOrder.workOrderContactPerson[0].email ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
],
),
separatorBuilder: (cxt, index) => const Divider().defaultStyle(context),
itemCount: 4),
],
).toShadowContainer(context, padding: 12);
}
}

@ -0,0 +1,426 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/common_widgets/autocomplete_generic_field.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart';
import 'package:test_sa/dashboard_latest/dashboard_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/device/asset_transfer_attachment.dart';
import 'package:test_sa/models/device/device_transfer.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/generic_attachment_model.dart';
import 'package:test_sa/models/new_models/department.dart';
import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/service_request/pending_service_request_model.dart';
import 'package:test_sa/models/service_request/spare_parts.dart';
import 'package:test_sa/models/service_request/supplier_details.dart';
import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/providers/ppm_service_provider.dart';
import 'package:test_sa/providers/work_order/vendor_provider.dart';
import 'package:test_sa/views/pages/user/requests/pending_requests_screen.dart';
import 'package:test_sa/views/widgets/equipment/asset_picker.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker_item.dart';
import 'package:test_sa/views/widgets/parts/auto_complete_parts_field.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import '../../../models/new_models/building.dart';
import '../../../models/new_models/site.dart';
import '../../../new_views/common_widgets/app_filled_button.dart';
import '../../../new_views/common_widgets/default_app_bar.dart';
import '../../../new_views/common_widgets/single_item_drop_down_menu.dart';
import '../../../providers/gas_request_providers/site_provider.dart';
import '../../../providers/loading_list_notifier.dart';
class AssetInventoryFormView extends StatefulWidget {
static const String id = "/request-device-transfer";
const AssetInventoryFormView({Key? key}) : super(key: key);
@override
State<AssetInventoryFormView> createState() => _AssetInventoryFormViewState();
}
class _AssetInventoryFormViewState extends State<AssetInventoryFormView> {
//TODO Need to replace with provider and models we have ...
late DeviceTransferProvider _deviceTransferProvider;
final DeviceTransfer _transferModel = DeviceTransfer(id: 0);
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
Asset _assetDestination = Asset();
Asset? _pickedAsset;
final List<GenericAttachmentModel> attachments = [];
void _onSubmit() async {
_transferModel.assetId = _pickedAsset?.id;
_transferModel.destSiteId = _assetDestination.site?.id;
_transferModel.destBuildingId = _assetDestination.building?.id;
_transferModel.destFloorId = _assetDestination.floor?.id;
_transferModel.destDepartmentId = _assetDestination.department?.id;
_transferModel.destRoomId = _assetDestination.room?.id;
if (!_formKey.currentState!.validate() || !(await validateRequest())) {
return;
}
_formKey.currentState!.save();
List<AssetTransferAttachment> attachement = [];
for (var item in attachments) {
String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
attachement.add(AssetTransferAttachment(id: item.id, attachmentName: fileName));
}
_transferModel.attachments = attachement;
await _deviceTransferProvider.createRequest(
context: context,
model: _transferModel,
);
if (_deviceTransferProvider.stateCode == 200) {
DashBoardProvider dashBoardProvider = Provider.of<DashBoardProvider>(context, listen: false);
dashBoardProvider.refreshDashboard(context: context, userType: UsersTypes.nurse);
}
}
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
//need to get internal and external request type data..
await Provider.of<PpmServiceProvider>(context, listen: false).getData();
});
super.initState();
}
@override
void dispose() {
_deviceTransferProvider.reset();
super.dispose();
}
@override
Widget build(BuildContext context) {
_deviceTransferProvider = Provider.of<DeviceTransferProvider>(context, listen: false);
return Scaffold(
key: _scaffoldKey,
appBar: DefaultAppBar(
title: context.translation.addAsset,
titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
body: Form(
key: _formKey,
child: Column(
children: [
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AssetPicker(
device: _pickedAsset,
showLoading: false,
labelColor: AppColor.white936,
iconColor: AppColor.neutral120,
label: 'Scan Asset'.addTranslation,
borderColor: AppColor.white936,
buttonColor: Colors.white,
showBorder: true,
onPick: (asset) async {
_pickedAsset = asset;
if (_pickedAsset?.site != null && _transferModel.transferType?.value == 1) {
await _deviceTransferProvider.getSiteData(siteId: int.tryParse(_pickedAsset!.site!.id.toString()));
_assetDestination.site = _deviceTransferProvider.internalAssetDestination?.site;
_assetDestination.building = null;
_assetDestination.floor = null;
_assetDestination.department = null;
} else if (_pickedAsset?.site != null && _transferModel.transferType?.value == 2) {
_assetDestination.site = null;
_assetDestination.building = null;
_assetDestination.floor = null;
_assetDestination.department = null;
}
setState(() {});
}),
12.height,
AppTextFormField(
labelText: context.translation.assetNo,
backgroundColor: AppColor.fieldBgColor(context),
textAlign: TextAlign.center,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
style: Theme.of(context).textTheme.titleMedium,
),
12.height,
AppTextFormField(
labelText: context.translation.serialNo,
backgroundColor: AppColor.fieldBgColor(context),
textAlign: TextAlign.center,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
style: Theme.of(context).textTheme.titleMedium,
),
12.height,
//TODO need to indentify where to
12.height,
//model..
AutoCompleteGenericField<SparePartsWorkOrders>(
clearAfterPick: false,
label: 'Asset Name'.addTranslation,
displayString: (item) => "",
onSearch: (query) async {
// final provider = Provider.of<PartsProvider>(context, listen: false);
// final list = await provider.getPartsList(partName: query);
// return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList();
return [];
},
initialValue: '',
// initialValue: model.partCatalogItem?.partNumber ?? "",
onPick: (part) {
setState(() {});
},
),
12.height,
//Asset Name..
AutoCompleteGenericField<SparePartsWorkOrders>(
clearAfterPick: false,
label: 'Manufacturer'.addTranslation,
displayString: (item) => "",
onSearch: (query) async {
// final provider = Provider.of<PartsProvider>(context, listen: false);
// final list = await provider.getPartsList(partName: query);
// return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList();
return [];
},
initialValue: '',
// initialValue: model.partCatalogItem?.partNumber ?? "",
onPick: (part) {
setState(() {});
},
),
12.height,
//manufacture..
AutoCompleteGenericField<SparePartsWorkOrders>(
clearAfterPick: false,
label: 'Model'.addTranslation,
displayString: (item) => "",
onSearch: (query) async {
// final provider = Provider.of<PartsProvider>(context, listen: false);
// final list = await provider.getPartsList(partName: query);
// return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList();
return [];
},
initialValue: '',
// initialValue: model.partCatalogItem?.partNumber ?? "",
onPick: (part) {
setState(() {});
},
),
12.height,
//model..
AutoCompleteGenericField<SparePartsWorkOrders>(
clearAfterPick: false,
label: 'Asset Name'.addTranslation,
displayString: (item) => "",
onSearch: (query) async {
// final provider = Provider.of<PartsProvider>(context, listen: false);
// final list = await provider.getPartsList(partName: query);
// return list.map((e) => SparePartsWorkOrders(sparePart: e)).toList();
return [];
},
initialValue: '',
// initialValue: model.partCatalogItem?.partNumber ?? "",
onPick: (part) {
setState(() {});
},
),
12.height,
SingleItemDropDownMenu<SupplierDetails, VendorProvider>(
context: context,
title: context.translation.supplier,
backgroundColor: AppColor.fieldBgColor(context),
initialValue: null,
showAsBottomSheet: true,
showShadow: false,
showCancel: true,
onSelect: (supplier) {
setState(() {});
},
),
12.height,
12.height,
SingleItemDropDownMenu<Site, SiteProvider>(
context: context,
title: context.translation.site,
initialValue: _assetDestination.site,
disableValue: _pickedAsset?.site,
showShadow: false,
loading: _deviceTransferProvider.isSiteLoading,
enabled: false,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
onSelect: (value) {
_assetDestination.site = value;
_assetDestination.building = null;
_assetDestination.floor = null;
_assetDestination.department = null;
setState(() {});
},
),
12.height,
SingleItemDropDownMenu<Building, NullableLoadingProvider>(
context: context,
title: context.translation.building,
initialValue: _assetDestination.building,
showShadow: false,
showAsBottomSheet: true,
backgroundColor: AppColor.fieldBgColor(context),
enabled: _assetDestination.site?.buildings?.isNotEmpty ?? false,
staticData: _assetDestination.site?.buildings ?? [],
onSelect: (value) {
_assetDestination.building = value;
_assetDestination.floor = null;
_assetDestination.department = null;
setState(() {});
},
),
12.height,
SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
context: context,
title: context.translation.floor,
showShadow: false,
showAsBottomSheet: true,
initialValue: _assetDestination.floor,
backgroundColor: AppColor.fieldBgColor(context),
enabled: _assetDestination.building?.floors?.isNotEmpty ?? false,
staticData: _assetDestination.building?.floors ?? [],
onSelect: (value) {
_assetDestination.floor = value;
_assetDestination.department = null;
setState(() {});
},
),
12.height,
SingleItemDropDownMenu<Department, NullableLoadingProvider>(
context: context,
title: context.translation.department,
showShadow: false,
showAsBottomSheet: true,
initialValue: _assetDestination.department,
backgroundColor: AppColor.fieldBgColor(context),
enabled: _assetDestination.floor?.departments?.isNotEmpty ?? false,
staticData: _assetDestination.floor?.departments ?? [],
onSelect: (value) {
_assetDestination.department = value;
_assetDestination.room = null;
setState(() {});
},
),
12.height,
classificationWidget(label: 'Found'),
12.height,
Text(
'Asset Photo'.addTranslation,
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936),
),
12.height,
attachments.isEmpty
? AttachmentPicker(
label: context.translation.attachImage,
attachment: attachments,
buttonColor: AppColor.black10,
onlyImages: true,
onChange: (value) {
setState(() {});
},
buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
)
: MultiFilesPickerItem(
file: File(attachments.first.name ?? ''),
enabled: true,
onRemoveTap: (file) {
setState(() {
attachments.clear();
});
},
),
12.height,
AppTextFormField(
backgroundColor: AppColor.fieldBgColor(context),
labelText: 'Remarks'.addTranslation,
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
alignLabelWithHint: true,
textInputType: TextInputType.multiline,
showShadow: false,
onSaved: (text) {
_transferModel.comment = text;
},
),
// 100.height,
],
).toShadowContainer(context).paddingOnly(top: 20, start: 16, end: 16),
).expanded,
10.height,
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.submitRequest, maxWidth: true, onPressed: _onSubmit),
),
],
),
),
);
}
Widget classificationWidget({String? label}) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Classification'.addTranslation,
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936),
),
//TODO Need to set background and text color according to data..
StatusLabel(
label: label,
radius: 4,
textColor: AppColor.getPriorityStatusTextColor(context, 81),
backgroundColor: AppColor.getPriorityStatusColor(context, 370),
),
],
);
}
Future<bool> validateRequest() async {
if (_pickedAsset == null) {
await Fluttertoast.showToast(msg: "Please Select Asset");
return false;
}
if (_assetDestination.site == null) {
await Fluttertoast.showToast(msg: "Please Select Site");
return false;
}
if (_assetDestination.building == null) {
await Fluttertoast.showToast(msg: "Please Select Building");
return false;
}
if (_assetDestination.floor == null) {
await Fluttertoast.showToast(msg: "Please Select Floor");
return false;
}
if (_assetDestination.department == null) {
await Fluttertoast.showToast(msg: "Please Select Department");
return false;
}
return true;
}
}

@ -0,0 +1,116 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/pick_site_information_view.dart';
import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import '../provider/asset_inventory_provider.dart';
class AssetInventoryPage extends StatefulWidget {
final int sessionId;
const AssetInventoryPage({Key? key, required this.sessionId}) : super(key: key);
@override
_AssetInventoryPageState createState() {
return _AssetInventoryPageState();
}
}
class _AssetInventoryPageState extends State<AssetInventoryPage> {
late AssetInventoryProvider _assetInventoryProvider;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
getInitialData();
});
}
Future<void> getInitialData() async {
_assetInventoryProvider = Provider.of<AssetInventoryProvider>(context, listen: false);
ServiceRequestDetailProvider _provider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
await _provider.getWorkOrderById(id: widget.sessionId);
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: DefaultAppBar(
title: 'Inventory Session Request'.addTranslation,
onBackPress: () {
Navigator.pop(context);
},
),
body: DefaultTabController(
length: 2,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <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} (1)', height: 57.toScreenHeight),
],
),
),
12.height,
TabBarView(
children: [
AssetInventoryDetailView(sessionModel: SessionModel(),),
AssetInventoryScanAssetView(workOrderData: Provider.of<ServiceRequestDetailProvider>(context,listen: false).currentWorkOrder!.data!,),
],
).expanded,
SafeArea(
top: false,
right: false,
left: false,
child: FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
buttonColor: AppColor.primary10,
label: 'Scan Assets'.addTranslation,
onPressed: _scanAsset,
// buttonColor: AppColor.primary10,
),
),
).toShadowContainer(context, padding: 0, showShadow: false, borderRadius: 0),
],
),
));
}
Future<void> _scanAsset() async {
Navigator.push(context, MaterialPageRoute(builder: (contxt) => PickSiteInformationView(sessionModel: SessionModel())));
}
}

@ -0,0 +1,53 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/work_order_detail_model.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_form_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'asset_detail_card_view.dart';
class AssetInventoryScanAssetView extends StatelessWidget {
WorkOrderData workOrderData ;
AssetInventoryScanAssetView({Key? key,required this.workOrderData}) : super(key: key);
@override
Widget build(BuildContext context) {
return SafeArea(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
itemBuilder: (cxt, index) => AssetDetailCardView(workOrder:workOrderData),
separatorBuilder: (cxt, index) => 12.height,
itemCount: 4),
12.height,
AppFilledButton(
label: "Add Asset".addTranslation,
maxWidth: true,
height: 70,
textColor: AppColor.textColor(context),
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed:()=> _addAsset(context),
),
],
).paddingOnly(start: 16, end: 16,),
),
);
}
void _addAsset(BuildContext context ){
//TODO need to confirm navigation...
Navigator.push(context, MaterialPageRoute(builder: (contxt) => const AssetInventoryFormView()));
}
}

@ -0,0 +1,133 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_page.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
class InventorySessionCard extends StatelessWidget {
final Data? requestData;
final RequestsDetails? requestDetails;
final bool showShadow;
const InventorySessionCard({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key);
@override
Widget build(BuildContext context) {
if (requestData != null) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StatusLabel(
label: requestData!.priorityName!,
textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.priorityName!),
backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.priorityName!),
),
8.width,
StatusLabel(
label: requestData!.statusName!,
textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!),
backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!),
),
1.width.expanded,
Text(
requestData!.transactionDate?.toServiceRequestCardFormat ?? "",
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
),
],
),
8.height,
(requestData?.typeTransaction ?? context.translation.taskRequest).heading5(context),
//TODO replace with Api Data..
infoWidget(label: 'Type'.addTranslation, value: requestData?.requestNo, context: context),
infoWidget(label: 'Assets'.addTranslation, value: requestData?.assetName, context: context),
infoWidget(label: 'Sites'.addTranslation, value: requestData?.assetNumber, context: context),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
context.translation.viewDetails,
style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
),
4.width,
Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14)
],
),
],
).toShadowContainer(context, withShadow: showShadow).onPress(() async {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => AssetInventoryPage(
sessionId: requestData!.id!,
)));
});
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StatusLabel(
label: requestDetails!.priority!,
textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.priority!),
backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.priority!),
),
8.width,
StatusLabel(
label: requestDetails!.status!,
textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!),
backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!),
),
1.width.expanded,
Text(
requestDetails!.date?.toServiceRequestCardFormat ?? "",
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
),
],
),
8.height,
(requestDetails?.nameOfType ?? context.translation.taskRequest).heading5(context),
8.height,
//TODO replace with Api Data..
infoWidget(label: 'Type'.addTranslation, value: requestDetails?.requestNo, context: context),
infoWidget(label: 'Assets'.addTranslation, value: requestDetails?.assetName, context: context),
infoWidget(label: 'Sites'.addTranslation, value: requestDetails?.site, context: context),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
context.translation.viewDetails,
style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
),
4.width,
Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14)
],
),
],
).toShadowContainer(context, withShadow: showShadow).onPress(() async {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => AssetInventoryPage(
sessionId: requestDetails!.id!,
)));
});
}
Widget infoWidget({required String label, String? value, required BuildContext context}) {
if (value != null && value.isNotEmpty) {
return '$label: $value'.bodyText(context);
}
return const SizedBox();
}
}

@ -0,0 +1,225 @@
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/new_models/building.dart';
import 'package:test_sa/models/new_models/department.dart';
import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/room_model.dart';
import 'package:test_sa/models/new_models/work_order_detail_model.dart';
import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_detail_card_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/asset_inventory_form_view.dart';
import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
import 'package:test_sa/providers/gas_request_providers/site_provider.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import '../../../models/new_models/site.dart';
class PickSiteInformationView extends StatefulWidget {
SessionModel sessionModel;
PickSiteInformationView({Key? key, required this.sessionModel}) : super(key: key);
@override
State<PickSiteInformationView> createState() => _PickSiteInformationViewState();
}
class _PickSiteInformationViewState extends State<PickSiteInformationView> {
late SessionModel _sessionModel;
//TODO need to remove this ...
Asset _assetDestination = Asset();
late ServiceRequestDetailProvider _requestDetailProvider;
void _onSave() async {}
@override
void initState() {
_sessionModel = widget.sessionModel;
super.initState();
}
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
_requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
return Scaffold(
key: _scaffoldKey,
appBar: DefaultAppBar(
title: 'Inventory Session Request'.addTranslation,
titleStyle: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
body: Column(
children: [
SingleChildScrollView(
child: Column(
children: [
siteInfoCard(context),
12.height,
assetDetailCard(context, _requestDetailProvider.currentWorkOrder!.data!),
12.height,
AppFilledButton(
label: "Add Asset".addTranslation,
maxWidth: true,
height: 70,
textColor: AppColor.textColor(context),
buttonColor: context.isDark ? AppColor.neutral60 : AppColor.white10,
icon: Icon(Icons.add_circle, color: AppColor.blueStatus(context)),
showIcon: true,
onPressed: _addAsset,
),
12.height,
],
).paddingOnly(start: 16, end: 16, top: 16),
).expanded,
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(buttonColor: AppColor.primary10, label: context.translation.save, maxWidth: true, onPressed: _onSave),
),
],
)
);
}
void _addAsset(){
Navigator.push(context, MaterialPageRoute(builder: (contxt) => const AssetInventoryFormView()));
}
Widget assetDetailCard(BuildContext context, WorkOrderData workOrder) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
itemBuilder: (cxt, index) => AssetDetailCardView(workOrder:workOrder),
separatorBuilder: (cxt, index) => 12.height,
itemCount: 4),
],
);
}
Widget siteInfoCard(BuildContext context,){
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
12.height,
SingleItemDropDownMenu<Site, SiteProvider>(
context: context,
title: context.translation.site,
initialValue: _assetDestination.site,
showShadow: false,
// loading: _deviceTransferProvider.isSiteLoading,
backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true,
onSelect: (value) {
_assetDestination.site = value;
_assetDestination.building = null;
_assetDestination.floor = null;
_assetDestination.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Building, NullableLoadingProvider>(
context: context,
title: context.translation.building,
initialValue: _assetDestination.building,
showShadow: false,
showAsBottomSheet: true,
backgroundColor: AppColor.fieldBgColor(context),
enabled: _assetDestination.site?.buildings?.isNotEmpty ?? false,
staticData: _assetDestination.site?.buildings ?? [],
onSelect: (value) {
_assetDestination.building = value;
_assetDestination.floor = null;
_assetDestination.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Floor, NullableLoadingProvider>(
context: context,
title: context.translation.floor,
showShadow: false,
showAsBottomSheet: true,
initialValue: _assetDestination.floor,
backgroundColor: AppColor.fieldBgColor(context),
enabled: _assetDestination.building?.floors?.isNotEmpty ?? false,
staticData: _assetDestination.building?.floors ?? [],
onSelect: (value) {
_assetDestination.floor = value;
_assetDestination.department = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Department, NullableLoadingProvider>(
context: context,
title: context.translation.department,
showShadow: false,
showAsBottomSheet: true,
initialValue: _assetDestination.department,
backgroundColor: AppColor.fieldBgColor(context),
enabled: _assetDestination.floor?.departments?.isNotEmpty ?? false,
staticData: _assetDestination.floor?.departments ?? [],
onSelect: (value) {
_assetDestination.department = value;
_assetDestination.room = null;
setState(() {});
},
),
8.height,
SingleItemDropDownMenu<Rooms, NullableLoadingProvider>(
context: context,
title: context.translation.room,
showShadow: false,
showAsBottomSheet: true,
initialValue: _assetDestination.room,
backgroundColor: AppColor.fieldBgColor(context),
enabled: _assetDestination.department?.rooms?.isNotEmpty ?? false,
staticData: _assetDestination.department?.rooms ?? [],
onSelect: (value) {
_assetDestination.room = value;
setState(() {});
},
),
8.height,
],
).toShadowContainer(context);
}
Future<bool> validateRequest() async {
if (_assetDestination.site == null) {
await Fluttertoast.showToast(msg: "Please Select Site");
return false;
}
if (_assetDestination.building == null) {
await Fluttertoast.showToast(msg: "Please Select Building");
return false;
}
if (_assetDestination.floor == null) {
await Fluttertoast.showToast(msg: "Please Select Floor");
return false;
}
if (_assetDestination.department == null) {
await Fluttertoast.showToast(msg: "Please Select Department");
return false;
}
return true;
}
}

@ -0,0 +1,62 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/models/service_request/pending_service_request_model.dart';
import 'package:test_sa/models/service_request/service_report.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/models/service_request/service_request_search.dart';
import 'package:test_sa/models/service_request/spare_parts.dart';
import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart';
import 'package:test_sa/models/service_request/supplier_engineer_model.dart';
import 'package:test_sa/models/timer_model.dart';
import 'package:test_sa/modules/asset_inventory_module/models/session_model.dart';
import '../../../models/service_request/search_work_order.dart';
import '../../../models/service_request/wo_call_request.dart';
import '../../../models/user.dart';
import '../../../new_views/common_widgets/app_lazy_loading.dart';
class AssetInventoryProvider extends ChangeNotifier {
final pageItemNumber = 10;
SessionModel? sessionModel;
void reset() {
nextPage = true;
stateCode = null;
}
int? stateCode;
bool isDetailLoading = false;
bool nextPage = true;
bool isLoading = false;
Future getSessionById({required int id}) async {
try {
isLoading = true;
notifyListeners();
final response = await ApiManager.instance.get(URLs.getAssetInventoryById + "?assetInventoryId=$id");
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
sessionModel = await SessionModel.fromJson(json.decode(response.body));
} else {
sessionModel = null;
}
isLoading = false;
notifyListeners();
} catch (e) {
log("getSessionError [error] : $e");
isLoading = false;
sessionModel = null;
notifyListeners();
return null;
}
}
}

@ -1,11 +1,9 @@
import 'package:clipboard/clipboard.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/site_contact_info_model.dart';
@ -77,7 +75,7 @@ class ContactUsBottomSheet extends StatelessWidget {
padding: EdgeInsets.zero,
iconSize: 20,
onPressed: () {
FlutterClipboard.copy('Hello Flutter friends');
// FlutterClipboard.copy('Hello Flutter friends');
},
)
],

@ -3,10 +3,12 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.dart';
import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/user_types.dart';
@ -50,7 +52,7 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
if (context.settingProvider.isUserFlowMedical) {
requestsList.add(Request(7, 'Recall and Alert'));
}
requestsList.add(Request(8, 'Inventory Session'.addTranslation));
_provider = Provider.of<AllRequestsProvider>(context, listen: false);
_provider!.reset();
WidgetsBinding.instance.addPostFrameCallback((_) {

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/inventory_seession_card.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart';
@ -45,44 +46,29 @@ class RequestPaginatedListview extends StatelessWidget {
}
Widget _buildRequestItem(Data request) {
bool isServiceRequest = request.transactionNo == 1;
bool isGasRefill = request.transactionNo == 2;
bool isAssetTransfer = request.transactionNo == 3;
bool isPPMs = request.transactionNo == 4;
bool isRecurrentTask = request.transactionNo == 5;
bool isTask = request.transactionNo == 6;
if (isServiceRequest) {
return ServiceRequestItemView(requestData: request, refreshData: false);
} else if (isGasRefill) {
return GasRefillItemView(requestData: request);
} else if (isPPMs) {
return PpmItemView(requestData: request);
} else if (isAssetTransfer) {
return DeviceItemView(requestData: request);
} else if (isRecurrentTask) {
return RecurrentWoItemView(requestData: request);
} else if (isTask) {
return TaskRequestItemView(requestData: request);
} else {
return Container(
height: 100,
width: double.infinity,
color: Colors.grey,
);
switch (request.transactionNo) {
case 1:
return ServiceRequestItemView(requestData: request);
case 2:
return GasRefillItemView(requestData: request);
case 3:
return DeviceItemView(requestData: request);
case 4:
return PpmItemView(requestData: request);
case 5:
return RecurrentWoItemView(requestData: request);
case 6:
return TaskRequestItemView(requestData: request);
case 7:
return TaskRequestItemView(requestData: request);
case 8:
return InventorySessionCard(requestData: request);
default:
return Container(
height: 100,
width: double.infinity,
color: Colors.grey,
);
}
}
}
// return Column(
// mainAxisSize: MainAxisSize.min,
// children: List.generate(isLoading ? 6 : list.length, (index) {
// // if (isLoading) {
// // return const SizedBox().toRequestShimmer(context, isLoading);
// // }
// // else {
// return Padding(
// padding: EdgeInsets.symmetric(vertical: 10.toScreenHeight),
// child: _buildRequestItem(list[index]));
// // }
// }));

@ -4,6 +4,7 @@ import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/inventory_seession_card.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart';
@ -29,7 +30,8 @@ class RequestItemViewList extends StatelessWidget {
if (isLoading) return const SizedBox().toRequestShimmer(cxt, isLoading);
switch (list[index].transactionType) {
case 1:
return ServiceRequestItemView(requestDetails: list[index]);
// return ServiceRequestItemView(requestDetails: list[index]);
return InventorySessionCard(requestDetails: list[index]);
case 2:
return GasRefillItemView(requestDetails: list[index]);
case 3:
@ -42,6 +44,8 @@ class RequestItemViewList extends StatelessWidget {
return TaskRequestItemView(requestDetails: list[index]);
case 7:
return TaskRequestItemView(requestDetails: list[index]);
case 8:
return InventorySessionCard(requestDetails: list[index]);
default:
Container(
height: 100,

@ -17,8 +17,12 @@ class AssetPicker extends StatelessWidget {
final List<Asset> deviceList;
final bool editable;
final bool showAssetInfo;
final bool showBorder;
final Color? borderColor;
final Color? buttonColor;
final Color? iconColor;
final Color? labelColor;
final String? label;
Color? backgroundColor;
final bool forPPM;
final bool showLoading;
@ -34,8 +38,12 @@ class AssetPicker extends StatelessWidget {
this.onAssetRemove,
this.borderColor,
this.buttonColor,
this.label,
this.iconColor,
this.labelColor,
this.backgroundColor,
this.showAssetInfo = true,
this.showBorder = false,
this.multiSelection = false,
this.forPPM = false,
this.showLoading = false})
@ -57,15 +65,16 @@ class AssetPicker extends StatelessWidget {
decoration: BoxDecoration(
color: buttonColor ?? backgroundColor ?? AppColor.blueStatus(context),
borderRadius: BorderRadius.circular(10),
border: showBorder?Border.all(color: borderColor ?? AppColor.blueStatus(context), width: 2):null,
// boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)],
),
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
"scan_asset".toSvgAsset(height: 22, fit: BoxFit.fitHeight, color: context.isDark ? AppColor.neutral20 : Colors.white),
"scan_asset".toSvgAsset(height: 22, fit: BoxFit.fitHeight, color: context.isDark ? AppColor.neutral20 :iconColor?? Colors.white),
8.width,
"Scan or Pick Asset".bodyText(context).custom(color: context.isDark ? AppColor.neutral20 : Colors.white),
' ${label??"Scan or Pick Asset"}'.bodyText(context).custom(color: context.isDark ? AppColor.neutral20 : labelColor?? Colors.white),
],
),
).onPress(() async {

@ -177,6 +177,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.4.1"
clipboard:
dependency: "direct main"
description:
name: clipboard
sha256: "1920c0337f8808be4166c5f1b236301ff381ef69633b0757c502d97f1f740102"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
clock:
dependency: transitive
description:

Loading…
Cancel
Save