Merge branch 'refs/heads/design_3.0_traf_module' into design_3.0_internal_audit_module

# Conflicts:
#	lib/controllers/api_routes/urls.dart
#	lib/dashboard_latest/widgets/request_category_list.dart
#	lib/new_views/pages/land_page/requests/request_paginated_listview.dart
#	lib/new_views/pages/land_page/widgets/request_item_view_list.dart
design_3.0_internal_audit_module
Sikander Saleem 3 months ago
commit 6ef6bc40a0

@ -38,12 +38,12 @@ android {
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "21" // Must match the compileOptions target
jvmTarget = "17" // Must match the compileOptions target
}
defaultConfig {

@ -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,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);
},
),
);
}
}

@ -1,16 +1,19 @@
class URLs {
URLs._();
static const String appReleaseBuildNumber = "26";
static const String appReleaseBuildNumber = "28";
// static const host1 = "https://atomsm.hmg.com"; // production url
static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
// static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
// static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url
// static String _baseUrl = "$_host/mobile";
static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
// static final String _baseUrl = "$_host/v4/mobile"; // for asset inventory on UAT
// static final String _baseUrl = "$_host/mobile"; // host local UAT
// static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM
// static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation
static String _host = host1;
@ -23,6 +26,8 @@ class URLs {
// API Routes
static get login => "$_baseUrl/MobileAuth/Login";
static get userChangeAssetGroup => "$_baseUrl/MobileAuth/UserChangeAssetGroup";
static get getUserInfo => "$_baseUrl/MobileAuth/GetUserInfo";
static get logout => "$_baseUrl/MobileAuth/Logout";
@ -258,7 +263,9 @@ class URLs {
//Traf
static get addTRAF => "$_baseUrl/TRAF/AddTRAF"; // get
static get getTRAFById => "$_baseUrl/TRAF/GetTRAFById"; // get
static get getAssetAnalytics => "$_baseUrl/Asset/GetAssetAnalytics"; // get
static get getAssetNDAutoCompleteByDynamicCodes => "$_baseUrl/AssetNameDefinition/GetAssetNDAutoCompleteByDynamicCodes"; // get// get
static get getAssetNameAutoComplete => "$_baseUrl/AssetNameDefinition/GetAssetNameAutoComplete"; // get// get
//gas refill
static get getGasTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=606"; // get
@ -295,6 +302,7 @@ class URLs {
static get getNurses => "$_baseUrl/Account/GetUserByRoleValue?value=R-7"; // get
static get getNursesBySiteId => "$_baseUrl/Account/GetUserByRoleValueSiteAndAssetGroupBySiteId?value=R-7"; // get
static get getUsersBasedOnSearch => "$_baseUrl/Account/GetUsersBasedOnSearch"; // get
static get getUserByRoleValueSiteMobileAutocomplete => "$_baseUrl/Account/GetUserByRoleValueSiteMobileAutocomplete"; // get
// pentry
static get getPentry => "$_baseUrl/return/pentry/details"; // get
@ -311,8 +319,32 @@ class URLs {
static get getSiteContactInfo => "$_baseUrl/AssetGroupSiteContactInfo"; // add
static get getDepartmentBasedOnSite => "$_baseUrl/TRAFDataSource/GetDepartmentBasedOnSite"; // add
// asset inventory Urls.
static get getAssetInventoryById => '$_baseUrl/AssetInventory/GetAssetInventoryById';
static get getAssetsInSession => '$_baseUrl/AssetInventory/GetAssetsInSeassion';
static get getInventoryDetailsByFilter => '$_baseUrl/AssetInventory/GetInventoryDetailsByFilter';
static get searchAsset => '$_baseUrl/AssetInventory/SearchAsset';
static get saveAssetInSession => '$_baseUrl/AssetInventory/SaveAssetInSession';
static get deleteAssetInSession => '$_baseUrl/AssetInventory/DeleteAssetInSession';
static get getManufacturerOrModelAutoComplete => '$_baseUrl/AssetInventory/GetManufacturerOrModelAutoComplete';
//internal Audit
static get searchAssetName => '$_baseUrl/AssetInventory/SearchAssetName';
static get getSuppliersAutoCompleteInventory => '$_baseUrl/Supplier/GetSuppliersMobile';
static get getAssetsTemp => '$_baseUrl/AssetInventory/GetAssetsTemp';
static get convertDetailToComplete => '$_baseUrl/AssetInventory/ConvertDetailToComplete';
static get getClassification => '$_baseUrl/AssetInventory/Classification';
//internal Audit
static get getInternalAuditEquipmentById => "$_baseUrl/InternalAuditEquipments/GetInternalAuditEquipmentById";
static get getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemByIdV2";
static get getInternalAuditChecklist => "$_baseUrl/Lookups/GetLookup?lookupEnum=43";
@ -324,5 +356,4 @@ class URLs {
static get updateAuditEquipmentsEngineer => "$_baseUrl/InternalAuditEquipments/UpdateAuditEquipmentsEngineer";
static get updateAuditSystemEngineer => "$_baseUrl/InternalAuditSystems/UpdateAuditSystemEngineer";
static get loadAllWorkOrderDetailsByID => "$_baseUrl/InternalAuditSystems/LoadAllWorkOrderDetailsByID";
}

@ -48,7 +48,6 @@ class GasRefillCommentsProvider extends ChangeNotifier {
late Response response;
try {
response = await ApiManager.instance.get(URLs.getGazRefillComments + "?gasRefillId=$callId");
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
List requestsListJson = json.decode(response.body)["data"];

@ -88,7 +88,7 @@ class OracleCodeProvider extends ChangeNotifier {
Future<List<AssetNDAutoCompleteByDynamicCodesModel>> getAssetByOracleCode(String oracleCode) async {
late Response response;
try {
response = await ApiManager.instance.post(URLs.getAssetNDAutoCompleteByDynamicCodes, body: {"codeValue": oracleCode});
response = await ApiManager.instance.post(URLs.getAssetNameAutoComplete, body: {"pageSize": 1, "pageNumber": 20, "searchText": oracleCode});
List<AssetNDAutoCompleteByDynamicCodesModel> page = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received

@ -46,10 +46,10 @@ class UserSearchProvider extends ChangeNotifier {
notifyListeners();
}
Future<List<UsersBasedOnSearchModel>> getUsersBasedOnSearch(String query) async {
Future<List<UsersBasedOnSearchModel>> getUsersBasedOnSearch(int siteId, String query) async {
late Response response;
try {
response = await ApiManager.instance.get(URLs.getUsersBasedOnSearch + "?searchText=$query");
response = await ApiManager.instance.get(URLs.getUserByRoleValueSiteMobileAutocomplete + "?siteId=$siteId&roleValue=R-7&searchText=$query");
List<UsersBasedOnSearchModel> page = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received

@ -155,6 +155,23 @@ class UserProvider extends ChangeNotifier {
}
}
Future<bool> userChangeAssetGroup() async {
Response response;
try {
response = await ApiManager.instance.post(URLs.userChangeAssetGroup, body: {});
if (response.statusCode >= 200 && response.statusCode < 300) {
User tempUser = await User.fromJson(jsonDecode(response.body));
tempUser.profilePhotoName = URLs.getFileUrl(tempUser!.profilePhotoName);
ApiManager.instance.user = tempUser;
_user = user;
return true;
}
return false;
} catch (error) {
return false;
}
}
Future<bool> logout(BuildContext context) async {
Response response;
try {

@ -37,7 +37,9 @@ class SettingProvider extends ChangeNotifier {
bool get isUserFlowMedical => _assetGroup?.id == 1;
bool get isUserFMS => _assetGroup?.id == 2;
bool get engineerCanCreateCM => isUserFMS;
bool get showPriority => !(isUserFMS && user?.type == UsersTypes.normal_user);
// Local authentication instance
@ -77,8 +79,10 @@ class SettingProvider extends ChangeNotifier {
}
void selectAssetGroup(User user) {
if(user.assetGroups ==null) return;
if (user.assetGroups!.length == 1) {
if (user.assetGroups == null) return;
if (user.selectedAssetGroup != null) {
_assetGroup = user.selectedAssetGroup;
} else if (user.assetGroups!.length == 1) {
_assetGroup = user.assetGroups!.first;
} else {
int fmIndex = user.assetGroups!.indexWhere((element) => element.id == 1);
@ -187,14 +191,13 @@ class SettingProvider extends ChangeNotifier {
}
}
Future<bool> checkIsEnabledFaceId({required bool status}) async {
try {
final response = await ApiManager.instance.post(
URLs.enableFaceId,
showToast: false,
body: <String, dynamic>{
'isEnabled':status,
'isEnabled': status,
},
);
return response.statusCode >= 200 && response.statusCode < 300;
@ -203,7 +206,6 @@ class SettingProvider extends ChangeNotifier {
}
}
Future<bool> checkAppUpdate(String buildNumber, String osType) async {
Response response;
bool isValid = false;

@ -1,13 +1,16 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/providers/settings/setting_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/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/helper/utils.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/pages/user/notifications/notifications_page.dart';
import 'package:test_sa/views/widgets/dialogs/confirm_dialog.dart';
import '../../controllers/providers/api/user_provider.dart';
import '../../models/user.dart';
@ -48,11 +51,11 @@ class AppBarWidget extends StatelessWidget {
children: [
Text(
snapshot.user?.username ?? "", // Simplified null check
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontWeight: FontWeight.w600),
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontWeight: FontWeight.w600, fontSize: context.isTablet() ? 14 : null),
),
Text(
snapshot.user?.type?.name.toCamelCase ?? "", // Simplified null check
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20),
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, fontSize: context.isTablet() ? 12 : null),
),
],
),
@ -83,16 +86,29 @@ class AppBarWidget extends StatelessWidget {
borderRadius: BorderRadius.circular(8),
style: TextStyle(color: Theme.of(context).primaryColor),
underline: const SizedBox.shrink(),
onChanged: (newValue) {
onChanged: (newValue) async {
if (settingProvider.assetGroup != newValue) {
settingProvider.setAssetGroup(newValue);
WidgetsBinding.instance.addPostFrameCallback((_) {
DashBoardProvider dashBoardProvider = Provider.of<DashBoardProvider>(context, listen: false);
dashBoardProvider.setTabs(userType: settingProvider.user!.type!, context: context);
dashBoardProvider.getDashBoardCount(usersType: settingProvider.user!.type!);
dashBoardProvider.resetRequestDataList();
dashBoardProvider.getRequestDetail(usersType: settingProvider.user!.type!, status: dashBoardProvider.tabs[dashBoardProvider.currentListIndex].tag);
});
AssetGroup? tempGroup = ApiManager.instance.assetGroup;
ApiManager.instance.assetGroup = newValue;
Utils.showLoading(context);
bool isSuccess = await context.userProvider.userChangeAssetGroup();
Utils.hideLoading(context);
if (isSuccess) {
settingProvider.setAssetGroup(newValue);
WidgetsBinding.instance.addPostFrameCallback((_) {
context.settingProvider.setUser(ApiManager.instance.user!);
context.userProvider.setUser(ApiManager.instance.user!);
DashBoardProvider dashBoardProvider = Provider.of<DashBoardProvider>(context, listen: false);
dashBoardProvider.setTabs(userType: settingProvider.user!.type!, context: context);
dashBoardProvider.getDashBoardCount(usersType: settingProvider.user!.type!);
dashBoardProvider.resetRequestDataList();
dashBoardProvider.getRequestDetail(usersType: settingProvider.user!.type!, status: dashBoardProvider.tabs[dashBoardProvider.currentListIndex].tag);
});
} else {
ApiManager.instance.assetGroup = tempGroup;
context.showConfirmDialog("Failed, Please Try again");
}
}
},
items: Provider.of<UserProvider>(context, listen: false).user?.assetGroups?.map<DropdownMenuItem<AssetGroup?>>((value) {

@ -73,7 +73,7 @@ class RequestCategoryFragment extends StatelessWidget {
Widget getTabs({required BuildContext context, required DashBoardProvider requestsProvider, required UsersTypes? userType}) {
List<CategoryTabs> tabs = CategoryTabs.getTabs(userType: userType ?? UsersTypes.normal_user, context: context);
return SizedBox(
height: 44 + 16,
height: 44 + (context.isTablet() ? 36 : 16),
child: ListView.separated(
scrollDirection: Axis.horizontal,
separatorBuilder: (cxt, index) => 12.width,

@ -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_session_item_view.dart';
import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/modules/traf_module/traf_request_item_view.dart';
@ -50,6 +51,10 @@ class RequestCategoryList extends StatelessWidget {
return RecurrentWoItemView(requestData: request);
case 6:
return TaskRequestItemView(requestData: request);
case 7:
return TaskRequestItemView(requestData: request);
case 8:
return InventorySessionItemView(requestData: request);
case 9:
return TrafRequestItemView(requestData: request);
//TODO need to verify this ...

@ -19,7 +19,14 @@ extension BuildContextExtension on BuildContext {
SettingProvider get settingProvider => Provider.of<SettingProvider>(this, listen: false);
UserProvider get userProvider => Provider.of<UserProvider>(this, listen: false);
bool isTablet() {
final mediaQueryData = MediaQuery.of(this);
final double screenWidth = mediaQueryData.size.width;
final double screenHeight = mediaQueryData.size.height;
final double devicePixelRatio = mediaQueryData.devicePixelRatio;
bool isTablet = (devicePixelRatio < 2 && (screenWidth >= 700 || screenHeight >= 700)) || (devicePixelRatio >= 2 && (screenWidth >= 1000 || screenHeight >= 1000));
return isTablet;
}
void showConfirmDialog(String message, {String? title, VoidCallback? onTap}) => showDialog(
context: this,
builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap, title: title),

@ -27,6 +27,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/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart';
@ -302,6 +303,7 @@ class MyApp extends StatelessWidget {
//ChangeNotifierProvider(create: (_) => RequestStatusProvider()),
ChangeNotifierProvider(create: (_) => VendorProvider()),
ChangeNotifierProvider(create: (_) => PpmChecklistStatusProvider()),
ChangeNotifierProvider(create: (_) => AssetInventoryProvider()),
],
child: GestureDetector(
onTap: () {

@ -123,11 +123,14 @@ class RequestsDetails {
String? statusReceiver;
String? assetTransferFrom;
String? assetTransferTo;
String? sessionType;
String? code;
String? date;
String? siteTransferFrom;
String? siteTransferTo;
int? transactionType;
int? numberOfAssets;
int? numberOfSites;
RequestsDetails(
{this.id,
@ -142,6 +145,9 @@ class RequestsDetails {
this.manufacturer,
this.requestType,
this.requestNo,
this.numberOfAssets,
this.numberOfSites,
this.sessionType,
this.gasType,
this.site,
this.statusReceiver,
@ -165,6 +171,9 @@ class RequestsDetails {
supplier = json['supplier'];
manufacturer = json['manufacturer'];
requestType = json['requestType'];
sessionType = json['sessionType'];
numberOfAssets = json['numberOfAssets'];
numberOfSites = json['numberOfSites'];
requestNo = json['requestNo'];
gasType = json['gasType'];
site = json['site'];
@ -197,6 +206,9 @@ class RequestsDetails {
data['statusReceiver'] = statusReceiver;
data['assetTransferFrom'] = assetTransferFrom;
data['assetTransferTo'] = assetTransferTo;
data['sessionType'] = sessionType;
data['numberOfSites'] = numberOfSites;
data['numberOfAssets'] = numberOfAssets;
data['code'] = code;
data['date'] = date;
data['siteTransferFrom'] = siteTransferFrom;

@ -142,11 +142,11 @@ class Asset {
Building? building; // Now nullable
Floor? floor; // Now nullable
Department? department; // Now nullable
Rooms? room;
MappedSite? mappedSite; // Now nullable
MappedBuilding? mappedBuilding; // Now nullable
MappedFloor? mappedFloor; // Now nullable
MappedDepartment? mappedDepartment; // No
Rooms? room; // Now nullable
MappedDepartment? mappedDepartment; //
num? testsDay; // Now nullable
num? purchasingPrice; // Now nullable
String? nbv; // Now nullable

@ -1,3 +1,5 @@
import 'dart:developer';
import 'package:test_sa/models/base.dart';
import 'package:test_sa/models/new_models/floor.dart';
@ -10,15 +12,20 @@ class Building extends Base {
}) : super(identifier: id?.toString() ?? '', name: name); // Handle potential null id
Building.fromJson(dynamic json) {
id = json['id'];
identifier = id?.toString() ?? ''; // Handle potential null id
name = json['name'];
id = json['id'] ?? json['buildingId'];
identifier = id?.toString() ?? '';
name = json['name'] ?? json['buildingName'];
value = json['value'];
if (json['floors'] != null) {
floors = [];
json['floors'].forEach((v) {
floors!.add(Floor.fromJson(v));
});
} else if (json['assetInventoryFloors'] != null) {
floors = [];
json['assetInventoryFloors'].forEach((v) {
floors!.add(Floor.fromJson(v));
});
}
}

@ -50,11 +50,14 @@ class Data {
String? priorityName;
bool? isHighPriority;
String? assetName;
String? sessionType;
String? rejectReason;
String? assetNumber;
String? requestTypeName;
String? requestNo;
int? transactionNo;
int? numberOfSites;
int? numberOfAssets;
String? nameOfType;
Data(
@ -63,6 +66,9 @@ class Data {
this.nameOfType,
this.transactionDate,
this.statusName,
this.numberOfAssets,
this.numberOfSites,
this.sessionType,
this.priorityName,
this.isHighPriority,
this.assetName,
@ -79,6 +85,9 @@ class Data {
priorityName = json['priorityName'];
isHighPriority = json['isHighPriority'];
assetName = json['assetName'];
sessionType = json['sessionType'];
numberOfSites = json['numberOfSites'];
numberOfAssets = json['numberOfAssets'];
assetNumber = json['assetNumber'];
requestTypeName = json['requestTypeName'];
requestNo = json['requestNo'];
@ -101,6 +110,9 @@ class Data {
data['requestNo'] = requestNo;
data['rejectReason'] = rejectReason;
data['transactionNo'] = transactionNo;
data['sessionType'] = sessionType;
data['numberOfAssets'] = numberOfAssets;
data['numberOfSites'] = numberOfSites;
data['nameOfType'] = nameOfType;
return data;
}

@ -13,7 +13,7 @@ class Department extends Base {
}) : super(identifier: id?.toString() ?? '', name: departmentName); // Handle potential null id
Department.fromJson(dynamic json) {
id = json['id'];
id = json['id']??json['departmentId'];
identifier = id?.toString() ?? ''; // Handle potential null id
departmentName = json['departmentName'] ?? json['name'];
name = departmentName;
@ -25,6 +25,11 @@ class Department extends Base {
json['rooms'].forEach((v) {
rooms!.add(Rooms.fromJson(v)); // Use '!' since rooms is non-nullable after initialization
});
} else if (json['assetInventoryRooms'] != null) {
rooms = [];
json['assetInventoryRooms'].forEach((v) {
rooms!.add(Rooms.fromJson(v)); // Use '!' since rooms is non-nullable after initialization
});
}
}
@ -33,7 +38,7 @@ class Department extends Base {
String? departmentCode; // Now nullable
dynamic departmentId; // Now nullable
String? ntCode; // Now nullable
List<Rooms>? rooms; // Now nullable
List<Rooms>? rooms=[]; // Now nullable
Department copyWith({
num? id, // Parameters are now nullable

@ -10,9 +10,9 @@ class Floor extends Base {
}) : super(identifier: id?.toString() ?? '', name: name); // Handle potentialnull id
Floor.fromJson(dynamic json) {
id = json['id'];
id = json['id']??json['floorId'];
identifier = id?.toString() ?? ''; // Handle potential null id
name = json['name'];
name = json['name']??json['floorName'];
value = json['value'];
if (json['departments'] != null) {
departments = [];
@ -20,6 +20,12 @@ class Floor extends Base {
departments!.add(Department.fromJson(v)); // Use '!' since departments is non-nullable after initialization
});
}
else if (json['assetInventoryDepartments'] != null) {
departments = [];
json['assetInventoryDepartments'].forEach((v) {
departments!.add(Department.fromJson(v)); // Use '!' since departments is non-nullable after initialization
});
}
}
num? id; // Now nullable

@ -10,8 +10,8 @@ class Rooms extends Base {
Rooms.fromJson(Map<String, dynamic>? json) {
// Handle potential null json input
id = json?['id']; // Use null-aware operator
name = json?['name'];
id = json?['id']?? json?['roomId'];
name = json?['name']??json?['roomName'];
value = json?['value'];
}

@ -9,9 +9,9 @@ class Site extends Base {
}) : super(identifier: id?.toString() ?? '', name: custName); // Handle potential null id
Site.fromJson(dynamic json) {
id = json['id'];
id = json['siteId'] ?? json['id'];
identifier = id?.toString() ?? ''; // Handle potential null id
custName = json['custName']?? json['siteName'];
custName = json['custName']?? json['siteName'];
name = custName;
if (json['buildings'] != null) {
buildings = [];
@ -19,6 +19,12 @@ class Site extends Base {
buildings!.add(Building.fromJson(v)); // Use '!' since buildings is initialized here
});
}
else if (json['assetInventoryBuildings'] != null) {
buildings = [];
json['assetInventoryBuildings'].forEach((v) {
buildings!.add(Building.fromJson(v));
});
}
}
num? id; // Now nullable

@ -928,6 +928,8 @@ class TaskAsset {
String? roomName;
String? supplierName;
String? assetTypeName;
String? poNumber;
String? installationDate;
TaskAsset();
@ -946,24 +948,26 @@ class TaskAsset {
roomName = json['roomName'];
supplierName = json['supplierName'];
assetTypeName = json['assetTypeName'];
poNumber = json['poNumber'];
installationDate = json['installationDate'];
}
Map<String, dynamic> toJson() {
return {
'id': id,
'assetNumber': assetNumber,
'serialNo': serialNo,
'assetName': assetName,
'model': model,
'manufacturer': manufacturer,
'siteName': siteName,
'siteId': siteId,
'buildingName': buildingName,
'floorName': floorName,
'departmentName': departmentName,
'roomName': roomName,
'supplierName': supplierName,
'assetTypeName': assetTypeName,
};
}
Map<String, dynamic> toJson() => {
'id': id,
'assetNumber': assetNumber,
'serialNo': serialNo,
'assetName': assetName,
'model': model,
'manufacturer': manufacturer,
'siteName': siteName,
'siteId': siteId,
'buildingName': buildingName,
'floorName': floorName,
'departmentName': departmentName,
'roomName': roomName,
'supplierName': supplierName,
'assetTypeName': assetTypeName,
'poNumber': poNumber,
'installationDate': installationDate,
};
}

@ -6,17 +6,11 @@ class UsersBasedOnSearchModel {
int? languageId;
String? extensionNo;
String? phoneNumber;
String? positionName;
String? position;
bool? isActive;
UsersBasedOnSearchModel(
{this.userId,
this.userName,
this.email,
this.employeeId,
this.languageId,
this.extensionNo,
this.phoneNumber,
this.isActive});
UsersBasedOnSearchModel({this.userId, this.userName, this.email, this.employeeId, this.languageId, this.extensionNo, this.phoneNumber, this.positionName, this.position, this.isActive});
UsersBasedOnSearchModel.fromJson(Map<String, dynamic> json) {
userId = json['userId'];
@ -26,6 +20,8 @@ class UsersBasedOnSearchModel {
languageId = json['languageId'];
extensionNo = json['extensionNo'];
phoneNumber = json['phoneNumber'];
positionName = json['positionName'];
position = json['position'];
isActive = json['isActive'];
}
@ -38,6 +34,8 @@ class UsersBasedOnSearchModel {
data['languageId'] = this.languageId;
data['extensionNo'] = this.extensionNo;
data['phoneNumber'] = this.phoneNumber;
data['positionName'] = this.positionName;
data['position'] = this.position;
data['isActive'] = this.isActive;
return data;
}

@ -11,7 +11,6 @@ class User {
List<int>? departmentId;
List<String>? departmentName;
String? message;
String? username;
String? userID;
String? email;
@ -39,6 +38,7 @@ class User {
bool? lockoutEnabled;
int? accessFailedCount;
List<AssetGroup>? assetGroups;
AssetGroup? selectedAssetGroup;
bool? employeeIsHMG;
bool? enableWifi;
bool? enableNFC;
@ -158,6 +158,7 @@ class User {
map['assetGroups'] = assetGroups!.map((v) => v.toJson()).toList();
}
map['tokenlife'] = tokenlife;
map['selectedAssetGroup'] = selectedAssetGroup?.toJson();
map['isAuthenticated'] = isAuthenticated;
map['hasError'] = hasError;
map['profilePhotoName'] = profilePhotoName;
@ -217,7 +218,7 @@ class User {
userRoles!.add(UserRoles.fromJson(v));
});
}
selectedAssetGroup = json['selectedAssetGroup'] != null ? AssetGroup.fromJson(json['selectedAssetGroup']) : null;
if (json['assetGroups'] != null) {
assetGroups = <AssetGroup>[];
json['assetGroups'].forEach((v) {

@ -0,0 +1,297 @@
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? transactionDate;
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.transactionDate,
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'];
transactionDate = json['transactionDate'];
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,
'transactionDate': transactionDate,
'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,
transactionDate: transactionDate ?? other.transactionDate,
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,234 @@
import 'package:test_sa/models/new_models/site.dart';
class SessionModel {
int? id;
String? createdDate;
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.createdDate,
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'];
createdDate = json['createdDate'];
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['createdDate'] = createdDate;
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,117 @@
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(
'transaction Date: ${assetInventoryModel.transactionDate?.toServiceRequestDetailsFormat ?? '-'}',
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120),
),
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(
'${'Classifications'.addTranslation}: ${assetInventoryModel.status ?? ''}',
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.createdDate!.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 Type'.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,485 @@
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/modules/asset_inventory_module/models/asset_inventory_model.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';
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();
if (value) {
_scannedAssetModel?.status = 'Not Registered';
}
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;
getClassificationData(assetImportId: _pickedAssetModel?.assetImportId);
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 ?? '-'),
],
if (_scannedAssetModel?.status != null && _scannedAssetModel!.status!.isNotEmpty) ...[
12.height,
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(assetNumber: _scannedAssetModel?.assetNumber, assetId: _scannedAssetModel?.assetId);
}
_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(),
);
}
Future<void> getClassificationData({num? assetImportId}) async {
AssetInventoryProvider provider = Provider.of<AssetInventoryProvider>(context, listen: false);
Map<String, dynamic> payload = {
"assetImportId": assetImportId,
"sessionId": widget.assetInventoryModel?.sessionId,
"siteId": widget.assetInventoryModel?.site?.id,
"buildingId": widget.assetInventoryModel?.building?.id,
"floorId": widget.assetInventoryModel?.floor?.id,
"departmentId": widget.assetInventoryModel?.department?.id,
};
await provider.getClassification(payload: payload).then((value) {
if (value != null) {
_scannedAssetModel?.status = value;
}
setState(() {});
});
}
}

@ -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,466 @@
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 {
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<String?> getClassification({
required Map<String, dynamic> payload,
}) async {
isLoading = true;
String? classification;
try {
final response = await ApiManager.instance.post(URLs.getClassification, body: payload);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
log('classifcation on response ${json.decode(response.body)["data"]['classification']}');
classification = json.decode(response.body)["data"]['classification'];
isLoading = false;
notifyListeners();
return classification;
} else {
isLoading = false;
notifyListeners();
return classification;
}
} catch (error) {
isLoading = false;
notifyListeners();
return classification;
}
}
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;
}
}
}

@ -138,20 +138,20 @@ class _ServiceRequestDetailViewState extends State<ServiceRequestDetailView> {
if (Provider.of<SettingProvider>(context, listen: false).showPriority) ...[
StatusLabel(
label: workOrder.priority?.name,
id: workOrder.priority!.id!,
id: workOrder.priority!.value!,
radius: 4,
textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!),
backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!),
textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.value!),
backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.value!),
),
8.width,
],
if (workOrder.itgFormWorkOrderStatus != null) ...[
StatusLabel(
label: workOrder.itgFormWorkOrderStatus,
id: 0,
// id: 0,
radius: 4,
textColor: AppColor.getPriorityStatusTextColor(context, 82),
backgroundColor: AppColor.getPriorityStatusColor(context, 0),
backgroundColor: AppColor.getPriorityStatusColor(context, 1000),
),
8.width,
],

@ -120,16 +120,16 @@ class _PpmDetailsPageState extends State<PpmDetailsPage> {
context: context,
)
] else ...[
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
onPressed: () async {
await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdatePpm(ppm: null, planPreventiveVisit: planPreventiveVisit)));
getVisitData();
},
label: context.translation.viewDetails,
),
)
// FooterActionButton.footerContainer(
// context: context,
// child: AppFilledButton(
// onPressed: () async {
// await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdatePpm(ppm: null, planPreventiveVisit: planPreventiveVisit)));
// getVisitData();
// },
// label: context.translation.viewDetails,
// ),
// )
]
])
: const Center(child: NoDataFound());

@ -58,7 +58,7 @@ class _PpmExternalDetailsFormState extends State<PpmExternalDetailsForm> {
final ppmProvider = Provider.of<PpmProvider>(context, listen: false);
return ListView.builder(
itemCount: widget.models!.length + 1,
padding: const EdgeInsets.all(16),
padding: const EdgeInsets.only(left: 16, right: 16, top: 8, bottom: 16),
itemBuilder: (context, index) {
if (index == widget.models!.length) {
return Visibility(
@ -190,7 +190,7 @@ class _ExternalDetailItemState extends State<ExternalDetailItem> {
),
child: Icon(Icons.add, color: context.isDark ? null : AppColor.neutral60),
).onPress(() async {
if(widget.model.supplier==null) {
if (widget.model.supplier == null) {
"Please select supplier".showToast;
return;
}

@ -108,7 +108,7 @@ class _UpdatePpmState extends State<UpdatePpm> with TickerProviderStateMixin {
if (typeOfService == null) {
return;
}
if (typeOfService?.id == 66) {
if (typeOfService?.value == 2) {
ppmProvider.totalTabs = 4;
} else {
ppmProvider.totalTabs = 3;

@ -299,7 +299,7 @@ class _WoInfoFormState extends State<WoInfoForm> {
onSelect: (value) {
if (value != null) {
widget.planPreventiveVisit.typeOfService = value;
if (widget.planPreventiveVisit.typeOfService?.id == 66) {
if (widget.planPreventiveVisit.typeOfService?.value == 2) {
ppmProvider.totalTabs = 4;
} else {
ppmProvider.totalTabs = 3;

@ -1,3 +1,4 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
@ -8,12 +9,15 @@ 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/task_request/task_request_model.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/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/working_time_tile.dart';
import 'package:test_sa/providers/task_request_provider/task_request_provider.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
import '../../../../controllers/providers/api/user_provider.dart';
import '../../../../models/enums/user_types.dart';
@ -61,7 +65,6 @@ class _TaskRequestDetailsViewState extends State<TaskRequestDetailsView> {
Widget build(BuildContext context) {
userProvider ??= Provider.of<UserProvider>(context, listen: false);
return Scaffold(
// appBar: DefaultAppBar(title:taskProvider?.taskRequestModel?.taskType?.id==7?'Recall and Alert Details': context.translation.taskRequest),
appBar: DefaultAppBar(title: context.translation.taskRequest),
body: Consumer<TaskRequestProvider>(builder: (context, taskProvider, child) {
TaskData? taskModel = taskProvider.taskRequestModel;
@ -122,6 +125,7 @@ class _TaskRequestDetailsViewState extends State<TaskRequestDetailsView> {
],
),
],
showWorkingTime(taskModel?.taskJobActivityEngineerTimers ?? []),
if ((taskProvider.taskRequestModel?.taskJobContactPersons ?? []).isNotEmpty) ...[contactInfoCard(context, taskProvider.taskRequestModel!)],
if (taskProvider.taskRequestModel?.callComment != null) ...[
const Divider().defaultStyle(context),
@ -167,6 +171,55 @@ class _TaskRequestDetailsViewState extends State<TaskRequestDetailsView> {
);
}
Widget showWorkingTime(List<TaskJobActivityEngineerTimer> timer) {
if (context.userProvider.user!.type == UsersTypes.normal_user) return const SizedBox();
double totalWorkingHours = timer.fold<double>(0.0, (sum, item) {
if (item.startDate == null || item.endDate == null) return sum;
try {
final start = DateTime.parse(item.startDate!);
final end = DateTime.parse(item.endDate!);
final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours
return sum + diffInHours;
} catch (_) {
return sum;
}
});
String totalHourString = (totalWorkingHours > 0.0) ? ServiceRequestUtils.formatTotalWorkingHours(totalWorkingHours) : totalWorkingHours.toString();
return RichText(
text: TextSpan(
text: "${context.translation.totalWorkingTime}: ",
style: TextStyle(
fontSize: 14.toScreenWidth, fontWeight: FontWeight.w500, fontStyle: FontStyle.normal, decoration: TextDecoration.none, color: context.isDark ? AppColor.neutral10 : AppColor.neutral20),
children: [
TextSpan(text: "$totalHourString ", style: AppTextStyles.bodyText),
const WidgetSpan(
child: Icon(Icons.info_outline_rounded, color: AppColor.primary10, size: 14),
),
],
),
).onPress(() => showModalBottomSheet(
context: context,
isDismissible: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
builder: (BuildContext context) => TotalWorkingTimeDetailBottomSheet(
timerList: timer.map((e) {
return TimerHistoryModel(
id: e.id,
startTime: e.startDate,
endTime: e.endDate,
workingHours: e.totalWorkingHour,
);
}).toList()),
));
}
Widget contactInfoCard(BuildContext context, TaskData? taskModel) {
return Column(
mainAxisSize: MainAxisSize.min,
@ -270,6 +323,16 @@ class _TaskRequestDetailsViewState extends State<TaskRequestDetailsView> {
'${context.translation.assetNo}: ${taskModel.asset?.assetNumber ?? "-"}'.bodyText(context),
'${context.translation.manufacture}: ${taskModel.asset?.manufacturer ?? "-"}'.bodyText(context),
'${context.translation.model}: ${taskModel.asset?.model ?? "-"}'.bodyText(context),
'${context.translation.serialNo}: ${taskModel.asset?.serialNo ?? "-"}'.bodyText(context),
'${context.translation.assetType}: ${taskModel.asset?.assetTypeName ?? "-"}'.bodyText(context),
'${context.translation.site}: ${taskModel.asset?.siteName ?? "-"}'.bodyText(context),
'${context.translation.building}: ${taskModel.asset?.buildingName ?? "-"}'.bodyText(context),
'${context.translation.floor}: ${taskModel.asset?.floorName ?? "-"}'.bodyText(context),
'${context.translation.department}: ${taskModel.asset?.departmentName ?? "-"}'.bodyText(context),
'${context.translation.room}: ${taskModel.asset?.roomName ?? "-"}'.bodyText(context),
'${context.translation.supplier}: ${taskModel.asset?.supplierName ?? "-"}'.bodyText(context),
'PO Number: ${taskModel.asset?.poNumber ?? "-"}'.bodyText(context),
'${context.translation.installationDate}: ${taskModel.asset?.installationDate?.toAssetDetailsFormat ?? "-"}'.bodyText(context),
],
)
: const SizedBox();

@ -0,0 +1,172 @@
class AssetAnalytics {
num? assetId;
String? assetNumber;
String? assetName;
num? lastPrice;
String? lastPONo;
String? lastPODate;
num? sameAssetQuantity;
String? slaStatus;
String? contractNumber;
String? contractStartDate;
String? contractEndDate;
num? assetAgeInDays;
String? assetAgeDescription;
num? totalMaintenanceCost;
num? sparePartCost;
num? laborCost;
num? exchangeCost;
num? travelCost;
num? netBookValue;
num? purchasedPrice;
num? lifeSpan;
num? mtbf;
String? mtbfDescription;
num? totalCMWorkOrders;
num? downTimeHours;
String? downTimeDescription;
num? upTimeHours;
String? upTimeDescription;
num? operationHours;
String? installationDate;
String? modelName;
String? manufacturerName;
String? serialNumber;
String? departmentName;
String? siteName;
num? id;
String? createdBy;
String? createdDate;
String? modifiedBy;
String? modifiedDate;
AssetAnalytics(
{this.assetId,
this.assetNumber,
this.assetName,
this.lastPrice,
this.lastPONo,
this.lastPODate,
this.sameAssetQuantity,
this.slaStatus,
this.contractNumber,
this.contractStartDate,
this.contractEndDate,
this.assetAgeInDays,
this.assetAgeDescription,
this.totalMaintenanceCost,
this.sparePartCost,
this.laborCost,
this.exchangeCost,
this.travelCost,
this.netBookValue,
this.purchasedPrice,
this.lifeSpan,
this.mtbf,
this.mtbfDescription,
this.totalCMWorkOrders,
this.downTimeHours,
this.downTimeDescription,
this.upTimeHours,
this.upTimeDescription,
this.operationHours,
this.installationDate,
this.modelName,
this.manufacturerName,
this.serialNumber,
this.departmentName,
this.siteName,
this.id,
this.createdBy,
this.createdDate,
this.modifiedBy,
this.modifiedDate});
AssetAnalytics.fromJson(Map<String, dynamic> json) {
assetId = json['assetId'];
assetNumber = json['assetNumber'];
assetName = json['assetName'];
lastPrice = json['lastPrice'];
lastPONo = json['lastPONo'];
lastPODate = json['lastPODate'];
sameAssetQuantity = json['sameAssetQuantity'];
slaStatus = json['slaStatus'];
contractNumber = json['contractNumber'];
contractStartDate = json['contractStartDate'];
contractEndDate = json['contractEndDate'];
assetAgeInDays = json['assetAgeInDays'];
assetAgeDescription = json['assetAgeDescription'];
totalMaintenanceCost = json['totalMaintenanceCost'];
sparePartCost = json['sparePartCost'];
laborCost = json['laborCost'];
exchangeCost = json['exchangeCost'];
travelCost = json['travelCost'];
netBookValue = json['netBookValue'];
purchasedPrice = json['purchasedPrice'];
lifeSpan = json['lifeSpan'];
mtbf = json['mtbf'];
mtbfDescription = json['mtbfDescription'];
totalCMWorkOrders = json['totalCMWorkOrders'];
downTimeHours = json['downTimeHours'];
downTimeDescription = json['downTimeDescription'];
upTimeHours = json['upTimeHours'];
upTimeDescription = json['upTimeDescription'];
operationHours = json['operationHours'];
installationDate = json['installationDate'];
modelName = json['modelName'];
manufacturerName = json['manufacturerName'];
serialNumber = json['serialNumber'];
departmentName = json['departmentName'];
siteName = json['siteName'];
id = json['id'];
createdBy = json['createdBy'];
createdDate = json['createdDate'];
modifiedBy = json['modifiedBy'];
modifiedDate = json['modifiedDate'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['assetId'] = this.assetId;
data['assetNumber'] = this.assetNumber;
data['assetName'] = this.assetName;
data['lastPrice'] = this.lastPrice;
data['lastPONo'] = this.lastPONo;
data['lastPODate'] = this.lastPODate;
data['sameAssetQuantity'] = this.sameAssetQuantity;
data['slaStatus'] = this.slaStatus;
data['contractNumber'] = this.contractNumber;
data['contractStartDate'] = this.contractStartDate;
data['contractEndDate'] = this.contractEndDate;
data['assetAgeInDays'] = this.assetAgeInDays;
data['assetAgeDescription'] = this.assetAgeDescription;
data['totalMaintenanceCost'] = this.totalMaintenanceCost;
data['sparePartCost'] = this.sparePartCost;
data['laborCost'] = this.laborCost;
data['exchangeCost'] = this.exchangeCost;
data['travelCost'] = this.travelCost;
data['netBookValue'] = this.netBookValue;
data['purchasedPrice'] = this.purchasedPrice;
data['lifeSpan'] = this.lifeSpan;
data['mtbf'] = this.mtbf;
data['mtbfDescription'] = this.mtbfDescription;
data['totalCMWorkOrders'] = this.totalCMWorkOrders;
data['downTimeHours'] = this.downTimeHours;
data['downTimeDescription'] = this.downTimeDescription;
data['upTimeHours'] = this.upTimeHours;
data['upTimeDescription'] = this.upTimeDescription;
data['operationHours'] = this.operationHours;
data['installationDate'] = this.installationDate;
data['modelName'] = this.modelName;
data['manufacturerName'] = this.manufacturerName;
data['serialNumber'] = this.serialNumber;
data['departmentName'] = this.departmentName;
data['siteName'] = this.siteName;
data['id'] = this.id;
data['createdBy'] = this.createdBy;
data['createdDate'] = this.createdDate;
data['modifiedBy'] = this.modifiedBy;
data['modifiedDate'] = this.modifiedDate;
return data;
}
}

@ -105,7 +105,7 @@ class _AssetAutoCompleteFieldState extends State<AssetAutoCompleteField> {
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: context.translation.oracleCode,
labelText: "Name/Oracle Code",
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
suffixIcon: loading ? const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3.0).paddingOnly(end: 8) : null,
),

@ -165,6 +165,10 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
AppTextFormField(
initialValue: "",
labelText: "How would the requested technology solve the current situation and/or serve the purpose?",
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
floatingLabelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
@ -178,6 +182,10 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
AppTextFormField(
initialValue: "",
labelText: "What is the current practice?",
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
@ -191,12 +199,16 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q1",
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
textInputType: TextInputType.number,
textInputType: TextInputType.text,
onChange: (value) {
trafRequest?.censusQ1 = int.tryParse(value);
trafRequest?.censusQ1 = value;
},
),
12.height,
@ -204,12 +216,16 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q2",
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
textInputType: TextInputType.number,
textInputType: TextInputType.text,
onChange: (value) {
trafRequest?.censusQ2 = int.tryParse(value);
trafRequest?.censusQ2 = value;
},
),
12.height,
@ -217,12 +233,16 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q3",
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
textInputType: TextInputType.number,
textInputType: TextInputType.text,
onChange: (value) {
trafRequest?.censusQ3 = int.tryParse(value);
trafRequest?.censusQ3 = value;
},
),
12.height,
@ -230,12 +250,16 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q4",
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
textInputType: TextInputType.number,
textInputType: TextInputType.text,
onChange: (value) {
trafRequest?.censusQ4 = int.tryParse(value);
trafRequest?.censusQ4 = value;
},
),
12.height,
@ -264,7 +288,8 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
dense: true,
contentPadding: EdgeInsets.zero,
title: Text("Name: ${userBasedOnSearch[index].userName ?? ""}"),
subtitle: Text("Email: ${userBasedOnSearch[index].email ?? ""}\nPhone: ${userBasedOnSearch[index].phoneNumber ?? ""}"),
subtitle: Text(
"Position: ${userBasedOnSearch[index].position ?? "-"}\nEmail: ${userBasedOnSearch[index].email ?? ""}\nPhone: ${userBasedOnSearch[index].phoneNumber ?? ""}"),
trailing: const Icon(Icons.delete_rounded, color: Color(0xffF63939), size: 20).onPress(() {
userBasedOnSearch.removeAt(index);
setState(() {});
@ -286,7 +311,7 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: isUsedSolelyOrShared,
onSelect: (value) {
isUsedSolelyOrShared = value;
trafRequest?.usingSolelyOrSharedId = value?.value;
trafRequest?.usingSolelyOrSharedId = value?.id;
if (isUsedSolelyOrShared?.value != 1) {
departments = [];
trafRequest?.trafDepartments = [];
@ -329,7 +354,7 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: otherServicesEffects,
onSelect: (value) {
otherServicesEffects = value;
trafRequest?.isEffectedId = value?.value;
trafRequest?.isEffectedId = value?.id;
if (otherServicesEffects?.value != 1) {
trafRequest?.effectedServices = null;
FocusScope.of(context).unfocus();
@ -347,6 +372,10 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
node: otherServicesEffectsNode,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
labelText: "List down these services and stat how would it be effected",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
@ -367,7 +396,7 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: useInCombination,
onSelect: (value) {
useInCombination = value;
trafRequest?.isCombinationId = value?.value;
trafRequest?.isCombinationId = value?.id;
if (useInCombination?.value != 1) {
trafRequest?.usedWithCombination = null;
FocusScope.of(context).unfocus();
@ -384,6 +413,10 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
node: useInCombinationNode,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
labelText: "kindly describe in detail",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
@ -430,14 +463,51 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
}
void _verifyAndSubmit() async {
if (requestType == null) {
"Select request type".showToast;
return;
} else if (requestType?.value == 1 && trafRequest?.assetNDId == null) {
"Oracle Code missing".showToast;
return;
} else if (requestType?.value == 2 && trafRequest?.assetId == null) {
"Pick asset".showToast;
return;
}
if (!_formKey.currentState!.validate()) return;
trafRequest?.employeeId = context.userProvider.user?.userID;
trafRequest?.siteId = context.userProvider.user?.clientId;
trafRequest?.trafContacts = [];
trafRequest?.trafContacts = userBasedOnSearch.map((item) => TrafContacts(id: 0, trafId: 0, name: item.userName, userId: item.userId)).toList();
if ((trafRequest?.trafContacts ?? []).isEmpty) {
"Please specify users going to use technology".showToast;
return;
}
if (isUsedSolelyOrShared == null) {
"Please specify technology solely or shared".showToast;
return;
}
if (isUsedSolelyOrShared?.value == 1 && (trafRequest?.trafDepartments ?? []).isEmpty) {
"Please specify departments and relations".showToast;
return;
}
if (otherServicesEffects == null) {
"Please specify other services will be effected or not".showToast;
return;
}
if (useInCombination == null) {
"Please specify equipment used in combination or not".showToast;
return;
}
Utils.showLoading(context);
await Provider.of<TrafRequestProvider>(context, listen: false).addTraf(trafRequest!.toJson());
bool isSuccess = await Provider.of<TrafRequestProvider>(context, listen: false).addTraf(trafRequest!.toJson());
Utils.hideLoading(context);
Navigator.pop(context);
if (isSuccess) {
Navigator.pop(context);
}
}
}

@ -13,7 +13,9 @@ 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/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import 'asset_analytics_model.dart';
import 'traf_request_model.dart';
class TrafRequestDetailPage extends StatefulWidget {
@ -51,30 +53,32 @@ class _TrafRequestDetailPageState extends State<TrafRequestDetailPage> {
builder: (_, isLoading, __) {
if (isLoading) return const ALoading();
TrafRequestProvider trafProvider = Provider.of<TrafRequestProvider>(context, listen: false);
return Column(
children: [
ListView(
padding: const EdgeInsets.all(16),
children: [
requesterInformation(trafProvider.trafRequestDataModel!),
12.height,
requestInformation(trafProvider.trafRequestDataModel!),
12.height,
assetInformation(trafProvider.trafRequestDataModel!),
],
).expanded,
// // if (isEngineer)
// FooterActionButton.footerContainer(
// context: context,
// child: AppFilledButton(
// buttonColor: AppColor.primary10,
// label: "Update",
// onPressed: () {
// Navigator.pushNamed(context, UpdateTrafRequestPage.id);
// }),
// ),
],
);
return trafProvider.trafRequestDataModel == null
? const NoDataFound().center
: Column(
children: [
ListView(
padding: const EdgeInsets.all(16),
children: [
requesterInformation(trafProvider.trafRequestDataModel!),
12.height,
requestInformation(trafProvider.trafRequestDataModel!),
12.height,
assetInformation(trafProvider.trafRequestDataModel!),
],
).expanded,
// // if (isEngineer)
// FooterActionButton.footerContainer(
// context: context,
// child: AppFilledButton(
// buttonColor: AppColor.primary10,
// label: "Update",
// onPressed: () {
// Navigator.pushNamed(context, UpdateTrafRequestPage.id);
// }),
// ),
],
);
},
));
}
@ -90,13 +94,14 @@ class _TrafRequestDetailPageState extends State<TrafRequestDetailPage> {
),
8.height,
'${context.translation.employeeId}: ${data.employeeIdForDisplay ?? '-'}'.bodyText(context),
'${context.translation.name}: ${data.employeeName ?? '-'}'.bodyText(context), // todo ask shaheer
'${context.translation.email}: ${data.employeeEmail ?? '-'}'.bodyText(context), // todo ask shaheer
'Position: ${data.positionName ?? '-'}'.bodyText(context), // todo ask shaheer
'${context.translation.name}: ${data.employeeName ?? '-'}'.bodyText(context),
'${context.translation.email}: ${data.employeeEmail ?? '-'}'.bodyText(context),
'Position: ${data.positionName ?? '-'}'.bodyText(context),
'${context.translation.site}: ${data.siteName ?? '-'}'.bodyText(context),
'${context.translation.department}: ${data.departments?.map((item) => item.departmentName).toList() ?? '-'}'.bodyText(context),
'Requester Extension: ${data.requesterExtensionName ?? '-'}'.bodyText(context),
'${context.translation.extensionNo}: ${data.requesterExtensionNumber ?? '-'}'.bodyText(context),
'${context.translation.department}: ${data.departmentName}'.bodyText(context),
// 'Requester Extension: ${data.requesterExtensionName ?? '-'}'.bodyText(context),
'Number/Contact Information: ${data.requesterContactNumber ?? '-'}'.bodyText(context),
'Extension: ${data.requesterExtensionNumber ?? '-'}'.bodyText(context),
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
@ -127,10 +132,22 @@ class _TrafRequestDetailPageState extends State<TrafRequestDetailPage> {
.bodyText(context),
4.height,
'Is the requesting department going to use the technology solely or shared with other departments?:\n${data.usingSolelyOrSharedName ?? '-'}'.bodyText(context),
if ((data.departments ?? []).isNotEmpty) ...[
4.height,
'Technology used with other departments:\n${data.departments?.map((item) => item.departmentName).toList() ?? '-'}'.bodyText(context),
],
4.height,
'Would other services be effected by acquiring the new equipment?:\n${data.effectedServices ?? '-'}'.bodyText(context),
'Would other services be effected by acquiring the new equipment?:\n${data.isEffectedName ?? '-'}'.bodyText(context),
if ((data.effectedServices ?? "").isNotEmpty) ...[
4.height,
'List of services would it be effected:\n${data.effectedServices ?? '-'}'.bodyText(context),
],
4.height,
'Is the equipment going to be used with combination of other equipment to accomplish a specific procedure?:\n${data.usedWithCombination ?? '-'}'.bodyText(context),
'Is the equipment going to be used with combination of other equipment to accomplish a specific procedure?:\n${data.isCombinationName ?? '-'}'.bodyText(context),
if ((data.usedWithCombination ?? "").isNotEmpty) ...[
4.height,
'Equipment going to be used with combination of other equipments:\n${data.usedWithCombination ?? '-'}'.bodyText(context),
],
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
@ -149,16 +166,29 @@ class _TrafRequestDetailPageState extends State<TrafRequestDetailPage> {
'${context.translation.model}: ${data.modelName ?? '-'}'.bodyText(context),
'${context.translation.manufacture}: ${data.manufacturerName ?? '-'}'.bodyText(context),
if (data.requestTypeId == 733) ...[
'Last price & PO: ${data.poNumber ?? '-'}'.bodyText(context),
'The quantity of the same asset: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
'Existing asset under SLA: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
'Age of the asset: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
'Total Maintenance Cost (TMC): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
'Net Book Value (NBV): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
'Mean Time Between Failure (MTBF): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
'Down Time (DT): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
'Up Time (UT): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
'Purchased Price: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
FutureBuilder<AssetAnalytics?>(
future: Provider.of<TrafRequestProvider>(context, listen: false).getAssetAnalytics(data.assetId!),
builder: (cxt, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const SizedBox.square(dimension: 24, child: CircularProgressIndicator()).center;
}
if (snapshot.hasData) {
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
'Last price: ${snapshot.data?.lastPrice ?? '-'}'.bodyText(context),
'PO: ${snapshot.data?.lastPONo ?? '-'}'.bodyText(context),
'The quantity of the same asset: ${snapshot.data?.sameAssetQuantity ?? '-'}'.bodyText(context), // todo check with shaheer
'Existing asset under SLA: ${snapshot.data?.slaStatus ?? '-'}'.bodyText(context), // todo check with shaheer
'Age of the asset: ${snapshot.data?.assetAgeDescription ?? '-'}'.bodyText(context), // todo check with shaheer
'Total Maintenance Cost (TMC): ${snapshot.data?.totalMaintenanceCost ?? '-'}'.bodyText(context), // todo check with shaheer
'Net Book Value (NBV): ${snapshot.data?.netBookValue ?? '-'}'.bodyText(context), // todo check with shaheer
'Mean Time Between Failure (MTBF): ${snapshot.data?.mtbfDescription ?? '-'}'.bodyText(context), // todo check with shaheer
'Down Time (DT): ${snapshot.data?.downTimeDescription ?? '-'}'.bodyText(context), // todo check with shaheer
'Up Time (UT): ${snapshot.data?.upTimeDescription ?? '-'}'.bodyText(context),
'Purchased Price: ${snapshot.data?.purchasedPrice ?? '-'}'.bodyText(context),
]);
}
return const SizedBox();
})
],
],
).toShadowContainer(context, borderRadius: 20, padding: 12);

@ -51,12 +51,15 @@ class TrafRequestDataModel {
String? employeeEmail;
int? positionId;
String? positionName;
String? departmentId;
String? departmentName;
List<Departments>? departments;
List<Departments>? trafDepartments;
int? siteId;
String? siteName;
String? requesterExtensionNumber;
String? requesterExtensionName;
String? requesterContactNumber;
int? requesterExtensionPositionId;
String? requesterExtensionPositionName;
int? requestTypeId;
@ -74,10 +77,10 @@ class TrafRequestDataModel {
int? qty;
String? purposeAnswer;
String? currentPractise;
int? censusQ1;
int? censusQ2;
int? censusQ3;
int? censusQ4;
String? censusQ1;
String? censusQ2;
String? censusQ3;
String? censusQ4;
List<TrafContacts>? trafContacts;
int? usingSolelyOrSharedId;
String? usingSolelyOrSharedName;
@ -124,7 +127,7 @@ class TrafRequestDataModel {
String? approvalDocDate;
String? isAssigned;
String? poNumber;
int? apiDirectorId;
String? apiDirectorId;
String? apiDirectorName;
int? apiDirectorApprovalId;
String? apiDirectorApprovalName;
@ -146,12 +149,15 @@ class TrafRequestDataModel {
this.employeeEmail,
this.positionId,
this.positionName,
this.departmentId,
this.departmentName,
this.departments,
this.trafDepartments,
this.siteId,
this.siteName,
this.requesterExtensionNumber,
this.requesterExtensionName,
this.requesterContactNumber,
this.requesterExtensionPositionId,
this.requesterExtensionPositionName,
this.requestTypeId,
@ -241,6 +247,8 @@ class TrafRequestDataModel {
employeeEmail = json['employeeEmail'];
positionId = json['positionId'];
positionName = json['positionName'];
departmentId = json['departmentId'];
departmentName = json['departmentName'];
if (json['departments'] != null) {
departments = <Departments>[];
json['departments'].forEach((v) {
@ -257,6 +265,7 @@ class TrafRequestDataModel {
siteName = json['siteName'];
requesterExtensionNumber = json['requesterExtensionNumber'];
requesterExtensionName = json['requesterExtensionName'];
requesterContactNumber = json['requesterContactNumber'];
requesterExtensionPositionId = json['requesterExtensionPositionId'];
requesterExtensionPositionName = json['requesterExtensionPositionName'];
requestTypeId = json['requestTypeId'];
@ -363,6 +372,8 @@ class TrafRequestDataModel {
data['employeeEmail'] = this.employeeEmail;
data['positionId'] = this.positionId;
data['positionName'] = this.positionName;
data['departmentId'] = this.departmentId;
data['departmentName'] = this.departmentName;
if (this.departments != null) {
data['departments'] = this.departments!.map((v) => v.toJson()).toList();
}
@ -373,6 +384,7 @@ class TrafRequestDataModel {
data['siteName'] = this.siteName;
data['requesterExtensionNumber'] = this.requesterExtensionNumber;
data['requesterExtensionName'] = this.requesterExtensionName;
data['requesterContactNumber'] = this.requesterContactNumber;
data['requesterExtensionPositionId'] = this.requesterExtensionPositionId;
data['requesterExtensionPositionName'] = this.requesterExtensionPositionName;
data['requestTypeId'] = this.requestTypeId;

@ -5,6 +5,7 @@ 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 'asset_analytics_model.dart';
import 'traf_request_model.dart';
class TrafRequestProvider extends ChangeNotifier {
@ -12,25 +13,21 @@ class TrafRequestProvider extends ChangeNotifier {
TrafRequestDataModel? trafRequestDataModel;
Future<int> addTraf(Map<String, dynamic> body) async {
Future<bool> addTraf(Map<String, dynamic> body) async {
try {
isLoading = true;
notifyListeners();
Response response = await ApiManager.instance.post(URLs.addTRAF, body: body);
if (response.statusCode >= 200 && response.statusCode < 300) {
// trafRequestDataModel = TrafRequestDataModel.fromJson(json.decode(response.body)["data"]);
return true;
}
isLoading = false;
notifyListeners();
return 0;
return false;
} catch (error) {
isLoading = false;
notifyListeners();
return -1;
return false;
}
}
Future<int> getTRAFById(int trafId) async {
trafRequestDataModel = null;
try {
isLoading = true;
notifyListeners();
@ -47,4 +44,16 @@ class TrafRequestProvider extends ChangeNotifier {
return -1;
}
}
Future<AssetAnalytics?> getAssetAnalytics(int assetId) async {
try {
Response response = await ApiManager.instance.get("${URLs.getAssetAnalytics}?assetId=$assetId");
if (response.statusCode >= 200 && response.statusCode < 300) {
return AssetAnalytics.fromJson(json.decode(response.body)["data"]);
}
} catch (error) {
print(error);
}
return null;
}
}

@ -81,13 +81,13 @@ class _UsersAutoCompleteFieldState extends State<SearchUserAutoCompleteField> {
loading = true;
});
}
List<UsersBasedOnSearchModel> workOrders = (await _TechnologyUsersProvider.getUsersBasedOnSearch(textEditingValue.text));
List<UsersBasedOnSearchModel> workOrders = (await _TechnologyUsersProvider.getUsersBasedOnSearch(context.userProvider.user!.clientId!, textEditingValue.text));
setState(() {
loading = false;
});
return workOrders;
},
displayStringForOption: (UsersBasedOnSearchModel option) => widget.byName ? option.userName ?? "" : option.employeeId ?? "",
displayStringForOption: (UsersBasedOnSearchModel option) => widget.byName ? "${option.userName ?? "-"} (Nurse)" ?? "" : option.employeeId ?? "",
fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
return TextField(
controller: _controller,

@ -264,6 +264,11 @@ class AppColor {
return green15;
case 370:
return green15;
case 0:
return green15;
case 1:
//high priority
return white10;
case 82:
//high priority
return white10;
@ -279,9 +284,13 @@ class AppColor {
return greenStatus(context);
case 370:
return greenStatus(context);
case 0:
return greenStatus(context);
//high priority
case 82:
return redStatus(context);
case 1:
return redStatus(context);
default:
return blueStatus(context);
}

@ -50,8 +50,8 @@ class AppFilledButton extends StatelessWidget {
),
child: loading
? SizedBox(
width: 24,
height: 24,
width: 24.toScreenHeight,
height: 24.toScreenHeight,
child: CircularProgressIndicator(
color: textColor ?? AppColor.background(context),
strokeWidth: 2,

@ -210,7 +210,7 @@ class _MultipleItemDropDownMenuState<T extends Base, X extends LoadingListNotifi
: null,
)
.expanded,
if (widget.enabled) const PositionedDirectional(end: 0, child: Icon(Icons.keyboard_arrow_down_rounded)),
if (widget.enabled) const Icon(Icons.keyboard_arrow_down_rounded),
],
),
),

@ -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');
},
)
],

@ -77,7 +77,7 @@ class CreateRequestTypeBottomSheet extends StatelessWidget {
size: 32,
),
//24.height,
label.bodyText2(context).custom(color: context.isDark ? Colors.white : AppColor.black20),
label.bodyText2(context).custom(color: context.isDark ? Colors.white : AppColor.black20, fontSize: context.isTablet() ? 10.toScreenWidth : null),
],
),
),

@ -9,6 +9,7 @@ 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';
import 'package:test_sa/models/search_all_requests_model.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
@ -74,7 +75,7 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
types["System Internal Audit".addTranslation] = 11;
}
if (context.settingProvider.isUserFlowMedical) {
if (context.settingProvider.isUserFlowMedical && isEngineer) {
types['Recall and Alert'] = 7;
}
@ -125,6 +126,7 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
body: Column(
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
@ -208,11 +210,11 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
// setState(() {});
// }),
],
).paddingOnly(start: 16, end: 16),
),
).expanded,
AppFilledButton(onPressed: _search, label: context.translation.applyFilter).paddingOnly(start: 16, end: 16),
FooterActionButton.footerContainer(context: context, child: AppFilledButton(onPressed: _search, label: context.translation.applyFilter))
],
).paddingOnly(top: 16, bottom: 16),
),
);
}

@ -7,6 +7,7 @@ import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
@ -90,6 +91,7 @@ class _AllRequestsSearchPageState extends State<AllRequestsSearchPage> {
child: Column(
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -124,9 +126,9 @@ class _AllRequestsSearchPageState extends State<AllRequestsSearchPage> {
],
),
).expanded,
AppFilledButton(onPressed: _search, label: context.translation.search),
FooterActionButton.footerContainer(context: context, child: AppFilledButton(onPressed: _search, label: context.translation.search)),
],
).paddingAll(16),
),
),
);
}

@ -5,10 +5,12 @@ import 'dart:developer';
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';
@ -51,9 +53,12 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
//TODO unCommit this to enable task
requestsList.add(Request(6, context.translation.taskRequest));
//after confirm name add this to translation...
if (context.settingProvider.isUserFlowMedical) {
if (context.settingProvider.isUserFlowMedical && Provider.of<UserProvider>(context, listen: false).user!.type != UsersTypes.normal_user) {
requestsList.add(Request(7, 'Recall and Alert'));
}
if (Provider.of<UserProvider>(context, listen: false).user!.type != UsersTypes.normal_user) {
requestsList.add(Request(8, 'Inventory Session'.addTranslation));
}
if (context.userProvider.user!.type == UsersTypes.normal_user) {
requestsList.add(Request(9, 'TRAF'));
}

@ -3,6 +3,7 @@ import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart';
import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/modules/traf_module/traf_request_item_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
@ -48,54 +49,35 @@ class RequestPaginatedListview extends StatelessWidget {
}
Widget _buildRequestItem(Data request) {
//TODO need to replace with switch statement
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;
bool isTRAF = request.transactionNo == 9;
bool isEquipmentInternalAudit = request.transactionNo == 10;
bool isSystemInternalAudit = request.transactionNo == 11;
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 if (isTRAF) {
return TrafRequestItemView(requestData: request);
} else if (isEquipmentInternalAudit) {
return EquipmentInternalAuditItemView(requestData: request);
} else if (isSystemInternalAudit) {
return SystemInternalAuditItemView(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 InventorySessionItemView(requestData: request);
case 9:
return TrafRequestItemView(requestData: request);
case 10:
return EquipmentInternalAuditItemView(requestData: request);
case 11:
return SystemInternalAuditItemView(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]));
// // }
// }));

@ -8,6 +8,7 @@ import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart';
import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart';
import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/modules/traf_module/traf_request_item_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
@ -58,6 +59,8 @@ class RequestItemViewList extends StatelessWidget {
return TaskRequestItemView(requestDetails: list[index]);
case 7:
return TaskRequestItemView(requestDetails: list[index]);
case 8:
return InventorySessionItemView(requestDetails: list[index]);
case 9:
return TrafRequestItemView(requestDetails: list[index]);
//Need to verify the type No..

@ -110,8 +110,9 @@ class _LoginPageState extends State<LoginPage> {
backgroundColor: AppColor.fieldBgColor(context),
validator: (value) => Validator.hasValue(value!) ? null : context.translation.requiredField,
labelText: context.translation.username,
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: 11, color: context.isDark ? Colors.white : const Color(0xff767676)),
style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
floatingLabelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff767676)),
textInputType: TextInputType.text,
showWithoutDecoration: true,
contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 12.toScreenHeight),
@ -125,8 +126,9 @@ class _LoginPageState extends State<LoginPage> {
showWithoutDecoration: true,
labelText: context.translation.password,
backgroundColor: AppColor.fieldBgColor(context),
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: 11, color: context.isDark ? Colors.white : const Color(0xff767676)),
style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff767676)),
floatingLabelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 12.toScreenHeight),
obscureText: !_passwordVisible,
suffixIcon: Icon(

@ -175,7 +175,7 @@ class _ProfilePageState extends State<ProfilePage> {
16.height,
AppFilledButton(
label: "Update Information",
buttonColor: context.isDark? AppColor.primary10:AppColor.neutral50,
buttonColor: context.isDark ? AppColor.primary10 : AppColor.neutral50,
onPressed: () {
context.showBottomSheet(
UpdateUserContactInfoBottomSheet(

@ -17,11 +17,16 @@ 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;
final bool enablePickManually;
final bool multiSelection;
AssetPicker(
@ -34,10 +39,14 @@ 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.forPPM = false, this.enablePickManually = true,
this.showLoading = false})
: assert(
multiSelection == false || onMultiAssetPick != null,
@ -57,15 +66,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 {
@ -74,6 +84,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr(
title: context.translation.assetScan,
multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as List<Asset>?;
if (device?.isNotEmpty ?? false) {
onMultiAssetPick!(device!);
@ -83,6 +94,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr(
title: context.translation.assetScan,
multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as Asset?;
if (device != null) {
onPick!(device);
@ -112,6 +124,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr(
title: context.translation.assetScan,
multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as List<Asset>?;
if (device?.isNotEmpty ?? false) {
onMultiAssetPick!(device!);
@ -121,6 +134,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr(
title: context.translation.assetScan,
multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as Asset?;
if (device != null) {
onPick!(device);
@ -131,7 +145,7 @@ class AssetPicker extends StatelessWidget {
if (deviceList.isNotEmpty && showAssetInfo)
ListView.separated(
shrinkWrap: true,
padding: EdgeInsets.only(top: 16),
padding: const EdgeInsets.only(top: 16),
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (cxt, index) => _assetInfoView(deviceList[index], context),
separatorBuilder: (cxt, index) => 12.height,
@ -195,10 +209,10 @@ class AssetPicker extends StatelessWidget {
],
),
8.height,
"${context.translation.assetNo}: ${device!.assetNumber}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
"${context.translation.assetNo}: ${device.assetNumber}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
2.height,
// "${context.translation.manufacture}: ${device.modelDefinition?.manufacturerName}".bodyText(context),
"${context.translation.model}: ${device!.modelDefinition?.modelName}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
"${context.translation.model}: ${device.modelDefinition?.modelName}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
// "${context.translation.serialNumber}: ${device.assetNumber}".bodyText(context),
// const Divider().defaultStyle(context),
// "${context.translation.department}: ${device.department?.departmentName}".bodyText(context),

@ -20,9 +20,10 @@ import '../../pages/device_transfer/search_device_page.dart';
class AssetScanQr extends StatefulWidget {
static const String id = "/asset-scan-qr";
const AssetScanQr({Key? key, required this.title, this.multiSelection = false}) : super(key: key);
const AssetScanQr({Key? key, required this.title, this.multiSelection = false,this.enablePickManually = true}) : super(key: key);
final String title;
final bool multiSelection;
final bool enablePickManually;
@override
_AssetScanQrState createState() => _AssetScanQrState();
@ -86,15 +87,23 @@ class _AssetScanQrState extends State<AssetScanQr> {
controller.scannedDataStream.listen((scanData) async {
if (!_scanDone) {
_scanDone = true;
final result = await _getDevice(scanData.code!, isQr: true);
if (result.isNotEmpty) {
if (widget.multiSelection) {
Navigator.of(context).pop(<Asset>[result[0]]);
if(!widget.enablePickManually){
if(scanData.code!=null){
Navigator.of(context).pop(Asset(assetNumber: scanData.code!));
}else{
_scanDone = false;
}
}else{
final result = await _getDevice(scanData.code!, isQr: true);
if (result.isNotEmpty) {
if (widget.multiSelection) {
Navigator.of(context).pop(<Asset>[result[0]]);
} else {
Navigator.of(context).pop(result[0]);
}
} else {
Navigator.of(context).pop(result[0]);
_scanDone = false;
}
} else {
_scanDone = false;
}
}
});
@ -109,7 +118,8 @@ class _AssetScanQrState extends State<AssetScanQr> {
),
],
).expanded,
FooterActionButton.footerContainer(
if(widget.enablePickManually)
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
label: context.translation.pickManually,

@ -11,23 +11,23 @@ class StatusLabel extends StatelessWidget {
final double radius;
final bool labelInCenter;
StatusLabel({Key? key, this.id = 0, this.label, this.backgroundColor, this.textColor, this.isPriority = false, this.radius = 4,this.labelInCenter=false}) : super(key: key);
StatusLabel({Key? key, this.id = 0, this.label, this.backgroundColor, this.textColor, this.isPriority = false, this.radius = 4, this.labelInCenter = false}) : super(key: key);
@override
Widget build(BuildContext context) {
if (id == 82) label = context.translation.highPriority;
if (id == 81) label = context.translation.lowPriority;
if (label?.toLowerCase() == 'In progress'.toLowerCase()) label = context.translation.inProgress;
if (label?.toLowerCase() == 'Completed'.toLowerCase()) label = context.translation.completed;
if (label?.toLowerCase() == 'Open'.toLowerCase()) label = context.translation.open;
if (label?.toLowerCase() == 'Closed'.toLowerCase()) label = context.translation.closed;
if (label?.toLowerCase() == 'Low'.toLowerCase()) label = context.translation.lowPriority;
if (label?.toLowerCase() == 'No'.toLowerCase()) label = context.translation.lowPriority;
if (label?.toLowerCase() == 'High'.toLowerCase()) label = context.translation.highPriority;
if (label?.toLowerCase() == 'Yes'.toLowerCase()) label = context.translation.highPriority;
if (label?.toLowerCase() == 'Waiting for quotation'.toLowerCase()) label = context.translation.waitingForQuotation;
return Container(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 10),
alignment: labelInCenter ? Alignment.center: null,
alignment: labelInCenter ? Alignment.center : null,
decoration: ShapeDecoration(
color: backgroundColor,
shape: RoundedRectangleBorder(

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.3.10+29
version: 1.3.11+30
environment:
sdk: ">=3.5.0 <4.0.0"

Loading…
Cancel
Save