Merge remote-tracking branch 'origin/design_3.0_internal_audit_module' into design_3.0_internal_audit_module

# Conflicts:
#	lib/controllers/api_routes/urls.dart
design_3.0_demo_module
waseemabbasi22 5 months ago
commit c9d2df4ea7

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

@ -0,0 +1,3 @@
<svg width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.35372 0.305286C1.4756 0.46666 1.83951 0.948403 2.05624 1.22611C2.49031 1.78233 3.08342 2.52142 3.72323 3.25831C4.36627 3.99893 5.04178 4.72022 5.64189 5.25046C5.94281 5.51634 6.20714 5.71838 6.42527 5.84987C6.63042 5.97355 6.75161 5.99927 6.75161 5.99927C6.75161 5.99927 6.86923 5.97355 7.07437 5.84988C7.2925 5.71838 7.55684 5.51635 7.85775 5.25047C8.45786 4.72022 9.13337 3.99892 9.77642 3.2583C10.4162 2.5214 11.0093 1.7823 11.4434 1.22608C11.6601 0.948368 12.0235 0.467305 12.1454 0.305929C12.3911 -0.0275935 12.8611 -0.0995297 13.1946 0.146103C13.5281 0.391736 13.5994 0.861234 13.3537 1.19476L13.3518 1.1973C13.224 1.36655 12.8471 1.86557 12.6259 2.14892C12.1821 2.7177 11.5716 3.47861 10.9091 4.24171C10.2497 5.00109 9.52408 5.77979 8.85096 6.37454C8.51526 6.67116 8.17497 6.93788 7.8488 7.1345C7.54322 7.31872 7.15633 7.5 6.74982 7.5C6.34331 7.5 5.95642 7.31871 5.65084 7.1345C5.32468 6.93787 4.98439 6.67116 4.64869 6.37454C3.97557 5.77979 3.2499 5.0011 2.59058 4.24173C1.92803 3.47863 1.3176 2.71774 0.873719 2.14896C0.652433 1.86541 0.275507 1.36637 0.14793 1.19747L0.14628 1.19528C-0.0993546 0.861762 -0.0284591 0.391787 0.305062 0.146153C0.638573 -0.0994739 1.10808 -0.0282082 1.35372 0.305286Z" fill="#3B3D4A"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,3 @@
<svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.305286 12.1462C0.46666 12.0243 0.948403 11.6604 1.22611 11.4436C1.78233 11.0096 2.52142 10.4165 3.25831 9.77665C3.99893 9.13361 4.72022 8.4581 5.25046 7.85799C5.51634 7.55707 5.71838 7.29274 5.84987 7.07461C5.97355 6.86945 5.99927 6.74827 5.99927 6.74827C5.99927 6.74827 5.97355 6.63064 5.84988 6.4255C5.71838 6.20738 5.51635 5.94304 5.25047 5.64213C4.72022 5.04201 3.99892 4.3665 3.2583 3.72346C2.5214 3.08366 1.7823 2.49055 1.22608 2.05647C0.948368 1.83975 0.467305 1.47634 0.305929 1.35446C-0.0275935 1.10883 -0.0995297 0.63882 0.146103 0.305298C0.391736 -0.0282253 0.861234 -0.0994742 1.19476 0.146159L1.1973 0.148077C1.36655 0.275917 1.86557 0.652817 2.14892 0.873949C2.7177 1.31783 3.47861 1.92826 4.24171 2.59081C5.00109 3.25013 5.77979 3.9758 6.37454 4.64892C6.67116 4.98462 6.93788 5.32491 7.1345 5.65108C7.31872 5.95665 7.5 6.34355 7.5 6.75006C7.5 7.15657 7.31871 7.54346 7.1345 7.84904C6.93787 8.1752 6.67116 8.51549 6.37454 8.85119C5.77979 9.52431 5.0011 10.25 4.24173 10.9093C3.47863 11.5719 2.71774 12.1823 2.14896 12.6262C1.86541 12.8474 1.36637 13.2244 1.19747 13.3519L1.19528 13.3536C0.861762 13.5992 0.391787 13.5283 0.146153 13.1948C-0.0994739 12.8613 -0.0282082 12.3918 0.305286 12.1462Z" fill="#3B3D4A"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -10,7 +10,7 @@ class AppAsset {
static String maintenanceIcon = 'maintenance_icon'; static String maintenanceIcon = 'maintenance_icon';
static String retiredAssetIcon = 'assets/images/retired_asset_icon.svg'; static String retiredAssetIcon = 'assets/images/retired_asset_icon.svg';
static String sparePartIcon = 'spare_part_icon'; static String sparePartIcon = 'spare_part_icon';
static String editIcon = 'assets/images/edit_icon.svg'; static String editIcon = 'assets/images/edit_icon';
static String deleteIcon = 'assets/images/delete_icon.svg'; static String deleteIcon = 'assets/images/delete_icon';
static String overDueIcon = 'assets/images/overdue.svg'; 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,15 +1,18 @@
class URLs { class URLs {
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://atomsm.hmg.com"; // production url
static const host1 = "https://atomsmdev.hmg.com"; // local DEV url static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
// static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static const host1 = "https://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 String _baseUrl = "$_host/mobile";
// static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
static final String _baseUrl = "$_host/mobile"; // host local 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/v3/mobile"; // v3 for production CM,PM,TM
// static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation
static String _host = host1; static String _host = host1;
@ -22,6 +25,8 @@ class URLs {
// API Routes // API Routes
static get login => "$_baseUrl/MobileAuth/Login"; static get login => "$_baseUrl/MobileAuth/Login";
static get userChangeAssetGroup => "$_baseUrl/MobileAuth/UserChangeAssetGroup";
static get getUserInfo => "$_baseUrl/MobileAuth/GetUserInfo"; static get getUserInfo => "$_baseUrl/MobileAuth/GetUserInfo";
static get logout => "$_baseUrl/MobileAuth/Logout"; static get logout => "$_baseUrl/MobileAuth/Logout";
@ -257,7 +262,9 @@ class URLs {
//Traf //Traf
static get addTRAF => "$_baseUrl/TRAF/AddTRAF"; // get static get addTRAF => "$_baseUrl/TRAF/AddTRAF"; // get
static get getTRAFById => "$_baseUrl/TRAF/GetTRAFById"; // 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 getAssetNDAutoCompleteByDynamicCodes => "$_baseUrl/AssetNameDefinition/GetAssetNDAutoCompleteByDynamicCodes"; // get// get
static get getAssetNameAutoComplete => "$_baseUrl/AssetNameDefinition/GetAssetNameAutoComplete"; // get// get
//gas refill //gas refill
static get getGasTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=606"; // get static get getGasTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=606"; // get
@ -294,6 +301,7 @@ class URLs {
static get getNurses => "$_baseUrl/Account/GetUserByRoleValue?value=R-7"; // get static get getNurses => "$_baseUrl/Account/GetUserByRoleValue?value=R-7"; // get
static get getNursesBySiteId => "$_baseUrl/Account/GetUserByRoleValueSiteAndAssetGroupBySiteId?value=R-7"; // get static get getNursesBySiteId => "$_baseUrl/Account/GetUserByRoleValueSiteAndAssetGroupBySiteId?value=R-7"; // get
static get getUsersBasedOnSearch => "$_baseUrl/Account/GetUsersBasedOnSearch"; // get static get getUsersBasedOnSearch => "$_baseUrl/Account/GetUsersBasedOnSearch"; // get
static get getUserByRoleValueSiteMobileAutocomplete => "$_baseUrl/Account/GetUserByRoleValueSiteMobileAutocomplete"; // get
// pentry // pentry
static get getPentry => "$_baseUrl/return/pentry/details"; // get static get getPentry => "$_baseUrl/return/pentry/details"; // get
@ -310,18 +318,51 @@ class URLs {
static get getSiteContactInfo => "$_baseUrl/AssetGroupSiteContactInfo"; // add static get getSiteContactInfo => "$_baseUrl/AssetGroupSiteContactInfo"; // add
static get getDepartmentBasedOnSite => "$_baseUrl/TRAFDataSource/GetDepartmentBasedOnSite"; // 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';
static get searchAssetName => '$_baseUrl/AssetInventory/SearchAssetName';
static get getSuppliersAutoCompleteInventory => '$_baseUrl/Supplier/GetSuppliersMobile';
static get getAssetsTemp => '$_baseUrl/AssetInventory/GetAssetsTemp';
static get convertDetailToComplete => '$_baseUrl/AssetInventory/ConvertDetailToComplete';
//internal Audit static get getClassification => '$_baseUrl/AssetInventory/Classification';
//internal Audit
static get getInternalAuditEquipmentById => "$_baseUrl/InternalAuditEquipments/GetInternalAuditEquipmentById"; static get getInternalAuditEquipmentById => "$_baseUrl/InternalAuditEquipments/GetInternalAuditEquipmentById";
static get getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemByIdV2"; static get getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemByIdV2";
static get getInternalAuditChecklist => "$_baseUrl/Lookups/GetLookup?lookupEnum=43"; static get getInternalAuditChecklist => "$_baseUrl/Lookups/GetLookup?lookupEnum=43";
static get getInternalAuditWoType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2500"; static get getInternalAuditWoType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2500";
static get getInternalAuditFindingType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2502"; static get getInternalAuditFindingType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2502";
static get addOrUpdateEquipmentInternalAudit => "$_baseUrl/InternalAuditEquipments/AddOrUpdateAuditEquipment"; static get addOrUpdateEquipmentInternalAudit => "$_baseUrl/InternalAuditEquipments/AddOrUpdateAuditEquipment";
static get addOrUpdateInternalAuditSystem => "$_baseUrl/InternalAuditSystems/AddOrUpdateInternalAuditSystem"; static get addOrUpdateInternalAuditSystem => "$_baseUrl/InternalAuditSystems/AddOrUpdateInternalAuditSystem";
static get getWoAutoComplete => "$_baseUrl/InternalAuditSystems/AutoCompleteAllWorkOrder"; static get getWoAutoComplete => "$_baseUrl/InternalAuditSystems/AutoCompleteAllWorkOrder";
static get updateAuditEquipmentsEngineer => "$_baseUrl/InternalAuditEquipments/UpdateAuditEquipmentsEngineer"; static get updateAuditEquipmentsEngineer => "$_baseUrl/InternalAuditEquipments/UpdateAuditEquipmentsEngineer";
static get updateAuditSystemEngineer => "$_baseUrl/InternalAuditSystems/UpdateAuditSystemEngineer"; static get updateAuditSystemEngineer => "$_baseUrl/InternalAuditSystems/UpdateAuditSystemEngineer";
static get loadAllWorkOrderDetailsByID => "$_baseUrl/InternalAuditSystems/LoadAllWorkOrderDetailsByID";
static get loadAllWorkOrderDetailsByID => "$_baseUrl/InternalAuditSystems/LoadAllWorkOrderDetailsByID";
} }

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

@ -88,7 +88,7 @@ class OracleCodeProvider extends ChangeNotifier {
Future<List<AssetNDAutoCompleteByDynamicCodesModel>> getAssetByOracleCode(String oracleCode) async { Future<List<AssetNDAutoCompleteByDynamicCodesModel>> getAssetByOracleCode(String oracleCode) async {
late Response response; late Response response;
try { 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 = []; List<AssetNDAutoCompleteByDynamicCodesModel> page = [];
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received // client's request was successfully received

@ -46,10 +46,10 @@ class UserSearchProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
Future<List<UsersBasedOnSearchModel>> getUsersBasedOnSearch(String query) async { Future<List<UsersBasedOnSearchModel>> getUsersBasedOnSearch(int siteId, String query) async {
late Response response; late Response response;
try { 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 = []; List<UsersBasedOnSearchModel> page = [];
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received // 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 { Future<bool> logout(BuildContext context) async {
Response response; Response response;
try { try {

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

@ -1,13 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.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/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/dashboard_latest/dashboard_provider.dart'; import 'package:test_sa/dashboard_latest/dashboard_provider.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_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/new_views/app_style/app_color.dart';
import 'package:test_sa/views/pages/user/notifications/notifications_page.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 '../../controllers/providers/api/user_provider.dart';
import '../../models/user.dart'; import '../../models/user.dart';
@ -48,11 +51,11 @@ class AppBarWidget extends StatelessWidget {
children: [ children: [
Text( Text(
snapshot.user?.username ?? "", // Simplified null check 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( Text(
snapshot.user?.type?.name.toCamelCase ?? "", // Simplified null check 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), borderRadius: BorderRadius.circular(8),
style: TextStyle(color: Theme.of(context).primaryColor), style: TextStyle(color: Theme.of(context).primaryColor),
underline: const SizedBox.shrink(), underline: const SizedBox.shrink(),
onChanged: (newValue) { onChanged: (newValue) async {
if (settingProvider.assetGroup != newValue) { if (settingProvider.assetGroup != newValue) {
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); settingProvider.setAssetGroup(newValue);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
context.settingProvider.setUser(ApiManager.instance.user!);
context.userProvider.setUser(ApiManager.instance.user!);
DashBoardProvider dashBoardProvider = Provider.of<DashBoardProvider>(context, listen: false); DashBoardProvider dashBoardProvider = Provider.of<DashBoardProvider>(context, listen: false);
dashBoardProvider.setTabs(userType: settingProvider.user!.type!, context: context); dashBoardProvider.setTabs(userType: settingProvider.user!.type!, context: context);
dashBoardProvider.getDashBoardCount(usersType: settingProvider.user!.type!); dashBoardProvider.getDashBoardCount(usersType: settingProvider.user!.type!);
dashBoardProvider.resetRequestDataList(); dashBoardProvider.resetRequestDataList();
dashBoardProvider.getRequestDetail(usersType: settingProvider.user!.type!, status: dashBoardProvider.tabs[dashBoardProvider.currentListIndex].tag); 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) { 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}) { Widget getTabs({required BuildContext context, required DashBoardProvider requestsProvider, required UsersTypes? userType}) {
List<CategoryTabs> tabs = CategoryTabs.getTabs(userType: userType ?? UsersTypes.normal_user, context: context); List<CategoryTabs> tabs = CategoryTabs.getTabs(userType: userType ?? UsersTypes.normal_user, context: context);
return SizedBox( return SizedBox(
height: 44 + 16, height: 44 + (context.isTablet() ? 36 : 16),
child: ListView.separated( child: ListView.separated(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
separatorBuilder: (cxt, index) => 12.width, 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/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/dashboard_detail.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/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/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/modules/traf_module/traf_request_item_view.dart';
@ -50,6 +51,10 @@ class RequestCategoryList extends StatelessWidget {
return RecurrentWoItemView(requestData: request); return RecurrentWoItemView(requestData: request);
case 6: case 6:
return TaskRequestItemView(requestData: request); return TaskRequestItemView(requestData: request);
case 7:
return TaskRequestItemView(requestData: request);
case 8:
return InventorySessionItemView(requestData: request);
case 9: case 9:
return TrafRequestItemView(requestData: request); return TrafRequestItemView(requestData: request);
//TODO need to verify this ... //TODO need to verify this ...

@ -19,7 +19,14 @@ extension BuildContextExtension on BuildContext {
SettingProvider get settingProvider => Provider.of<SettingProvider>(this, listen: false); SettingProvider get settingProvider => Provider.of<SettingProvider>(this, listen: false);
UserProvider get userProvider => Provider.of<UserProvider>(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( void showConfirmDialog(String message, {String? title, VoidCallback? onTap}) => showDialog(
context: this, context: this,
builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap, title: title), 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_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_report_repair_location_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_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/service_request_detail_provider.dart';
import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.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'; 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: (_) => RequestStatusProvider()),
ChangeNotifierProvider(create: (_) => VendorProvider()), ChangeNotifierProvider(create: (_) => VendorProvider()),
ChangeNotifierProvider(create: (_) => PpmChecklistStatusProvider()), ChangeNotifierProvider(create: (_) => PpmChecklistStatusProvider()),
ChangeNotifierProvider(create: (_) => AssetInventoryProvider()),
], ],
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {

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

@ -142,11 +142,11 @@ class Asset {
Building? building; // Now nullable Building? building; // Now nullable
Floor? floor; // Now nullable Floor? floor; // Now nullable
Department? department; // Now nullable Department? department; // Now nullable
Rooms? room;
MappedSite? mappedSite; // Now nullable MappedSite? mappedSite; // Now nullable
MappedBuilding? mappedBuilding; // Now nullable MappedBuilding? mappedBuilding; // Now nullable
MappedFloor? mappedFloor; // Now nullable MappedFloor? mappedFloor; // Now nullable
MappedDepartment? mappedDepartment; // No MappedDepartment? mappedDepartment; //
Rooms? room; // Now nullable
num? testsDay; // Now nullable num? testsDay; // Now nullable
num? purchasingPrice; // Now nullable num? purchasingPrice; // Now nullable
String? nbv; // 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/base.dart';
import 'package:test_sa/models/new_models/floor.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 }) : super(identifier: id?.toString() ?? '', name: name); // Handle potential null id
Building.fromJson(dynamic json) { Building.fromJson(dynamic json) {
id = json['id']; id = json['id'] ?? json['buildingId'];
identifier = id?.toString() ?? ''; // Handle potential null id identifier = id?.toString() ?? '';
name = json['name']; name = json['name'] ?? json['buildingName'];
value = json['value']; value = json['value'];
if (json['floors'] != null) { if (json['floors'] != null) {
floors = []; floors = [];
json['floors'].forEach((v) { json['floors'].forEach((v) {
floors!.add(Floor.fromJson(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; String? priorityName;
bool? isHighPriority; bool? isHighPriority;
String? assetName; String? assetName;
String? sessionType;
String? rejectReason; String? rejectReason;
String? assetNumber; String? assetNumber;
String? requestTypeName; String? requestTypeName;
String? requestNo; String? requestNo;
int? transactionNo; int? transactionNo;
int? numberOfSites;
int? numberOfAssets;
String? nameOfType; String? nameOfType;
Data( Data(
@ -63,6 +66,9 @@ class Data {
this.nameOfType, this.nameOfType,
this.transactionDate, this.transactionDate,
this.statusName, this.statusName,
this.numberOfAssets,
this.numberOfSites,
this.sessionType,
this.priorityName, this.priorityName,
this.isHighPriority, this.isHighPriority,
this.assetName, this.assetName,
@ -79,6 +85,9 @@ class Data {
priorityName = json['priorityName']; priorityName = json['priorityName'];
isHighPriority = json['isHighPriority']; isHighPriority = json['isHighPriority'];
assetName = json['assetName']; assetName = json['assetName'];
sessionType = json['sessionType'];
numberOfSites = json['numberOfSites'];
numberOfAssets = json['numberOfAssets'];
assetNumber = json['assetNumber']; assetNumber = json['assetNumber'];
requestTypeName = json['requestTypeName']; requestTypeName = json['requestTypeName'];
requestNo = json['requestNo']; requestNo = json['requestNo'];
@ -101,6 +110,9 @@ class Data {
data['requestNo'] = requestNo; data['requestNo'] = requestNo;
data['rejectReason'] = rejectReason; data['rejectReason'] = rejectReason;
data['transactionNo'] = transactionNo; data['transactionNo'] = transactionNo;
data['sessionType'] = sessionType;
data['numberOfAssets'] = numberOfAssets;
data['numberOfSites'] = numberOfSites;
data['nameOfType'] = nameOfType; data['nameOfType'] = nameOfType;
return data; return data;
} }

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

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

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

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

@ -928,6 +928,8 @@ class TaskAsset {
String? roomName; String? roomName;
String? supplierName; String? supplierName;
String? assetTypeName; String? assetTypeName;
String? poNumber;
String? installationDate;
TaskAsset(); TaskAsset();
@ -946,10 +948,11 @@ class TaskAsset {
roomName = json['roomName']; roomName = json['roomName'];
supplierName = json['supplierName']; supplierName = json['supplierName'];
assetTypeName = json['assetTypeName']; assetTypeName = json['assetTypeName'];
poNumber = json['poNumber'];
installationDate = json['installationDate'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() => {
return {
'id': id, 'id': id,
'assetNumber': assetNumber, 'assetNumber': assetNumber,
'serialNo': serialNo, 'serialNo': serialNo,
@ -964,6 +967,7 @@ class TaskAsset {
'roomName': roomName, 'roomName': roomName,
'supplierName': supplierName, 'supplierName': supplierName,
'assetTypeName': assetTypeName, 'assetTypeName': assetTypeName,
'poNumber': poNumber,
'installationDate': installationDate,
}; };
}
} }

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

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

@ -0,0 +1,345 @@
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;
List<AssetInventoryDetailAssetAttachments> assetInventoryDetailAssetAttachments = [];
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,
this.assetInventoryDetailAssetAttachments = const [],
});
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'];
if (json['assetTransferAttachments'] != null) {
assetInventoryDetailAssetAttachments = [];
json['assetInventoryDetailAssetAttachments'].forEach((v) {
assetInventoryDetailAssetAttachments.add(AssetInventoryDetailAssetAttachments.fromJson(v));
});
}
//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,
'assetInventoryDetailAssetAttachments': assetInventoryDetailAssetAttachments != null
? assetInventoryDetailAssetAttachments!.map((v) => v.toJson()).toList()
: [],
};
}
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,
assetInventoryDetailAssetAttachments: assetInventoryDetailAssetAttachments??other.assetInventoryDetailAssetAttachments,
);
}
}
class AssetInventoryDetailAssetAttachments {
AssetInventoryDetailAssetAttachments({
this.id,
this.name,
this.originalName,
});
AssetInventoryDetailAssetAttachments.fromJson(dynamic json) {
id = json['id'];
name = json['name'];
originalName = json['originalName'];
}
num? id;
String? name;
String? originalName;
AssetInventoryDetailAssetAttachments copyWith({
num? id, // Parameter is now nullable
String? name, // Parameter is now nullable
String? originalName, // Parameter is now nullable
}) =>
AssetInventoryDetailAssetAttachments(
id: id ?? this.id,
name: name??this.name,
originalName: originalName??this.originalName,
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['id'] = id;
map['name'] = name;
map['originalName'] = originalName;
return map;
}
}

@ -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,112 @@
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(
crossAxisAlignment: CrossAxisAlignment.start,
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,
Text(
'Inventory 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.assetName}: ${assetInventoryModel.assetName ?? '-'}',
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),
),
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
}
//TODO old code.
// 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,
// )

@ -0,0 +1,242 @@
import 'package:flutter/material.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/site.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.getRequestStatusTextColorByName(context, sessionModel.statusName),
backgroundColor: AppColor.getRequestStatusColorByName(context, sessionModel.statusName),
// 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(
'Session Details'.addTranslation,
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,
SiteHierarchyView(
sites: sites,
),
],
).toShadowContainer(context, padding: 12, borderRadius: 20);
}
}
class SiteHierarchyView extends StatelessWidget {
final List<Site> sites;
const SiteHierarchyView({super.key, required this.sites});
@override
Widget build(BuildContext context) {
return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: sites.length,
itemBuilder: (context, index) {
final site = sites[index];
return HierarchyTile(
title: site.name ?? '-',
children: (site.buildings ?? [])
.map((b) => HierarchyTile(
title: b.name ?? '-',
children: (b.floors ?? [])
.map((f) => HierarchyTile(
title: f.name ?? '-',
children: (f.departments ?? [])
.map((d) => HierarchyTile(
title: d.name ?? '-',
children: (d.rooms ?? [])
.map((r) => LeafTile(title: r.name ?? '-'))
.toList(),
))
.toList(),
))
.toList(),
))
.toList(),
);
},
);
}
}
class HierarchyTile extends StatefulWidget {
final String title;
final List<Widget> children;
final double indent;
const HierarchyTile({
super.key,
required this.title,
this.children = const [],
this.indent = 0,
});
@override
State<HierarchyTile> createState() => _HierarchyTileState();
}
class _HierarchyTileState extends State<HierarchyTile> {
bool expanded = false;
@override
Widget build(BuildContext context) {
final hasChildren = widget.children.isNotEmpty;
return Padding(
padding: EdgeInsets.only(left: widget.indent,top: 10.toScreenHeight),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: hasChildren ? () => setState(() => expanded = !expanded) : null,
child: Row(
children: [
if (hasChildren)
// expanded? 'expended_arrow_icon'.toSvgAsset(color: AppColor.neutral50,width: 8,height:13): 'collesped_arrow_icon'.toSvgAsset(color: AppColor.neutral50,width: 8,height:13)
Icon(
expanded ? Icons.expand_more : Icons.chevron_right,
size: 25.toScreenHeight,
color: AppColor.neutral50,
)
else
SizedBox(width: 18.toScreenWidth),
SizedBox(width: 15.toScreenWidth),
Text(
widget.title,
style:AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
),
],
),
),
if (expanded)
Padding(
padding: const EdgeInsets.only(left: 20, top: 6),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: widget.children
.map((child) => child is HierarchyTile
? HierarchyTile(
title: (child).title,
indent: 0,
children: (child).children,
)
: child)
.toList(),
),
),
],
),
);
}
}
class LeafTile extends StatelessWidget {
final String title;
const LeafTile({super.key, required this.title});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 22, top: 4, bottom: 4),
child: Text(
title,
style: const TextStyle(fontSize: 13, color: Colors.black87),
),
);
}
}

@ -0,0 +1,480 @@
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(
'Attachments'.addTranslation,
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.white936),
),
12.height,
AttachmentPicker(
label: context.translation.attachFiles,
attachment: attachments,
buttonColor: AppColor.black10,
onlyImages: false,
buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
),
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: 'Submit'.addTranslation, 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;
_scannedAssetModel?.assetInventoryDetailAssetAttachments = [];
// try {
for (var item in attachments) {
String fileName = ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
_scannedAssetModel?.assetInventoryDetailAssetAttachments.add(AssetInventoryDetailAssetAttachments(id: item.id, name: fileName));
}
// // } catch (error) {
// // print(error);
// // }
// 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: 'Asset Inventory Session'.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: 'Session 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,112 @@
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!.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: 'Session Type'.addTranslation, 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!.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: 'Session Type'.addTranslation, 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) ...[ if (Provider.of<SettingProvider>(context, listen: false).showPriority) ...[
StatusLabel( StatusLabel(
label: workOrder.priority?.name, label: workOrder.priority?.name,
id: workOrder.priority!.id!, id: workOrder.priority!.value!,
radius: 4, radius: 4,
textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!), textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.value!),
backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!), backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.value!),
), ),
8.width, 8.width,
], ],
if (workOrder.itgFormWorkOrderStatus != null) ...[ if (workOrder.itgFormWorkOrderStatus != null) ...[
StatusLabel( StatusLabel(
label: workOrder.itgFormWorkOrderStatus, label: workOrder.itgFormWorkOrderStatus,
id: 0, // id: 0,
radius: 4, radius: 4,
textColor: AppColor.getPriorityStatusTextColor(context, 82), textColor: AppColor.getPriorityStatusTextColor(context, 82),
backgroundColor: AppColor.getPriorityStatusColor(context, 0), backgroundColor: AppColor.getPriorityStatusColor(context, 1000),
), ),
8.width, 8.width,
], ],

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

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

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

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

@ -1,3 +1,4 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/urls.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/extensions/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.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/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/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/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/providers/task_request_provider/task_request_provider.dart';
import 'package:test_sa/views/widgets/images/files_list.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/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/requests/request_status.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 '../../../../controllers/providers/api/user_provider.dart';
import '../../../../models/enums/user_types.dart'; import '../../../../models/enums/user_types.dart';
@ -61,7 +65,6 @@ class _TaskRequestDetailsViewState extends State<TaskRequestDetailsView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
userProvider ??= Provider.of<UserProvider>(context, listen: false); userProvider ??= Provider.of<UserProvider>(context, listen: false);
return Scaffold( return Scaffold(
// appBar: DefaultAppBar(title:taskProvider?.taskRequestModel?.taskType?.id==7?'Recall and Alert Details': context.translation.taskRequest),
appBar: DefaultAppBar(title: context.translation.taskRequest), appBar: DefaultAppBar(title: context.translation.taskRequest),
body: Consumer<TaskRequestProvider>(builder: (context, taskProvider, child) { body: Consumer<TaskRequestProvider>(builder: (context, taskProvider, child) {
TaskData? taskModel = taskProvider.taskRequestModel; 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?.taskJobContactPersons ?? []).isNotEmpty) ...[contactInfoCard(context, taskProvider.taskRequestModel!)],
if (taskProvider.taskRequestModel?.callComment != null) ...[ if (taskProvider.taskRequestModel?.callComment != null) ...[
const Divider().defaultStyle(context), 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) { Widget contactInfoCard(BuildContext context, TaskData? taskModel) {
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -270,6 +323,16 @@ class _TaskRequestDetailsViewState extends State<TaskRequestDetailsView> {
'${context.translation.assetNo}: ${taskModel.asset?.assetNumber ?? "-"}'.bodyText(context), '${context.translation.assetNo}: ${taskModel.asset?.assetNumber ?? "-"}'.bodyText(context),
'${context.translation.manufacture}: ${taskModel.asset?.manufacturer ?? "-"}'.bodyText(context), '${context.translation.manufacture}: ${taskModel.asset?.manufacturer ?? "-"}'.bodyText(context),
'${context.translation.model}: ${taskModel.asset?.model ?? "-"}'.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(); : 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), fillColor: AppColor.fieldBgColor(context),
errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60), errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60),
floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20), 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)), labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
suffixIcon: loading ? const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3.0).paddingOnly(end: 8) : null, suffixIcon: loading ? const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3.0).paddingOnly(end: 8) : null,
), ),

@ -165,6 +165,10 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
AppTextFormField( AppTextFormField(
initialValue: "", initialValue: "",
labelText: "How would the requested technology solve the current situation and/or serve the purpose?", 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), backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
floatingLabelStyle: 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( AppTextFormField(
initialValue: "", initialValue: "",
labelText: "What is the current practice?", labelText: "What is the current practice?",
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false, showShadow: false,
@ -191,12 +199,16 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: "", initialValue: "",
makeMultiLinesNull: true, makeMultiLinesNull: true,
labelText: "Census Q1", labelText: "Census Q1",
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false, showShadow: false,
textInputType: TextInputType.number, textInputType: TextInputType.text,
onChange: (value) { onChange: (value) {
trafRequest?.censusQ1 = int.tryParse(value); trafRequest?.censusQ1 = value;
}, },
), ),
12.height, 12.height,
@ -204,12 +216,16 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: "", initialValue: "",
makeMultiLinesNull: true, makeMultiLinesNull: true,
labelText: "Census Q2", labelText: "Census Q2",
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false, showShadow: false,
textInputType: TextInputType.number, textInputType: TextInputType.text,
onChange: (value) { onChange: (value) {
trafRequest?.censusQ2 = int.tryParse(value); trafRequest?.censusQ2 = value;
}, },
), ),
12.height, 12.height,
@ -217,12 +233,16 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: "", initialValue: "",
makeMultiLinesNull: true, makeMultiLinesNull: true,
labelText: "Census Q3", labelText: "Census Q3",
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false, showShadow: false,
textInputType: TextInputType.number, textInputType: TextInputType.text,
onChange: (value) { onChange: (value) {
trafRequest?.censusQ3 = int.tryParse(value); trafRequest?.censusQ3 = value;
}, },
), ),
12.height, 12.height,
@ -230,12 +250,16 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: "", initialValue: "",
makeMultiLinesNull: true, makeMultiLinesNull: true,
labelText: "Census Q4", labelText: "Census Q4",
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false, showShadow: false,
textInputType: TextInputType.number, textInputType: TextInputType.text,
onChange: (value) { onChange: (value) {
trafRequest?.censusQ4 = int.tryParse(value); trafRequest?.censusQ4 = value;
}, },
), ),
12.height, 12.height,
@ -264,7 +288,8 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
dense: true, dense: true,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
title: Text("Name: ${userBasedOnSearch[index].userName ?? ""}"), 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(() { trailing: const Icon(Icons.delete_rounded, color: Color(0xffF63939), size: 20).onPress(() {
userBasedOnSearch.removeAt(index); userBasedOnSearch.removeAt(index);
setState(() {}); setState(() {});
@ -286,7 +311,7 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: isUsedSolelyOrShared, initialValue: isUsedSolelyOrShared,
onSelect: (value) { onSelect: (value) {
isUsedSolelyOrShared = value; isUsedSolelyOrShared = value;
trafRequest?.usingSolelyOrSharedId = value?.value; trafRequest?.usingSolelyOrSharedId = value?.id;
if (isUsedSolelyOrShared?.value != 1) { if (isUsedSolelyOrShared?.value != 1) {
departments = []; departments = [];
trafRequest?.trafDepartments = []; trafRequest?.trafDepartments = [];
@ -329,7 +354,7 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: otherServicesEffects, initialValue: otherServicesEffects,
onSelect: (value) { onSelect: (value) {
otherServicesEffects = value; otherServicesEffects = value;
trafRequest?.isEffectedId = value?.value; trafRequest?.isEffectedId = value?.id;
if (otherServicesEffects?.value != 1) { if (otherServicesEffects?.value != 1) {
trafRequest?.effectedServices = null; trafRequest?.effectedServices = null;
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
@ -347,6 +372,10 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
textInputType: TextInputType.multiline, textInputType: TextInputType.multiline,
alignLabelWithHint: true, alignLabelWithHint: true,
node: otherServicesEffectsNode, node: otherServicesEffectsNode,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
labelText: "List down these services and stat how would it be effected", labelText: "List down these services and stat how would it be effected",
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
@ -367,7 +396,7 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
initialValue: useInCombination, initialValue: useInCombination,
onSelect: (value) { onSelect: (value) {
useInCombination = value; useInCombination = value;
trafRequest?.isCombinationId = value?.value; trafRequest?.isCombinationId = value?.id;
if (useInCombination?.value != 1) { if (useInCombination?.value != 1) {
trafRequest?.usedWithCombination = null; trafRequest?.usedWithCombination = null;
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
@ -384,6 +413,10 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
textInputType: TextInputType.multiline, textInputType: TextInputType.multiline,
alignLabelWithHint: true, alignLabelWithHint: true,
node: useInCombinationNode, node: useInCombinationNode,
validator: (value) {
if ((value ?? "").isEmpty) return "Mandatory";
return null;
},
labelText: "kindly describe in detail", labelText: "kindly describe in detail",
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
@ -430,14 +463,51 @@ class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
} }
void _verifyAndSubmit() async { 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?.employeeId = context.userProvider.user?.userID;
trafRequest?.siteId = context.userProvider.user?.clientId; trafRequest?.siteId = context.userProvider.user?.clientId;
trafRequest?.trafContacts = []; trafRequest?.trafContacts = [];
trafRequest?.trafContacts = userBasedOnSearch.map((item) => TrafContacts(id: 0, trafId: 0, name: item.userName, userId: item.userId)).toList(); 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); 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); Utils.hideLoading(context);
if (isSuccess) {
Navigator.pop(context); 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/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.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/app_loading.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
import 'asset_analytics_model.dart';
import 'traf_request_model.dart'; import 'traf_request_model.dart';
class TrafRequestDetailPage extends StatefulWidget { class TrafRequestDetailPage extends StatefulWidget {
@ -51,7 +53,9 @@ class _TrafRequestDetailPageState extends State<TrafRequestDetailPage> {
builder: (_, isLoading, __) { builder: (_, isLoading, __) {
if (isLoading) return const ALoading(); if (isLoading) return const ALoading();
TrafRequestProvider trafProvider = Provider.of<TrafRequestProvider>(context, listen: false); TrafRequestProvider trafProvider = Provider.of<TrafRequestProvider>(context, listen: false);
return Column( return trafProvider.trafRequestDataModel == null
? const NoDataFound().center
: Column(
children: [ children: [
ListView( ListView(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
@ -90,13 +94,14 @@ class _TrafRequestDetailPageState extends State<TrafRequestDetailPage> {
), ),
8.height, 8.height,
'${context.translation.employeeId}: ${data.employeeIdForDisplay ?? '-'}'.bodyText(context), '${context.translation.employeeId}: ${data.employeeIdForDisplay ?? '-'}'.bodyText(context),
'${context.translation.name}: ${data.employeeName ?? '-'}'.bodyText(context), // todo ask shaheer '${context.translation.name}: ${data.employeeName ?? '-'}'.bodyText(context),
'${context.translation.email}: ${data.employeeEmail ?? '-'}'.bodyText(context), // todo ask shaheer '${context.translation.email}: ${data.employeeEmail ?? '-'}'.bodyText(context),
'Position: ${data.positionName ?? '-'}'.bodyText(context), // todo ask shaheer 'Position: ${data.positionName ?? '-'}'.bodyText(context),
'${context.translation.site}: ${data.siteName ?? '-'}'.bodyText(context), '${context.translation.site}: ${data.siteName ?? '-'}'.bodyText(context),
'${context.translation.department}: ${data.departments?.map((item) => item.departmentName).toList() ?? '-'}'.bodyText(context), '${context.translation.department}: ${data.departmentName}'.bodyText(context),
'Requester Extension: ${data.requesterExtensionName ?? '-'}'.bodyText(context), // 'Requester Extension: ${data.requesterExtensionName ?? '-'}'.bodyText(context),
'${context.translation.extensionNo}: ${data.requesterExtensionNumber ?? '-'}'.bodyText(context), 'Number/Contact Information: ${data.requesterContactNumber ?? '-'}'.bodyText(context),
'Extension: ${data.requesterExtensionNumber ?? '-'}'.bodyText(context),
], ],
).toShadowContainer(context, borderRadius: 20, padding: 12); ).toShadowContainer(context, borderRadius: 20, padding: 12);
} }
@ -127,10 +132,22 @@ class _TrafRequestDetailPageState extends State<TrafRequestDetailPage> {
.bodyText(context), .bodyText(context),
4.height, 4.height,
'Is the requesting department going to use the technology solely or shared with other departments?:\n${data.usingSolelyOrSharedName ?? '-'}'.bodyText(context), '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, 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, 4.height,
'Is the equipment going to be used with combination of other equipment to accomplish a specific procedure?:\n${data.usedWithCombination ?? '-'}'.bodyText(context), '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.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); ).toShadowContainer(context, borderRadius: 20, padding: 12);
} }
@ -149,16 +166,29 @@ class _TrafRequestDetailPageState extends State<TrafRequestDetailPage> {
'${context.translation.model}: ${data.modelName ?? '-'}'.bodyText(context), '${context.translation.model}: ${data.modelName ?? '-'}'.bodyText(context),
'${context.translation.manufacture}: ${data.manufacturerName ?? '-'}'.bodyText(context), '${context.translation.manufacture}: ${data.manufacturerName ?? '-'}'.bodyText(context),
if (data.requestTypeId == 733) ...[ if (data.requestTypeId == 733) ...[
'Last price & PO: ${data.poNumber ?? '-'}'.bodyText(context), FutureBuilder<AssetAnalytics?>(
'The quantity of the same asset: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer future: Provider.of<TrafRequestProvider>(context, listen: false).getAssetAnalytics(data.assetId!),
'Existing asset under SLA: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer builder: (cxt, snapshot) {
'Age of the asset: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer if (snapshot.connectionState == ConnectionState.waiting) {
'Total Maintenance Cost (TMC): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer return const SizedBox.square(dimension: 24, child: CircularProgressIndicator()).center;
'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 if (snapshot.hasData) {
'Down Time (DT): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
'Up Time (UT): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer 'Last price: ${snapshot.data?.lastPrice ?? '-'}'.bodyText(context),
'Purchased Price: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer '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); ).toShadowContainer(context, borderRadius: 20, padding: 12);

@ -51,12 +51,15 @@ class TrafRequestDataModel {
String? employeeEmail; String? employeeEmail;
int? positionId; int? positionId;
String? positionName; String? positionName;
String? departmentId;
String? departmentName;
List<Departments>? departments; List<Departments>? departments;
List<Departments>? trafDepartments; List<Departments>? trafDepartments;
int? siteId; int? siteId;
String? siteName; String? siteName;
String? requesterExtensionNumber; String? requesterExtensionNumber;
String? requesterExtensionName; String? requesterExtensionName;
String? requesterContactNumber;
int? requesterExtensionPositionId; int? requesterExtensionPositionId;
String? requesterExtensionPositionName; String? requesterExtensionPositionName;
int? requestTypeId; int? requestTypeId;
@ -74,10 +77,10 @@ class TrafRequestDataModel {
int? qty; int? qty;
String? purposeAnswer; String? purposeAnswer;
String? currentPractise; String? currentPractise;
int? censusQ1; String? censusQ1;
int? censusQ2; String? censusQ2;
int? censusQ3; String? censusQ3;
int? censusQ4; String? censusQ4;
List<TrafContacts>? trafContacts; List<TrafContacts>? trafContacts;
int? usingSolelyOrSharedId; int? usingSolelyOrSharedId;
String? usingSolelyOrSharedName; String? usingSolelyOrSharedName;
@ -124,7 +127,7 @@ class TrafRequestDataModel {
String? approvalDocDate; String? approvalDocDate;
String? isAssigned; String? isAssigned;
String? poNumber; String? poNumber;
int? apiDirectorId; String? apiDirectorId;
String? apiDirectorName; String? apiDirectorName;
int? apiDirectorApprovalId; int? apiDirectorApprovalId;
String? apiDirectorApprovalName; String? apiDirectorApprovalName;
@ -146,12 +149,15 @@ class TrafRequestDataModel {
this.employeeEmail, this.employeeEmail,
this.positionId, this.positionId,
this.positionName, this.positionName,
this.departmentId,
this.departmentName,
this.departments, this.departments,
this.trafDepartments, this.trafDepartments,
this.siteId, this.siteId,
this.siteName, this.siteName,
this.requesterExtensionNumber, this.requesterExtensionNumber,
this.requesterExtensionName, this.requesterExtensionName,
this.requesterContactNumber,
this.requesterExtensionPositionId, this.requesterExtensionPositionId,
this.requesterExtensionPositionName, this.requesterExtensionPositionName,
this.requestTypeId, this.requestTypeId,
@ -241,6 +247,8 @@ class TrafRequestDataModel {
employeeEmail = json['employeeEmail']; employeeEmail = json['employeeEmail'];
positionId = json['positionId']; positionId = json['positionId'];
positionName = json['positionName']; positionName = json['positionName'];
departmentId = json['departmentId'];
departmentName = json['departmentName'];
if (json['departments'] != null) { if (json['departments'] != null) {
departments = <Departments>[]; departments = <Departments>[];
json['departments'].forEach((v) { json['departments'].forEach((v) {
@ -257,6 +265,7 @@ class TrafRequestDataModel {
siteName = json['siteName']; siteName = json['siteName'];
requesterExtensionNumber = json['requesterExtensionNumber']; requesterExtensionNumber = json['requesterExtensionNumber'];
requesterExtensionName = json['requesterExtensionName']; requesterExtensionName = json['requesterExtensionName'];
requesterContactNumber = json['requesterContactNumber'];
requesterExtensionPositionId = json['requesterExtensionPositionId']; requesterExtensionPositionId = json['requesterExtensionPositionId'];
requesterExtensionPositionName = json['requesterExtensionPositionName']; requesterExtensionPositionName = json['requesterExtensionPositionName'];
requestTypeId = json['requestTypeId']; requestTypeId = json['requestTypeId'];
@ -363,6 +372,8 @@ class TrafRequestDataModel {
data['employeeEmail'] = this.employeeEmail; data['employeeEmail'] = this.employeeEmail;
data['positionId'] = this.positionId; data['positionId'] = this.positionId;
data['positionName'] = this.positionName; data['positionName'] = this.positionName;
data['departmentId'] = this.departmentId;
data['departmentName'] = this.departmentName;
if (this.departments != null) { if (this.departments != null) {
data['departments'] = this.departments!.map((v) => v.toJson()).toList(); data['departments'] = this.departments!.map((v) => v.toJson()).toList();
} }
@ -373,6 +384,7 @@ class TrafRequestDataModel {
data['siteName'] = this.siteName; data['siteName'] = this.siteName;
data['requesterExtensionNumber'] = this.requesterExtensionNumber; data['requesterExtensionNumber'] = this.requesterExtensionNumber;
data['requesterExtensionName'] = this.requesterExtensionName; data['requesterExtensionName'] = this.requesterExtensionName;
data['requesterContactNumber'] = this.requesterContactNumber;
data['requesterExtensionPositionId'] = this.requesterExtensionPositionId; data['requesterExtensionPositionId'] = this.requesterExtensionPositionId;
data['requesterExtensionPositionName'] = this.requesterExtensionPositionName; data['requesterExtensionPositionName'] = this.requesterExtensionPositionName;
data['requestTypeId'] = this.requestTypeId; 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/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/controllers/api_routes/urls.dart';
import 'asset_analytics_model.dart';
import 'traf_request_model.dart'; import 'traf_request_model.dart';
class TrafRequestProvider extends ChangeNotifier { class TrafRequestProvider extends ChangeNotifier {
@ -12,25 +13,21 @@ class TrafRequestProvider extends ChangeNotifier {
TrafRequestDataModel? trafRequestDataModel; TrafRequestDataModel? trafRequestDataModel;
Future<int> addTraf(Map<String, dynamic> body) async { Future<bool> addTraf(Map<String, dynamic> body) async {
try { try {
isLoading = true;
notifyListeners();
Response response = await ApiManager.instance.post(URLs.addTRAF, body: body); Response response = await ApiManager.instance.post(URLs.addTRAF, body: body);
if (response.statusCode >= 200 && response.statusCode < 300) { if (response.statusCode >= 200 && response.statusCode < 300) {
// trafRequestDataModel = TrafRequestDataModel.fromJson(json.decode(response.body)["data"]); // trafRequestDataModel = TrafRequestDataModel.fromJson(json.decode(response.body)["data"]);
return true;
} }
isLoading = false; return false;
notifyListeners();
return 0;
} catch (error) { } catch (error) {
isLoading = false; return false;
notifyListeners();
return -1;
} }
} }
Future<int> getTRAFById(int trafId) async { Future<int> getTRAFById(int trafId) async {
trafRequestDataModel = null;
try { try {
isLoading = true; isLoading = true;
notifyListeners(); notifyListeners();
@ -47,4 +44,16 @@ class TrafRequestProvider extends ChangeNotifier {
return -1; 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; loading = true;
}); });
} }
List<UsersBasedOnSearchModel> workOrders = (await _TechnologyUsersProvider.getUsersBasedOnSearch(textEditingValue.text)); List<UsersBasedOnSearchModel> workOrders = (await _TechnologyUsersProvider.getUsersBasedOnSearch(context.userProvider.user!.clientId!, textEditingValue.text));
setState(() { setState(() {
loading = false; loading = false;
}); });
return workOrders; 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) { fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
return TextField( return TextField(
controller: _controller, controller: _controller,

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

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

@ -210,7 +210,7 @@ class _MultipleItemDropDownMenuState<T extends Base, X extends LoadingListNotifi
: null, : null,
) )
.expanded, .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/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/user_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/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.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/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/site_contact_info_model.dart'; import 'package:test_sa/models/site_contact_info_model.dart';
@ -77,7 +75,7 @@ class ContactUsBottomSheet extends StatelessWidget {
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
iconSize: 20, iconSize: 20,
onPressed: () { onPressed: () {
FlutterClipboard.copy('Hello Flutter friends'); // FlutterClipboard.copy('Hello Flutter friends');
}, },
) )
], ],

@ -77,7 +77,7 @@ class CreateRequestTypeBottomSheet extends StatelessWidget {
size: 32, size: 32,
), ),
//24.height, //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/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/user_types.dart'; import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/search_all_requests_model.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/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_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.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; types["System Internal Audit".addTranslation] = 11;
} }
if (context.settingProvider.isUserFlowMedical) { if (context.settingProvider.isUserFlowMedical && isEngineer) {
types['Recall and Alert'] = 7; types['Recall and Alert'] = 7;
} }
@ -125,6 +126,7 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
body: Column( body: Column(
children: [ children: [
SingleChildScrollView( SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
@ -208,11 +210,11 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
// setState(() {}); // setState(() {});
// }), // }),
], ],
).paddingOnly(start: 16, end: 16), ),
).expanded, ).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/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_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_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.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( child: Column(
children: [ children: [
SingleChildScrollView( SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -124,9 +126,9 @@ class _AllRequestsSearchPageState extends State<AllRequestsSearchPage> {
], ],
), ),
).expanded, ).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:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/all_requests_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/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_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/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.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/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/user_types.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 //TODO unCommit this to enable task
requestsList.add(Request(6, context.translation.taskRequest)); requestsList.add(Request(6, context.translation.taskRequest));
//after confirm name add this to translation... //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')); 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) { if (context.userProvider.user!.type == UsersTypes.normal_user) {
requestsList.add(Request(9, 'TRAF')); 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/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/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/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/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/modules/traf_module/traf_request_item_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
@ -48,36 +49,30 @@ class RequestPaginatedListview extends StatelessWidget {
} }
Widget _buildRequestItem(Data request) { Widget _buildRequestItem(Data request) {
//TODO need to replace with switch statement switch (request.transactionNo) {
bool isServiceRequest = request.transactionNo == 1; case 1:
bool isGasRefill = request.transactionNo == 2; return ServiceRequestItemView(requestData: request);
bool isAssetTransfer = request.transactionNo == 3; case 2:
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); return GasRefillItemView(requestData: request);
} else if (isPPMs) { case 3:
return PpmItemView(requestData: request);
} else if (isAssetTransfer) {
return DeviceItemView(requestData: request); return DeviceItemView(requestData: request);
} else if (isRecurrentTask) { case 4:
return PpmItemView(requestData: request);
case 5:
return RecurrentWoItemView(requestData: request); return RecurrentWoItemView(requestData: request);
} else if (isTask) { case 6:
return TaskRequestItemView(requestData: request); return TaskRequestItemView(requestData: request);
} else if (isTRAF) { case 7:
return TaskRequestItemView(requestData: request);
case 8:
return InventorySessionItemView(requestData: request);
case 9:
return TrafRequestItemView(requestData: request); return TrafRequestItemView(requestData: request);
} else if (isEquipmentInternalAudit) { case 10:
return EquipmentInternalAuditItemView(requestData: request); return EquipmentInternalAuditItemView(requestData: request);
} else if (isSystemInternalAudit) { case 11:
return SystemInternalAuditItemView(requestData: request); return SystemInternalAuditItemView(requestData: request);
} else { default:
return Container( return Container(
height: 100, height: 100,
width: double.infinity, width: double.infinity,
@ -86,16 +81,3 @@ class RequestPaginatedListview extends StatelessWidget {
} }
} }
} }
// 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/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/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/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/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/modules/traf_module/traf_request_item_view.dart';
import 'package:test_sa/new_views/app_style/app_color.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]); return TaskRequestItemView(requestDetails: list[index]);
case 7: case 7:
return TaskRequestItemView(requestDetails: list[index]); return TaskRequestItemView(requestDetails: list[index]);
case 8:
return InventorySessionItemView(requestDetails: list[index]);
case 9: case 9:
return TrafRequestItemView(requestDetails: list[index]); return TrafRequestItemView(requestDetails: list[index]);
//Need to verify the type No.. //Need to verify the type No..

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

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

@ -17,11 +17,16 @@ class AssetPicker extends StatelessWidget {
final List<Asset> deviceList; final List<Asset> deviceList;
final bool editable; final bool editable;
final bool showAssetInfo; final bool showAssetInfo;
final bool showBorder;
final Color? borderColor; final Color? borderColor;
final Color? buttonColor; final Color? buttonColor;
final Color? iconColor;
final Color? labelColor;
final String? label;
Color? backgroundColor; Color? backgroundColor;
final bool forPPM; final bool forPPM;
final bool showLoading; final bool showLoading;
final bool enablePickManually;
final bool multiSelection; final bool multiSelection;
AssetPicker( AssetPicker(
@ -34,10 +39,14 @@ class AssetPicker extends StatelessWidget {
this.onAssetRemove, this.onAssetRemove,
this.borderColor, this.borderColor,
this.buttonColor, this.buttonColor,
this.label,
this.iconColor,
this.labelColor,
this.backgroundColor, this.backgroundColor,
this.showAssetInfo = true, this.showAssetInfo = true,
this.showBorder = false,
this.multiSelection = false, this.multiSelection = false,
this.forPPM = false, this.forPPM = false, this.enablePickManually = true,
this.showLoading = false}) this.showLoading = false})
: assert( : assert(
multiSelection == false || onMultiAssetPick != null, multiSelection == false || onMultiAssetPick != null,
@ -57,15 +66,16 @@ class AssetPicker extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: buttonColor ?? backgroundColor ?? AppColor.blueStatus(context), color: buttonColor ?? backgroundColor ?? AppColor.blueStatus(context),
borderRadius: BorderRadius.circular(10), 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)], // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)],
), ),
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ 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, 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 { ).onPress(() async {
@ -74,6 +84,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr( builder: (context) => AssetScanQr(
title: context.translation.assetScan, title: context.translation.assetScan,
multiSelection: multiSelection, multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as List<Asset>?; ))) as List<Asset>?;
if (device?.isNotEmpty ?? false) { if (device?.isNotEmpty ?? false) {
onMultiAssetPick!(device!); onMultiAssetPick!(device!);
@ -83,6 +94,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr( builder: (context) => AssetScanQr(
title: context.translation.assetScan, title: context.translation.assetScan,
multiSelection: multiSelection, multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as Asset?; ))) as Asset?;
if (device != null) { if (device != null) {
onPick!(device); onPick!(device);
@ -112,6 +124,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr( builder: (context) => AssetScanQr(
title: context.translation.assetScan, title: context.translation.assetScan,
multiSelection: multiSelection, multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as List<Asset>?; ))) as List<Asset>?;
if (device?.isNotEmpty ?? false) { if (device?.isNotEmpty ?? false) {
onMultiAssetPick!(device!); onMultiAssetPick!(device!);
@ -121,6 +134,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr( builder: (context) => AssetScanQr(
title: context.translation.assetScan, title: context.translation.assetScan,
multiSelection: multiSelection, multiSelection: multiSelection,
enablePickManually: enablePickManually,
))) as Asset?; ))) as Asset?;
if (device != null) { if (device != null) {
onPick!(device); onPick!(device);
@ -131,7 +145,7 @@ class AssetPicker extends StatelessWidget {
if (deviceList.isNotEmpty && showAssetInfo) if (deviceList.isNotEmpty && showAssetInfo)
ListView.separated( ListView.separated(
shrinkWrap: true, shrinkWrap: true,
padding: EdgeInsets.only(top: 16), padding: const EdgeInsets.only(top: 16),
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (cxt, index) => _assetInfoView(deviceList[index], context), itemBuilder: (cxt, index) => _assetInfoView(deviceList[index], context),
separatorBuilder: (cxt, index) => 12.height, separatorBuilder: (cxt, index) => 12.height,
@ -195,10 +209,10 @@ class AssetPicker extends StatelessWidget {
], ],
), ),
8.height, 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, 2.height,
// "${context.translation.manufacture}: ${device.modelDefinition?.manufacturerName}".bodyText(context), // "${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), // "${context.translation.serialNumber}: ${device.assetNumber}".bodyText(context),
// const Divider().defaultStyle(context), // const Divider().defaultStyle(context),
// "${context.translation.department}: ${device.department?.departmentName}".bodyText(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 { class AssetScanQr extends StatefulWidget {
static const String id = "/asset-scan-qr"; 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 String title;
final bool multiSelection; final bool multiSelection;
final bool enablePickManually;
@override @override
_AssetScanQrState createState() => _AssetScanQrState(); _AssetScanQrState createState() => _AssetScanQrState();
@ -86,6 +87,13 @@ class _AssetScanQrState extends State<AssetScanQr> {
controller.scannedDataStream.listen((scanData) async { controller.scannedDataStream.listen((scanData) async {
if (!_scanDone) { if (!_scanDone) {
_scanDone = true; _scanDone = true;
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); final result = await _getDevice(scanData.code!, isQr: true);
if (result.isNotEmpty) { if (result.isNotEmpty) {
if (widget.multiSelection) { if (widget.multiSelection) {
@ -97,6 +105,7 @@ class _AssetScanQrState extends State<AssetScanQr> {
_scanDone = false; _scanDone = false;
} }
} }
}
}); });
}, },
), ),
@ -109,6 +118,7 @@ class _AssetScanQrState extends State<AssetScanQr> {
), ),
], ],
).expanded, ).expanded,
if(widget.enablePickManually)
FooterActionButton.footerContainer( FooterActionButton.footerContainer(
context: context, context: context,
child: AppFilledButton( child: AppFilledButton(

@ -11,23 +11,23 @@ class StatusLabel extends StatelessWidget {
final double radius; final double radius;
final bool labelInCenter; 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 @override
Widget build(BuildContext context) { 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() == 'In progress'.toLowerCase()) label = context.translation.inProgress;
if (label?.toLowerCase() == 'Completed'.toLowerCase()) label = context.translation.completed; if (label?.toLowerCase() == 'Completed'.toLowerCase()) label = context.translation.completed;
if (label?.toLowerCase() == 'Open'.toLowerCase()) label = context.translation.open; if (label?.toLowerCase() == 'Open'.toLowerCase()) label = context.translation.open;
if (label?.toLowerCase() == 'Closed'.toLowerCase()) label = context.translation.closed; if (label?.toLowerCase() == 'Closed'.toLowerCase()) label = context.translation.closed;
if (label?.toLowerCase() == 'Low'.toLowerCase()) label = context.translation.lowPriority; 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() == '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; if (label?.toLowerCase() == 'Waiting for quotation'.toLowerCase()) label = context.translation.waitingForQuotation;
return Container( return Container(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 10), padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 10),
alignment: labelInCenter ? Alignment.center: null, alignment: labelInCenter ? Alignment.center : null,
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: backgroundColor, color: backgroundColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(

@ -1570,6 +1570,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.3.0"
tree_view_flutter:
dependency: "direct main"
description:
name: tree_view_flutter
sha256: "3365e29b7d1b1e6c5098a2a0e77a208a12a9345dfa73865cb4c87657cf387801"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:

@ -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. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.3.10+29 version: 1.3.11+30
environment: environment:
sdk: ">=3.5.0 <4.0.0" sdk: ">=3.5.0 <4.0.0"
@ -95,6 +95,7 @@ dependencies:
safe_device: ^1.2.1 safe_device: ^1.2.1
toggle_switch: ^2.3.0 toggle_switch: ^2.3.0
clipboard: ^2.0.2 clipboard: ^2.0.2
tree_view_flutter: ^1.0.2
local_auth_darwin: any local_auth_darwin: any
dev_dependencies: dev_dependencies:

Loading…
Cancel
Save