diff --git a/android/app/build.gradle b/android/app/build.gradle
index b92d6c6d..b315f561 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -38,12 +38,12 @@ android {
compileOptions {
coreLibraryDesugaringEnabled true
- sourceCompatibility JavaVersion.VERSION_21
- targetCompatibility JavaVersion.VERSION_21
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
- jvmTarget = "21" // Must match the compileOptions target
+ jvmTarget = "17" // Must match the compileOptions target
}
defaultConfig {
diff --git a/assets/images/collesped_arrow_icon.svg b/assets/images/collesped_arrow_icon.svg
new file mode 100644
index 00000000..7980fef7
--- /dev/null
+++ b/assets/images/collesped_arrow_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/expended_arrow_icon.svg b/assets/images/expended_arrow_icon.svg
new file mode 100644
index 00000000..c1085125
--- /dev/null
+++ b/assets/images/expended_arrow_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/app_strings/app_asset.dart b/lib/app_strings/app_asset.dart
index 242f0170..b5d64cea 100644
--- a/lib/app_strings/app_asset.dart
+++ b/lib/app_strings/app_asset.dart
@@ -10,7 +10,7 @@ class AppAsset {
static String maintenanceIcon = 'maintenance_icon';
static String retiredAssetIcon = 'assets/images/retired_asset_icon.svg';
static String sparePartIcon = 'spare_part_icon';
- static String editIcon = 'assets/images/edit_icon.svg';
- static String deleteIcon = 'assets/images/delete_icon.svg';
+ static String editIcon = 'assets/images/edit_icon';
+ static String deleteIcon = 'assets/images/delete_icon';
static String overDueIcon = 'assets/images/overdue.svg';
}
diff --git a/lib/common_widgets/lookup_autocomplete_field.dart b/lib/common_widgets/lookup_autocomplete_field.dart
new file mode 100644
index 00000000..8b296a7d
--- /dev/null
+++ b/lib/common_widgets/lookup_autocomplete_field.dart
@@ -0,0 +1,124 @@
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/models/lookup.dart';
+import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
+import 'package:test_sa/new_views/app_style/app_color.dart';
+import 'package:test_sa/views/app_style/sizing.dart';
+import '../../../extensions/text_extensions.dart';
+import '../../../new_views/app_style/app_text_style.dart';
+
+class LookUpAutoCompleteField extends StatefulWidget {
+ final String initialValue;
+ final String label;
+ final num? assetId;
+ final bool forAssetName;
+ final bool forSupplier;
+ final bool clearAfterPick, isManufacturer;
+ final Function(Lookup) onPick;
+ final Function(String) onChanged;
+ //need to pass directly url
+ const LookUpAutoCompleteField(
+ {Key? key,
+ this.isManufacturer = false,
+ required this.initialValue,
+ required this.label,
+ this.forAssetName = false,
+ this.forSupplier = false,
+ this.assetId,
+ required this.onPick,
+ this.clearAfterPick = true,
+ required this.onChanged})
+ : super(key: key);
+
+ @override
+ _AutoCompletePartsFieldState createState() => _AutoCompletePartsFieldState();
+}
+
+class _AutoCompletePartsFieldState extends State {
+ AssetInventoryProvider? assetInventoryProvider;
+ late TextEditingController _controller;
+
+ @override
+ void initState() {
+ _controller = TextEditingController(text: widget.initialValue);
+ super.initState();
+ }
+
+ @override
+ void didUpdateWidget(covariant LookUpAutoCompleteField oldWidget) {
+ if (widget.initialValue != oldWidget.initialValue) {
+ _controller = TextEditingController(text: widget.initialValue);
+ }
+ super.didUpdateWidget(oldWidget);
+ }
+
+ @override
+ void dispose() {
+ _controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ assetInventoryProvider ??= Provider.of(context);
+ final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10));
+ return Container(
+ decoration: BoxDecoration(
+ color: AppColor.background(context),
+ borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
+ // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)],
+ ),
+ child: Autocomplete(
+ optionsBuilder: (TextEditingValue textEditingValue) async {
+ if (textEditingValue.text.isEmpty) {
+ return const Iterable.empty();
+ }
+ return (await assetInventoryProvider!.getAutoCompleteDetails(query: textEditingValue.text, isManufacturer: widget.isManufacturer, type: widget.forAssetName?1:widget.forSupplier?2:0));
+ },
+ displayStringForOption: (Lookup option) => option.name ?? "",
+ fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
+ return TextField(
+ controller: _controller,
+ focusNode: fieldFocusNode,
+ style: AppTextStyles.bodyText.copyWith(color: AppColor.black10),
+ textAlign: TextAlign.start,
+ decoration: InputDecoration(
+ border: border,
+ disabledBorder: border,
+ focusedBorder: border,
+ enabledBorder: border,
+ errorBorder: border,
+ contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth),
+ constraints: const BoxConstraints(),
+ suffixIconConstraints: const BoxConstraints(minWidth: 0),
+ filled: true,
+ fillColor: AppColor.fieldBgColor(context),
+ errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60),
+ floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20),
+ labelText: widget.label,
+ labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
+ ),
+ textInputAction: TextInputAction.search,
+ onChanged: (text) {
+ widget.onChanged(text);
+ fieldTextEditingController.text = text;
+ },
+ onSubmitted: (String value) {
+ onFieldSubmitted();
+ },
+ );
+ },
+ onSelected: (Lookup selection) {
+ if (widget.clearAfterPick) {
+ _controller.clear();
+ } else {
+ _controller.text = selection.name ?? '';
+ }
+ widget.onPick(selection);
+ },
+ ),
+ );
+ }
+}
diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart
index 587aebc1..4194ca02 100644
--- a/lib/controllers/api_routes/urls.dart
+++ b/lib/controllers/api_routes/urls.dart
@@ -1,15 +1,18 @@
class URLs {
URLs._();
- static const String appReleaseBuildNumber = "26";
+ static const String appReleaseBuildNumber = "28";
+
// static const host1 = "https://atomsm.hmg.com"; // production url
static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
// static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
+ // static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url
// static String _baseUrl = "$_host/mobile";
// static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
static final String _baseUrl = "$_host/mobile"; // host local UAT
// static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM
+ // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation
static String _host = host1;
@@ -22,6 +25,8 @@ class URLs {
// API Routes
static get login => "$_baseUrl/MobileAuth/Login";
+ static get userChangeAssetGroup => "$_baseUrl/MobileAuth/UserChangeAssetGroup";
+
static get getUserInfo => "$_baseUrl/MobileAuth/GetUserInfo";
static get logout => "$_baseUrl/MobileAuth/Logout";
@@ -257,7 +262,9 @@ class URLs {
//Traf
static get addTRAF => "$_baseUrl/TRAF/AddTRAF"; // get
static get getTRAFById => "$_baseUrl/TRAF/GetTRAFById"; // get
+ static get getAssetAnalytics => "$_baseUrl/Asset/GetAssetAnalytics"; // get
static get getAssetNDAutoCompleteByDynamicCodes => "$_baseUrl/AssetNameDefinition/GetAssetNDAutoCompleteByDynamicCodes"; // get// get
+ static get getAssetNameAutoComplete => "$_baseUrl/AssetNameDefinition/GetAssetNameAutoComplete"; // get// get
//gas refill
static get getGasTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=606"; // get
@@ -294,6 +301,7 @@ class URLs {
static get getNurses => "$_baseUrl/Account/GetUserByRoleValue?value=R-7"; // get
static get getNursesBySiteId => "$_baseUrl/Account/GetUserByRoleValueSiteAndAssetGroupBySiteId?value=R-7"; // get
static get getUsersBasedOnSearch => "$_baseUrl/Account/GetUsersBasedOnSearch"; // get
+ static get getUserByRoleValueSiteMobileAutocomplete => "$_baseUrl/Account/GetUserByRoleValueSiteMobileAutocomplete"; // get
// pentry
static get getPentry => "$_baseUrl/return/pentry/details"; // get
@@ -310,18 +318,51 @@ class URLs {
static get getSiteContactInfo => "$_baseUrl/AssetGroupSiteContactInfo"; // add
static get getDepartmentBasedOnSite => "$_baseUrl/TRAFDataSource/GetDepartmentBasedOnSite"; // add
+// asset inventory Urls.
+ static get getAssetInventoryById => '$_baseUrl/AssetInventory/GetAssetInventoryById';
+
+ static get getAssetsInSession => '$_baseUrl/AssetInventory/GetAssetsInSeassion';
+
+ static get getInventoryDetailsByFilter => '$_baseUrl/AssetInventory/GetInventoryDetailsByFilter';
+
+ static get searchAsset => '$_baseUrl/AssetInventory/SearchAsset';
+
+ static get saveAssetInSession => '$_baseUrl/AssetInventory/SaveAssetInSession';
+
+ static get deleteAssetInSession => '$_baseUrl/AssetInventory/DeleteAssetInSession';
+
+ static get getManufacturerOrModelAutoComplete => '$_baseUrl/AssetInventory/GetManufacturerOrModelAutoComplete';
+
+ 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 getInternalAuditSystemById => "$_baseUrl/InternalAuditSystems/GetInternalAuditSystemByIdV2";
+
static get getInternalAuditChecklist => "$_baseUrl/Lookups/GetLookup?lookupEnum=43";
+
static get getInternalAuditWoType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2500";
+
static get getInternalAuditFindingType => "$_baseUrl/Lookups/GetLookup?lookupEnum=2502";
+
static get addOrUpdateEquipmentInternalAudit => "$_baseUrl/InternalAuditEquipments/AddOrUpdateAuditEquipment";
+
static get addOrUpdateInternalAuditSystem => "$_baseUrl/InternalAuditSystems/AddOrUpdateInternalAuditSystem";
+
static get getWoAutoComplete => "$_baseUrl/InternalAuditSystems/AutoCompleteAllWorkOrder";
+
static get updateAuditEquipmentsEngineer => "$_baseUrl/InternalAuditEquipments/UpdateAuditEquipmentsEngineer";
+
static get updateAuditSystemEngineer => "$_baseUrl/InternalAuditSystems/UpdateAuditSystemEngineer";
- static get loadAllWorkOrderDetailsByID => "$_baseUrl/InternalAuditSystems/LoadAllWorkOrderDetailsByID";
+ static get loadAllWorkOrderDetailsByID => "$_baseUrl/InternalAuditSystems/LoadAllWorkOrderDetailsByID";
}
diff --git a/lib/controllers/providers/api/gas_refill_comments.dart b/lib/controllers/providers/api/gas_refill_comments.dart
index 71e85f01..b40d44e4 100644
--- a/lib/controllers/providers/api/gas_refill_comments.dart
+++ b/lib/controllers/providers/api/gas_refill_comments.dart
@@ -48,7 +48,6 @@ class GasRefillCommentsProvider extends ChangeNotifier {
late Response response;
try {
response = await ApiManager.instance.get(URLs.getGazRefillComments + "?gasRefillId=$callId");
-
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
List requestsListJson = json.decode(response.body)["data"];
diff --git a/lib/controllers/providers/api/oracle_code_provider.dart b/lib/controllers/providers/api/oracle_code_provider.dart
index ea8b0978..71375675 100644
--- a/lib/controllers/providers/api/oracle_code_provider.dart
+++ b/lib/controllers/providers/api/oracle_code_provider.dart
@@ -88,7 +88,7 @@ class OracleCodeProvider extends ChangeNotifier {
Future> getAssetByOracleCode(String oracleCode) async {
late Response response;
try {
- response = await ApiManager.instance.post(URLs.getAssetNDAutoCompleteByDynamicCodes, body: {"codeValue": oracleCode});
+ response = await ApiManager.instance.post(URLs.getAssetNameAutoComplete, body: {"pageSize": 1, "pageNumber": 20, "searchText": oracleCode});
List page = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
diff --git a/lib/controllers/providers/api/search_user_provider.dart b/lib/controllers/providers/api/search_user_provider.dart
index 2804e8a6..f13a30ca 100644
--- a/lib/controllers/providers/api/search_user_provider.dart
+++ b/lib/controllers/providers/api/search_user_provider.dart
@@ -46,10 +46,10 @@ class UserSearchProvider extends ChangeNotifier {
notifyListeners();
}
- Future> getUsersBasedOnSearch(String query) async {
+ Future> getUsersBasedOnSearch(int siteId, String query) async {
late Response response;
try {
- response = await ApiManager.instance.get(URLs.getUsersBasedOnSearch + "?searchText=$query");
+ response = await ApiManager.instance.get(URLs.getUserByRoleValueSiteMobileAutocomplete + "?siteId=$siteId&roleValue=R-7&searchText=$query");
List page = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
diff --git a/lib/controllers/providers/api/user_provider.dart b/lib/controllers/providers/api/user_provider.dart
index 5d1495d5..471be087 100644
--- a/lib/controllers/providers/api/user_provider.dart
+++ b/lib/controllers/providers/api/user_provider.dart
@@ -155,6 +155,23 @@ class UserProvider extends ChangeNotifier {
}
}
+ Future 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 logout(BuildContext context) async {
Response response;
try {
diff --git a/lib/controllers/providers/settings/setting_provider.dart b/lib/controllers/providers/settings/setting_provider.dart
index 2482c5b9..63cd4a28 100644
--- a/lib/controllers/providers/settings/setting_provider.dart
+++ b/lib/controllers/providers/settings/setting_provider.dart
@@ -37,7 +37,9 @@ class SettingProvider extends ChangeNotifier {
bool get isUserFlowMedical => _assetGroup?.id == 1;
bool get isUserFMS => _assetGroup?.id == 2;
+
bool get engineerCanCreateCM => isUserFMS;
+
bool get showPriority => !(isUserFMS && user?.type == UsersTypes.normal_user);
// Local authentication instance
@@ -77,8 +79,10 @@ class SettingProvider extends ChangeNotifier {
}
void selectAssetGroup(User user) {
- if(user.assetGroups ==null) return;
- if (user.assetGroups!.length == 1) {
+ if (user.assetGroups == null) return;
+ if (user.selectedAssetGroup != null) {
+ _assetGroup = user.selectedAssetGroup;
+ } else if (user.assetGroups!.length == 1) {
_assetGroup = user.assetGroups!.first;
} else {
int fmIndex = user.assetGroups!.indexWhere((element) => element.id == 1);
@@ -187,14 +191,13 @@ class SettingProvider extends ChangeNotifier {
}
}
-
Future checkIsEnabledFaceId({required bool status}) async {
try {
final response = await ApiManager.instance.post(
URLs.enableFaceId,
showToast: false,
body: {
- 'isEnabled':status,
+ 'isEnabled': status,
},
);
return response.statusCode >= 200 && response.statusCode < 300;
@@ -203,7 +206,6 @@ class SettingProvider extends ChangeNotifier {
}
}
-
Future checkAppUpdate(String buildNumber, String osType) async {
Response response;
bool isValid = false;
diff --git a/lib/dashboard_latest/widgets/app_bar_widget.dart b/lib/dashboard_latest/widgets/app_bar_widget.dart
index f65ed034..a716fd58 100644
--- a/lib/dashboard_latest/widgets/app_bar_widget.dart
+++ b/lib/dashboard_latest/widgets/app_bar_widget.dart
@@ -1,13 +1,16 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
+import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/dashboard_latest/dashboard_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/helper/utils.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/pages/user/notifications/notifications_page.dart';
+import 'package:test_sa/views/widgets/dialogs/confirm_dialog.dart';
import '../../controllers/providers/api/user_provider.dart';
import '../../models/user.dart';
@@ -48,11 +51,11 @@ class AppBarWidget extends StatelessWidget {
children: [
Text(
snapshot.user?.username ?? "", // Simplified null check
- style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontWeight: FontWeight.w600),
+ style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontWeight: FontWeight.w600, fontSize: context.isTablet() ? 14 : null),
),
Text(
snapshot.user?.type?.name.toCamelCase ?? "", // Simplified null check
- style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20),
+ style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, fontSize: context.isTablet() ? 12 : null),
),
],
),
@@ -83,16 +86,29 @@ class AppBarWidget extends StatelessWidget {
borderRadius: BorderRadius.circular(8),
style: TextStyle(color: Theme.of(context).primaryColor),
underline: const SizedBox.shrink(),
- onChanged: (newValue) {
+ onChanged: (newValue) async {
if (settingProvider.assetGroup != newValue) {
- settingProvider.setAssetGroup(newValue);
- WidgetsBinding.instance.addPostFrameCallback((_) {
- DashBoardProvider dashBoardProvider = Provider.of(context, listen: false);
- dashBoardProvider.setTabs(userType: settingProvider.user!.type!, context: context);
- dashBoardProvider.getDashBoardCount(usersType: settingProvider.user!.type!);
- dashBoardProvider.resetRequestDataList();
- dashBoardProvider.getRequestDetail(usersType: settingProvider.user!.type!, status: dashBoardProvider.tabs[dashBoardProvider.currentListIndex].tag);
- });
+ AssetGroup? tempGroup = ApiManager.instance.assetGroup;
+ ApiManager.instance.assetGroup = newValue;
+
+ Utils.showLoading(context);
+ bool isSuccess = await context.userProvider.userChangeAssetGroup();
+ Utils.hideLoading(context);
+ if (isSuccess) {
+ settingProvider.setAssetGroup(newValue);
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ context.settingProvider.setUser(ApiManager.instance.user!);
+ context.userProvider.setUser(ApiManager.instance.user!);
+ DashBoardProvider dashBoardProvider = Provider.of(context, listen: false);
+ dashBoardProvider.setTabs(userType: settingProvider.user!.type!, context: context);
+ dashBoardProvider.getDashBoardCount(usersType: settingProvider.user!.type!);
+ dashBoardProvider.resetRequestDataList();
+ dashBoardProvider.getRequestDetail(usersType: settingProvider.user!.type!, status: dashBoardProvider.tabs[dashBoardProvider.currentListIndex].tag);
+ });
+ } else {
+ ApiManager.instance.assetGroup = tempGroup;
+ context.showConfirmDialog("Failed, Please Try again");
+ }
}
},
items: Provider.of(context, listen: false).user?.assetGroups?.map>((value) {
diff --git a/lib/dashboard_latest/widgets/request_category_fragment.dart b/lib/dashboard_latest/widgets/request_category_fragment.dart
index 95af0330..0736fe80 100644
--- a/lib/dashboard_latest/widgets/request_category_fragment.dart
+++ b/lib/dashboard_latest/widgets/request_category_fragment.dart
@@ -73,7 +73,7 @@ class RequestCategoryFragment extends StatelessWidget {
Widget getTabs({required BuildContext context, required DashBoardProvider requestsProvider, required UsersTypes? userType}) {
List tabs = CategoryTabs.getTabs(userType: userType ?? UsersTypes.normal_user, context: context);
return SizedBox(
- height: 44 + 16,
+ height: 44 + (context.isTablet() ? 36 : 16),
child: ListView.separated(
scrollDirection: Axis.horizontal,
separatorBuilder: (cxt, index) => 12.width,
diff --git a/lib/dashboard_latest/widgets/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart
index 639b3e6a..9ca9daff 100644
--- a/lib/dashboard_latest/widgets/request_category_list.dart
+++ b/lib/dashboard_latest/widgets/request_category_list.dart
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
+import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart';
import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/modules/traf_module/traf_request_item_view.dart';
@@ -50,6 +51,10 @@ class RequestCategoryList extends StatelessWidget {
return RecurrentWoItemView(requestData: request);
case 6:
return TaskRequestItemView(requestData: request);
+ case 7:
+ return TaskRequestItemView(requestData: request);
+ case 8:
+ return InventorySessionItemView(requestData: request);
case 9:
return TrafRequestItemView(requestData: request);
//TODO need to verify this ...
diff --git a/lib/extensions/context_extension.dart b/lib/extensions/context_extension.dart
index 1f36d4ba..85299f73 100644
--- a/lib/extensions/context_extension.dart
+++ b/lib/extensions/context_extension.dart
@@ -19,7 +19,14 @@ extension BuildContextExtension on BuildContext {
SettingProvider get settingProvider => Provider.of(this, listen: false);
UserProvider get userProvider => Provider.of(this, listen: false);
-
+ bool isTablet() {
+ final mediaQueryData = MediaQuery.of(this);
+ final double screenWidth = mediaQueryData.size.width;
+ final double screenHeight = mediaQueryData.size.height;
+ final double devicePixelRatio = mediaQueryData.devicePixelRatio;
+ bool isTablet = (devicePixelRatio < 2 && (screenWidth >= 700 || screenHeight >= 700)) || (devicePixelRatio >= 2 && (screenWidth >= 1000 || screenHeight >= 1000));
+ return isTablet;
+ }
void showConfirmDialog(String message, {String? title, VoidCallback? onTap}) => showDialog(
context: this,
builder: (BuildContext cxt) => ConfirmDialog(message: message, onTap: onTap, title: title),
diff --git a/lib/main.dart b/lib/main.dart
index 1ad94683..f3e3bc3a 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -27,6 +27,7 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart';
+import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart';
import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart';
import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/create_equipment_internal_audit_form.dart';
@@ -302,6 +303,7 @@ class MyApp extends StatelessWidget {
//ChangeNotifierProvider(create: (_) => RequestStatusProvider()),
ChangeNotifierProvider(create: (_) => VendorProvider()),
ChangeNotifierProvider(create: (_) => PpmChecklistStatusProvider()),
+ ChangeNotifierProvider(create: (_) => AssetInventoryProvider()),
],
child: GestureDetector(
onTap: () {
diff --git a/lib/models/all_requests_and_count_model.dart b/lib/models/all_requests_and_count_model.dart
index 511ece33..e980e164 100644
--- a/lib/models/all_requests_and_count_model.dart
+++ b/lib/models/all_requests_and_count_model.dart
@@ -123,11 +123,14 @@ class RequestsDetails {
String? statusReceiver;
String? assetTransferFrom;
String? assetTransferTo;
+ String? sessionType;
String? code;
String? date;
String? siteTransferFrom;
String? siteTransferTo;
int? transactionType;
+ int? numberOfAssets;
+ int? numberOfSites;
RequestsDetails(
{this.id,
@@ -142,6 +145,9 @@ class RequestsDetails {
this.manufacturer,
this.requestType,
this.requestNo,
+ this.numberOfAssets,
+ this.numberOfSites,
+ this.sessionType,
this.gasType,
this.site,
this.statusReceiver,
@@ -165,6 +171,9 @@ class RequestsDetails {
supplier = json['supplier'];
manufacturer = json['manufacturer'];
requestType = json['requestType'];
+ sessionType = json['sessionType'];
+ numberOfAssets = json['numberOfAssets'];
+ numberOfSites = json['numberOfSites'];
requestNo = json['requestNo'];
gasType = json['gasType'];
site = json['site'];
@@ -197,6 +206,9 @@ class RequestsDetails {
data['statusReceiver'] = statusReceiver;
data['assetTransferFrom'] = assetTransferFrom;
data['assetTransferTo'] = assetTransferTo;
+ data['sessionType'] = sessionType;
+ data['numberOfSites'] = numberOfSites;
+ data['numberOfAssets'] = numberOfAssets;
data['code'] = code;
data['date'] = date;
data['siteTransferFrom'] = siteTransferFrom;
diff --git a/lib/models/device/asset.dart b/lib/models/device/asset.dart
index 9473cfcc..1e41dc31 100644
--- a/lib/models/device/asset.dart
+++ b/lib/models/device/asset.dart
@@ -142,11 +142,11 @@ class Asset {
Building? building; // Now nullable
Floor? floor; // Now nullable
Department? department; // Now nullable
+ Rooms? room;
MappedSite? mappedSite; // Now nullable
MappedBuilding? mappedBuilding; // Now nullable
MappedFloor? mappedFloor; // Now nullable
- MappedDepartment? mappedDepartment; // No
- Rooms? room; // Now nullable
+ MappedDepartment? mappedDepartment; //
num? testsDay; // Now nullable
num? purchasingPrice; // Now nullable
String? nbv; // Now nullable
diff --git a/lib/models/new_models/building.dart b/lib/models/new_models/building.dart
index 131d8d40..e112af11 100644
--- a/lib/models/new_models/building.dart
+++ b/lib/models/new_models/building.dart
@@ -1,3 +1,5 @@
+import 'dart:developer';
+
import 'package:test_sa/models/base.dart';
import 'package:test_sa/models/new_models/floor.dart';
@@ -10,15 +12,20 @@ class Building extends Base {
}) : super(identifier: id?.toString() ?? '', name: name); // Handle potential null id
Building.fromJson(dynamic json) {
- id = json['id'];
- identifier = id?.toString() ?? ''; // Handle potential null id
- name = json['name'];
+ id = json['id'] ?? json['buildingId'];
+ identifier = id?.toString() ?? '';
+ name = json['name'] ?? json['buildingName'];
value = json['value'];
if (json['floors'] != null) {
floors = [];
json['floors'].forEach((v) {
floors!.add(Floor.fromJson(v));
});
+ } else if (json['assetInventoryFloors'] != null) {
+ floors = [];
+ json['assetInventoryFloors'].forEach((v) {
+ floors!.add(Floor.fromJson(v));
+ });
}
}
diff --git a/lib/models/new_models/dashboard_detail.dart b/lib/models/new_models/dashboard_detail.dart
index de0617be..093019b2 100644
--- a/lib/models/new_models/dashboard_detail.dart
+++ b/lib/models/new_models/dashboard_detail.dart
@@ -50,11 +50,14 @@ class Data {
String? priorityName;
bool? isHighPriority;
String? assetName;
+ String? sessionType;
String? rejectReason;
String? assetNumber;
String? requestTypeName;
String? requestNo;
int? transactionNo;
+ int? numberOfSites;
+ int? numberOfAssets;
String? nameOfType;
Data(
@@ -63,6 +66,9 @@ class Data {
this.nameOfType,
this.transactionDate,
this.statusName,
+ this.numberOfAssets,
+ this.numberOfSites,
+ this.sessionType,
this.priorityName,
this.isHighPriority,
this.assetName,
@@ -79,6 +85,9 @@ class Data {
priorityName = json['priorityName'];
isHighPriority = json['isHighPriority'];
assetName = json['assetName'];
+ sessionType = json['sessionType'];
+ numberOfSites = json['numberOfSites'];
+ numberOfAssets = json['numberOfAssets'];
assetNumber = json['assetNumber'];
requestTypeName = json['requestTypeName'];
requestNo = json['requestNo'];
@@ -101,6 +110,9 @@ class Data {
data['requestNo'] = requestNo;
data['rejectReason'] = rejectReason;
data['transactionNo'] = transactionNo;
+ data['sessionType'] = sessionType;
+ data['numberOfAssets'] = numberOfAssets;
+ data['numberOfSites'] = numberOfSites;
data['nameOfType'] = nameOfType;
return data;
}
diff --git a/lib/models/new_models/department.dart b/lib/models/new_models/department.dart
index fb93cc40..e48585da 100644
--- a/lib/models/new_models/department.dart
+++ b/lib/models/new_models/department.dart
@@ -13,7 +13,7 @@ class Department extends Base {
}) : super(identifier: id?.toString() ?? '', name: departmentName); // Handle potential null id
Department.fromJson(dynamic json) {
- id = json['id'];
+ id = json['id']??json['departmentId'];
identifier = id?.toString() ?? ''; // Handle potential null id
departmentName = json['departmentName'] ?? json['name'];
name = departmentName;
@@ -25,6 +25,11 @@ class Department extends Base {
json['rooms'].forEach((v) {
rooms!.add(Rooms.fromJson(v)); // Use '!' since rooms is non-nullable after initialization
});
+ } else if (json['assetInventoryRooms'] != null) {
+ rooms = [];
+ json['assetInventoryRooms'].forEach((v) {
+ rooms!.add(Rooms.fromJson(v)); // Use '!' since rooms is non-nullable after initialization
+ });
}
}
@@ -33,7 +38,7 @@ class Department extends Base {
String? departmentCode; // Now nullable
dynamic departmentId; // Now nullable
String? ntCode; // Now nullable
- List? rooms; // Now nullable
+ List? rooms=[]; // Now nullable
Department copyWith({
num? id, // Parameters are now nullable
diff --git a/lib/models/new_models/floor.dart b/lib/models/new_models/floor.dart
index 2f62da25..33e74d8b 100644
--- a/lib/models/new_models/floor.dart
+++ b/lib/models/new_models/floor.dart
@@ -10,9 +10,9 @@ class Floor extends Base {
}) : super(identifier: id?.toString() ?? '', name: name); // Handle potentialnull id
Floor.fromJson(dynamic json) {
- id = json['id'];
+ id = json['id']??json['floorId'];
identifier = id?.toString() ?? ''; // Handle potential null id
- name = json['name'];
+ name = json['name']??json['floorName'];
value = json['value'];
if (json['departments'] != null) {
departments = [];
@@ -20,6 +20,12 @@ class Floor extends Base {
departments!.add(Department.fromJson(v)); // Use '!' since departments is non-nullable after initialization
});
}
+ else if (json['assetInventoryDepartments'] != null) {
+ departments = [];
+ json['assetInventoryDepartments'].forEach((v) {
+ departments!.add(Department.fromJson(v)); // Use '!' since departments is non-nullable after initialization
+ });
+ }
}
num? id; // Now nullable
diff --git a/lib/models/new_models/room_model.dart b/lib/models/new_models/room_model.dart
index 1fa7ccbe..62012565 100644
--- a/lib/models/new_models/room_model.dart
+++ b/lib/models/new_models/room_model.dart
@@ -10,8 +10,8 @@ class Rooms extends Base {
Rooms.fromJson(Map? json) {
// Handle potential null json input
- id = json?['id']; // Use null-aware operator
- name = json?['name'];
+ id = json?['id']?? json?['roomId'];
+ name = json?['name']??json?['roomName'];
value = json?['value'];
}
diff --git a/lib/models/new_models/site.dart b/lib/models/new_models/site.dart
index e76839fd..83922549 100644
--- a/lib/models/new_models/site.dart
+++ b/lib/models/new_models/site.dart
@@ -9,9 +9,9 @@ class Site extends Base {
}) : super(identifier: id?.toString() ?? '', name: custName); // Handle potential null id
Site.fromJson(dynamic json) {
- id = json['id'];
+ id = json['siteId'] ?? json['id'];
identifier = id?.toString() ?? ''; // Handle potential null id
- custName = json['custName']?? json['siteName'];
+ custName = json['custName']?? json['siteName'];
name = custName;
if (json['buildings'] != null) {
buildings = [];
@@ -19,6 +19,12 @@ class Site extends Base {
buildings!.add(Building.fromJson(v)); // Use '!' since buildings is initialized here
});
}
+ else if (json['assetInventoryBuildings'] != null) {
+ buildings = [];
+ json['assetInventoryBuildings'].forEach((v) {
+ buildings!.add(Building.fromJson(v));
+ });
+ }
}
num? id; // Now nullable
diff --git a/lib/models/new_models/task_request/task_request_model.dart b/lib/models/new_models/task_request/task_request_model.dart
index 3dc5e315..d1b6dc1a 100644
--- a/lib/models/new_models/task_request/task_request_model.dart
+++ b/lib/models/new_models/task_request/task_request_model.dart
@@ -928,6 +928,8 @@ class TaskAsset {
String? roomName;
String? supplierName;
String? assetTypeName;
+ String? poNumber;
+ String? installationDate;
TaskAsset();
@@ -946,24 +948,26 @@ class TaskAsset {
roomName = json['roomName'];
supplierName = json['supplierName'];
assetTypeName = json['assetTypeName'];
+ poNumber = json['poNumber'];
+ installationDate = json['installationDate'];
}
- Map toJson() {
- return {
- 'id': id,
- 'assetNumber': assetNumber,
- 'serialNo': serialNo,
- 'assetName': assetName,
- 'model': model,
- 'manufacturer': manufacturer,
- 'siteName': siteName,
- 'siteId': siteId,
- 'buildingName': buildingName,
- 'floorName': floorName,
- 'departmentName': departmentName,
- 'roomName': roomName,
- 'supplierName': supplierName,
- 'assetTypeName': assetTypeName,
- };
- }
+ Map toJson() => {
+ 'id': id,
+ 'assetNumber': assetNumber,
+ 'serialNo': serialNo,
+ 'assetName': assetName,
+ 'model': model,
+ 'manufacturer': manufacturer,
+ 'siteName': siteName,
+ 'siteId': siteId,
+ 'buildingName': buildingName,
+ 'floorName': floorName,
+ 'departmentName': departmentName,
+ 'roomName': roomName,
+ 'supplierName': supplierName,
+ 'assetTypeName': assetTypeName,
+ 'poNumber': poNumber,
+ 'installationDate': installationDate,
+ };
}
diff --git a/lib/models/new_models/users_based_on_search_model.dart b/lib/models/new_models/users_based_on_search_model.dart
index 54480f91..4dea3117 100644
--- a/lib/models/new_models/users_based_on_search_model.dart
+++ b/lib/models/new_models/users_based_on_search_model.dart
@@ -6,17 +6,11 @@ class UsersBasedOnSearchModel {
int? languageId;
String? extensionNo;
String? phoneNumber;
+ String? positionName;
+ String? position;
bool? isActive;
- UsersBasedOnSearchModel(
- {this.userId,
- this.userName,
- this.email,
- this.employeeId,
- this.languageId,
- this.extensionNo,
- this.phoneNumber,
- this.isActive});
+ UsersBasedOnSearchModel({this.userId, this.userName, this.email, this.employeeId, this.languageId, this.extensionNo, this.phoneNumber, this.positionName, this.position, this.isActive});
UsersBasedOnSearchModel.fromJson(Map json) {
userId = json['userId'];
@@ -26,6 +20,8 @@ class UsersBasedOnSearchModel {
languageId = json['languageId'];
extensionNo = json['extensionNo'];
phoneNumber = json['phoneNumber'];
+ positionName = json['positionName'];
+ position = json['position'];
isActive = json['isActive'];
}
@@ -38,6 +34,8 @@ class UsersBasedOnSearchModel {
data['languageId'] = this.languageId;
data['extensionNo'] = this.extensionNo;
data['phoneNumber'] = this.phoneNumber;
+ data['positionName'] = this.positionName;
+ data['position'] = this.position;
data['isActive'] = this.isActive;
return data;
}
diff --git a/lib/models/user.dart b/lib/models/user.dart
index de6f88b8..76ac1a2c 100644
--- a/lib/models/user.dart
+++ b/lib/models/user.dart
@@ -11,7 +11,6 @@ class User {
List? departmentId;
List? departmentName;
String? message;
-
String? username;
String? userID;
String? email;
@@ -39,6 +38,7 @@ class User {
bool? lockoutEnabled;
int? accessFailedCount;
List? assetGroups;
+ AssetGroup? selectedAssetGroup;
bool? employeeIsHMG;
bool? enableWifi;
bool? enableNFC;
@@ -158,6 +158,7 @@ class User {
map['assetGroups'] = assetGroups!.map((v) => v.toJson()).toList();
}
map['tokenlife'] = tokenlife;
+ map['selectedAssetGroup'] = selectedAssetGroup?.toJson();
map['isAuthenticated'] = isAuthenticated;
map['hasError'] = hasError;
map['profilePhotoName'] = profilePhotoName;
@@ -217,7 +218,7 @@ class User {
userRoles!.add(UserRoles.fromJson(v));
});
}
-
+ selectedAssetGroup = json['selectedAssetGroup'] != null ? AssetGroup.fromJson(json['selectedAssetGroup']) : null;
if (json['assetGroups'] != null) {
assetGroups = [];
json['assetGroups'].forEach((v) {
diff --git a/lib/modules/asset_inventory_module/models/asset_inventory_model.dart b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart
new file mode 100644
index 00000000..4a4e6587
--- /dev/null
+++ b/lib/modules/asset_inventory_module/models/asset_inventory_model.dart
@@ -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? assetList;
+
+ AssetInventoryResponse({
+ this.totalRows,
+ this.count,
+ this.message,
+ this.title,
+ this.innerMessage,
+ this.responseCode,
+ this.isSuccess,
+ this.assetList,
+ });
+
+ AssetInventoryResponse.fromJson(Map json) {
+ totalRows = json['totalRows'];
+ count = json['count'];
+ message = json['message'];
+ title = json['title'];
+ innerMessage = json['innerMessage'];
+ responseCode = json['responseCode'];
+ isSuccess = json['isSuccess'];
+ if (json['data'] != null) {
+ assetList = (json['data'] as List).map((item) => AssetInventoryModel.fromJson(item)).toList();
+ }
+ }
+
+ Map toJson() {
+ return {
+ 'totalRows': totalRows,
+ 'count': count,
+ 'message': message,
+ 'title': title,
+ 'innerMessage': innerMessage,
+ 'responseCode': responseCode,
+ 'isSuccess': isSuccess,
+ };
+ }
+}
+
+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 = [];
+
+ 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 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 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 toJson() {
+ final map = {};
+ map['id'] = id;
+ map['name'] = name;
+ map['originalName'] = originalName;
+ return map;
+ }
+}
diff --git a/lib/modules/asset_inventory_module/models/session_model.dart b/lib/modules/asset_inventory_module/models/session_model.dart
new file mode 100644
index 00000000..8de8503b
--- /dev/null
+++ b/lib/modules/asset_inventory_module/models/session_model.dart
@@ -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 assetInventorySites = [];
+ List assetInventoryAssignedEmployee = [];
+
+ SessionModel({
+ this.id,
+ this.sessionName,
+ this.createdDate,
+ this.sessionTypeId,
+ this.sessionTypeValue,
+ this.sessionTypeName,
+ this.statusId,
+ this.statusName,
+ this.startDate,
+ this.endDate,
+ List? assetInventorySites,
+ List? assetInventoryAssignedEmployee,
+ }) {
+ this.assetInventorySites = assetInventorySites ?? [];
+ this.assetInventoryAssignedEmployee = assetInventoryAssignedEmployee ?? [];
+ }
+
+ SessionModel.fromJson(Map json) {
+ id = json['id'];
+ sessionName = json['sessionName'];
+ sessionTypeId = json['sessionTypeId'];
+ 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 toJson() {
+ final map = {};
+ 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 assetInventoryBuildings = [];
+//
+// AssetInventorySite({
+// this.siteId,
+// this.siteName,
+// List? assetInventoryBuildings,
+// }) {
+// this.assetInventoryBuildings = assetInventoryBuildings ?? [];
+// }
+//
+// AssetInventorySite.fromJson(Map json) {
+// siteId = json['siteId'];
+// siteName = json['siteName'];
+//
+// if (json['assetInventoryBuildings'] != null) {
+// assetInventoryBuildings = (json['assetInventoryBuildings'] as List).map((e) => AssetInventoryBuilding.fromJson(e)).toList();
+// }
+// }
+//
+// Map toJson() {
+// final map = {};
+// map['siteId'] = siteId;
+// map['siteName'] = siteName;
+// map['assetInventoryBuildings'] = assetInventoryBuildings.map((e) => e.toJson()).toList();
+// return map;
+// }
+// }
+//
+// class AssetInventoryBuilding {
+// int? buildingId;
+// String? buildingName;
+// List assetInventoryFloors = [];
+//
+// AssetInventoryBuilding({
+// this.buildingId,
+// this.buildingName,
+// List? assetInventoryFloors,
+// }) {
+// this.assetInventoryFloors = assetInventoryFloors ?? [];
+// }
+//
+// AssetInventoryBuilding.fromJson(Map json) {
+// buildingId = json['buildingId'];
+// buildingName = json['buildingName'];
+//
+// if (json['assetInventoryFloors'] != null) {
+// assetInventoryFloors = (json['assetInventoryFloors'] as List).map((e) => AssetInventoryFloor.fromJson(e)).toList();
+// }
+// }
+//
+// Map toJson() {
+// final map = {};
+// map['buildingId'] = buildingId;
+// map['buildingName'] = buildingName;
+// map['assetInventoryFloors'] = assetInventoryFloors.map((e) => e.toJson()).toList();
+// return map;
+// }
+// }
+//
+// class AssetInventoryFloor {
+// int? floorId;
+// String? floorName;
+// List assetInventoryDepartments = [];
+//
+// AssetInventoryFloor({
+// this.floorId,
+// this.floorName,
+// List? assetInventoryDepartments,
+// }) {
+// this.assetInventoryDepartments = assetInventoryDepartments ?? [];
+// }
+//
+// AssetInventoryFloor.fromJson(Map json) {
+// floorId = json['floorId'];
+// floorName = json['floorName'];
+//
+// if (json['assetInventoryDepartments'] != null) {
+// assetInventoryDepartments = (json['assetInventoryDepartments'] as List).map((e) => AssetInventoryDepartment.fromJson(e)).toList();
+// }
+// }
+//
+// Map toJson() {
+// final map = {};
+// map['floorId'] = floorId;
+// map['floorName'] = floorName;
+// map['assetInventoryDepartments'] = assetInventoryDepartments.map((e) => e.toJson()).toList();
+// return map;
+// }
+// }
+//
+// class AssetInventoryDepartment {
+// int? departmentId;
+// String? departmentName;
+// List assetInventoryRooms = [];
+//
+// AssetInventoryDepartment({
+// this.departmentId,
+// this.departmentName,
+// List? assetInventoryRooms,
+// }) {
+// this.assetInventoryRooms = assetInventoryRooms ?? [];
+// }
+//
+// AssetInventoryDepartment.fromJson(Map json) {
+// departmentId = json['departmentId'];
+// departmentName = json['departmentName'];
+//
+// if (json['assetInventoryRooms'] != null) {
+// assetInventoryRooms = (json['assetInventoryRooms'] as List).map((e) => AssetInventoryRoom.fromJson(e)).toList();
+// }
+// }
+//
+// Map toJson() {
+// final map = {};
+// map['departmentId'] = departmentId;
+// map['departmentName'] = departmentName;
+// map['assetInventoryRooms'] = assetInventoryRooms.map((e) => e.toJson()).toList();
+// return map;
+// }
+// }
+//
+// class AssetInventoryRoom {
+// int? roomId;
+// String? roomName;
+//
+// AssetInventoryRoom({this.roomId, this.roomName});
+//
+// AssetInventoryRoom.fromJson(Map json) {
+// roomId = json['roomId'];
+// roomName = json['roomName'];
+// }
+//
+// Map toJson() {
+// final map = {};
+// map['roomId'] = roomId;
+// map['roomName'] = roomName;
+// return map;
+// }
+// }
+
+class AssetInventoryAssignedEmployee {
+ String? assignedEngineerId;
+ String? assignedEngineerName;
+
+ AssetInventoryAssignedEmployee({this.assignedEngineerId, this.assignedEngineerName});
+
+ AssetInventoryAssignedEmployee.fromJson(Map json) {
+ assignedEngineerId = json['assignedEngineerId'];
+ assignedEngineerName = json['assignedEngineerName'];
+ }
+
+ Map toJson() {
+ final map = {};
+ map['assignedEngineerId'] = assignedEngineerId;
+ map['assignedEngineerName'] = assignedEngineerName;
+ return map;
+ }
+}
diff --git a/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart
new file mode 100644
index 00000000..9d128718
--- /dev/null
+++ b/lib/modules/asset_inventory_module/pages/asset_detail_card_view.dart
@@ -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,
+// )
diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart
new file mode 100644
index 00000000..9337013a
--- /dev/null
+++ b/lib/modules/asset_inventory_module/pages/asset_inventory_detail_view.dart
@@ -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 createState() => _AssetInventoryDetailViewState();
+}
+
+class _AssetInventoryDetailViewState extends State {
+ @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 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 children;
+ final double indent;
+
+ const HierarchyTile({
+ super.key,
+ required this.title,
+ this.children = const [],
+ this.indent = 0,
+ });
+
+ @override
+ State createState() => _HierarchyTileState();
+}
+
+class _HierarchyTileState extends State {
+ 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),
+ ),
+ );
+ }
+}
+
+
diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart
new file mode 100644
index 00000000..f6c2e0b2
--- /dev/null
+++ b/lib/modules/asset_inventory_module/pages/asset_inventory_form_view.dart
@@ -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 createState() => _AssetInventoryFormViewState();
+}
+
+class _AssetInventoryFormViewState extends State {
+ AssetInventoryModel? _scannedAssetModel = AssetInventoryModel();
+ AssetInventoryModel? _pickedAssetModel = AssetInventoryModel();
+ final GlobalKey _formKey = GlobalKey();
+ final GlobalKey _scaffoldKey = GlobalKey();
+ final TextEditingController _assetNoController = TextEditingController();
+ final TextEditingController _serialNoController = TextEditingController();
+ final TextEditingController _remarksController = TextEditingController();
+ ValueNotifier? registeredController;
+ bool isRegistered = false;
+
+ final List 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 searchAsset({required String assetNo}) async {
+ AssetInventoryProvider provider = Provider.of(context, listen: false);
+ Map payload = {
+ "assetNumber": assetNo,
+ "sessionId": widget.assetInventoryModel?.sessionId,
+ "siteId": widget.assetInventoryModel?.site?.id,
+ "buildingId": widget.assetInventoryModel?.building?.id,
+ "floorId": widget.assetInventoryModel?.floor?.id,
+ "departmentId": widget.assetInventoryModel?.department?.id,
+ "roomId": widget.assetInventoryModel?.room?.id,
+ };
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ _scannedAssetModel = await provider.searchAsset(payload: payload);
+ Navigator.pop(context);
+ if (_scannedAssetModel != null) {
+ populateFormValues();
+ }
+ setState(() {});
+ }
+
+ Widget siteInfoContainer({required String label, required String value}) {
+ //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(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(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 getAssetFilteredList({bool loadMore = false}) async {
+ AssetInventoryProvider provider = Provider.of(context, listen: false);
+ Map payload = {
+ "sessionId": widget.assetInventoryModel?.sessionId,
+ "siteId": widget.assetInventoryModel?.site?.id,
+ "buildingId": widget.assetInventoryModel?.building?.id,
+ "floorId": widget.assetInventoryModel?.floor?.id,
+ "departmentId": widget.assetInventoryModel?.department?.id,
+ "roomId": widget.assetInventoryModel?.room?.id,
+ };
+ await provider.getInventoryDetailsByFilter(payload: payload, loadMore: loadMore);
+ provider.getAssetsInSession(
+ sessionId: (widget.assetInventoryModel?.sessionId ?? 0).toInt(),
+ );
+ }
+
+ Future getClassificationData({num? assetImportId}) async {
+ AssetInventoryProvider provider = Provider.of(context, listen: false);
+ Map 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(() {});
+ });
+ }
+}
diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart
new file mode 100644
index 00000000..6240373c
--- /dev/null
+++ b/lib/modules/asset_inventory_module/pages/asset_inventory_page.dart
@@ -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 {
+ late AssetInventoryProvider _assetInventoryProvider;
+
+ @override
+ void initState() {
+ super.initState();
+ _assetInventoryProvider = Provider.of(context, listen: false);
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ getInitialData();
+ });
+ }
+
+ Future 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(builder: (context, provider, child) {
+ return DefaultTabController(
+ length: 2,
+ child: provider.isLoading
+ ? const CircularProgressIndicator(color: AppColor.primary10).center
+ : Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight),
+ decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.white10, borderRadius: BorderRadius.circular(10)),
+ child: TabBar(
+ padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth),
+ labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20,
+ unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20,
+ unselectedLabelStyle: AppTextStyles.bodyText,
+ labelStyle: AppTextStyles.bodyText,
+ indicatorPadding: EdgeInsets.zero,
+ indicatorSize: TabBarIndicatorSize.tab,
+ dividerColor: Colors.transparent,
+ indicator: BoxDecoration(color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, borderRadius: BorderRadius.circular(7)),
+ onTap: (index) {},
+ tabs: [
+ Tab(text: '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 _scanAsset({required AssetInventoryProvider provider}) async {
+ provider.siteFilterAssetList.clear();
+ Navigator.push(context, MaterialPageRoute(builder: (contxt) => SiteInformationPage(sessionModel: provider.sessionModel ?? SessionModel())));
+ }
+}
diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart
new file mode 100644
index 00000000..4bf38915
--- /dev/null
+++ b/lib/modules/asset_inventory_module/pages/asset_inventory_scan_assets_view.dart
@@ -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 createState() => _AssetInventoryScanAssetViewState();
+}
+
+class _AssetInventoryScanAssetViewState extends State {
+ late AssetInventoryProvider assetInventoryProvider;
+
+ @override
+ void initState() {
+ assetInventoryProvider = Provider.of(context, listen: false);
+ super.initState();
+ }
+
+ Future getAssetList({bool loadMore = false}) async {
+ await assetInventoryProvider.getAssetsInSession(
+ sessionId: widget.sessionId,
+ loadMore: loadMore,
+ );
+ }
+
+ @override
+ @override
+ Widget build(BuildContext context) {
+ return Consumer(
+ builder: (context, provider, _) {
+ if (provider.isLoading && provider.assetInventoryResponse == null) {
+ return const Center(child: CircularProgressIndicator());
+ }
+ final assets = provider.assetInventoryResponse?.assetList ?? [];
+ if (assets.isEmpty) {
+ return const Center(child: NoDataFound());
+ }
+ return NotificationListener(
+ onNotification: (scrollInfo) {
+ if (!provider.isNextPageLoading && provider.nextPage && scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
+ getAssetList(loadMore: true);
+ }
+ return false;
+ },
+ child: ListView.separated(
+ padding: const EdgeInsets.all(16),
+ itemCount: assets.length + (provider.isNextPageLoading ? 1 : 0),
+ itemBuilder: (context, index) {
+ 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(
+// builder: (context, provider, _) {
+// if (provider.isLoading && provider.assetInventoryResponse == null) {
+// //TODO need use existing loader if found..
+// return const Center(child: CircularProgressIndicator());
+// }
+// final assets = provider.assetInventoryResponse?.assetList ?? [];
+// if (assets.isEmpty) {
+// return const Center(child: NoDataFound());
+// }
+// return LazyLoading(
+// nextPage: provider.nextPage,
+// onLazyLoad: () async {
+// log('Loading next page...');
+// await getAssetList(loadMore: true);
+// },
+// child: ListView.separated(
+// padding: const EdgeInsets.all(16),
+// itemBuilder: (context, index) {
+// if (index == assets.length) {
+// // bottom loader
+// return const Padding(
+// padding: EdgeInsets.symmetric(vertical: 16),
+// child: Center(child: CircularProgressIndicator()),
+// );
+// }
+// return AssetDetailCardView(
+// assetInventoryModel: assets[index],
+// onDeletePress: () async {
+// await provider.deleteAssetISession(id: assets[index].id ?? 0).then((success) async {
+// if (success) {
+// await provider.getAssetsInSession(sessionId: widget.sessionId);
+// }
+// });
+// },
+// );
+// },
+// separatorBuilder: (context, index) => 12.height,
+// itemCount: assets.length + (provider.nextPage ? 1 : 0),
+// ),
+// );
+// },
+// );
+// }
+}
diff --git a/lib/modules/asset_inventory_module/pages/asset_inventory_site_information_page.dart b/lib/modules/asset_inventory_module/pages/asset_inventory_site_information_page.dart
new file mode 100644
index 00000000..11dcc31b
--- /dev/null
+++ b/lib/modules/asset_inventory_module/pages/asset_inventory_site_information_page.dart
@@ -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 createState() => _SiteInformationPageState();
+}
+
+class _SiteInformationPageState extends State {
+ AssetInventoryModel assetInventoryModel = AssetInventoryModel();
+ bool showMarkAsComplete = false;
+ final ScrollController _scrollController = ScrollController();
+
+ @override
+ void initState() {
+ super.initState();
+ _scrollController.addListener(() {
+ final provider = Provider.of(context, listen: false);
+ if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent && !provider.isNextPageLoading && provider.nextPage) {
+ getAssetFilteredList(loadMore: true);
+ }
+ });
+ }
+
+ final GlobalKey _scaffoldKey = GlobalKey();
+
+ @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(context, listen: false);
+ Map payload = {
+ "sessionId": widget.sessionModel.id,
+ "siteId": assetInventoryModel.site?.id,
+ "buildingId": assetInventoryModel.building?.id,
+ "floorId": assetInventoryModel.floor?.id,
+ "departmentId": assetInventoryModel.department?.id,
+ "roomId": assetInventoryModel.room?.id,
+ };
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ await provider.markAsComplete(payload: payload).then((success) {
+ Navigator.pop(context);
+ if (success) {
+ ///TODO need to confirm need to call this or not ..
+ // AllRequestsProvider allRequestsProvider = Provider.of(context, listen: false);
+ // allRequestsProvider.reset();
+ // allRequestsProvider.getAllRequests(context, typeTransaction: 8);
+ ///Need to call push and remove until...
+ Navigator.pop(context);
+ Navigator.pop(context);
+ }
+ });
+ }
+ }
+
+ Widget assetDetailList() {
+ return Consumer(
+ builder: (context, provider, _) {
+ if (provider.isLoading) {
+ return SizedBox(
+ height: 300.toScreenHeight,
+ child: const CircularProgressIndicator(color: AppColor.primary10).center,
+ );
+ }
+
+ final assets = provider.siteFilterAssetList;
+ return 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(
+ 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(
+ 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(
+ 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(
+ 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(
+ 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 validateRequest() async {
+ if (assetInventoryModel.site == null) {
+ await Fluttertoast.showToast(msg: "Please Select Site");
+ return false;
+ }
+ if (assetInventoryModel.building == null) {
+ await Fluttertoast.showToast(msg: "Please Select Building");
+ return false;
+ }
+ if (assetInventoryModel.floor == null) {
+ await Fluttertoast.showToast(msg: "Please Select Floor");
+ return false;
+ }
+ if (assetInventoryModel.department == null) {
+ await Fluttertoast.showToast(msg: "Please Select Department");
+ return false;
+ }
+ return true;
+ }
+
+ Future getAssetFilteredList({bool loadMore = false}) async {
+ AssetInventoryProvider provider = Provider.of(context, listen: false);
+ Map payload = {
+ "sessionId": widget.sessionModel.id,
+ "siteId": assetInventoryModel.site?.id,
+ "buildingId": assetInventoryModel.building?.id,
+ "floorId": assetInventoryModel.floor?.id,
+ "departmentId": assetInventoryModel.department?.id,
+ "roomId": assetInventoryModel.room?.id,
+ };
+ await provider.getInventoryDetailsByFilter(payload: payload, loadMore: loadMore);
+ }
+}
diff --git a/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart b/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart
new file mode 100644
index 00000000..12adb610
--- /dev/null
+++ b/lib/modules/asset_inventory_module/pages/inventory_session_item_view.dart
@@ -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();
+ }
+}
diff --git a/lib/modules/asset_inventory_module/pages/search_asset_view.dart b/lib/modules/asset_inventory_module/pages/search_asset_view.dart
new file mode 100644
index 00000000..6557d3ed
--- /dev/null
+++ b/lib/modules/asset_inventory_module/pages/search_asset_view.dart
@@ -0,0 +1,276 @@
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:test_sa/controllers/api_routes/urls.dart';
+import 'package:test_sa/extensions/context_extension.dart';
+import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/string_extensions.dart';
+import 'package:test_sa/extensions/text_extensions.dart';
+import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/modules/asset_inventory_module/models/asset_inventory_model.dart';
+import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
+import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
+import 'package:test_sa/views/widgets/equipment/asset_item_listview.dart';
+import 'package:test_sa/views/widgets/horizontal_list_widget.dart';
+import 'package:test_sa/views/widgets/loaders/lazy_loading.dart';
+import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
+import '../../../models/device/asset.dart';
+import '../../../models/device/asset_search.dart';
+import '../../../new_views/app_style/app_color.dart';
+import '../../../new_views/common_widgets/app_lazy_loading.dart';
+import '../../../new_views/common_widgets/custom_app_bar.dart';
+
+class SearchAssetView extends StatefulWidget {
+ static const String id = "asset_search_view";
+ final num sessionId;
+
+ const SearchAssetView({Key? key, required this.sessionId}) : super(key: key);
+
+ @override
+ State createState() => _SearchAssetViewState();
+}
+
+class _SearchAssetViewState extends State {
+ int _selectedIndex = 0;
+ DeviceSearch? search;
+ late TextEditingController _searchController;
+ late AssetInventoryProvider _assetInventoryProvider;
+ final List _searchableList = [];
+ final GlobalKey _formKey = GlobalKey();
+ bool _isFirst = true;
+
+ @override
+ void initState() {
+ _searchController = TextEditingController();
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ _searchController.dispose();
+ _assetInventoryProvider.searchReset();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ List searchBy = [
+ context.translation.assetName,
+ context.translation.model,
+ context.translation.manufacture,
+ context.translation.snNumber,
+ context.translation.siteName,
+ // 'Building Name'.addTranslation,
+ // 'Floor Name'.addTranslation,
+ 'Department Name'.addTranslation,
+
+ ///need to check if want to add more filters
+ ];
+
+ _assetInventoryProvider = Provider.of(context, listen: false);
+
+ return Scaffold(
+ resizeToAvoidBottomInset: false,
+ appBar: CustomAppBar(
+ title: context.translation.searchAsset,
+ ),
+ body: Column(
+ children: [
+ HorizontalListWidget(
+ list: searchBy,
+ callBackFunction: (index) {
+ setState(() {
+ _selectedIndex = index;
+ });
+ },
+ ).paddingOnly(top: 16, bottom: 0),
+ Form(
+ key: _formKey,
+ child: AppTextFormField(
+ controller: _searchController,
+ textInputAction: TextInputAction.search,
+ labelText: "${context.translation.searchBy} ${searchBy[_selectedIndex]}",
+ onAction: _search,
+ onChange: (text) {
+ _searchController.text = text;
+ _searchController.selection = TextSelection.fromPosition(TextPosition(offset: _searchController.text.length));
+ setState(() {});
+ },
+ onSaved: (value) {
+ setState(() {
+ search = DeviceSearch();
+ });
+ _setValue(value);
+ },
+ suffixIcon: IconButton(
+ icon: const Icon(Icons.search),
+ splashColor: Colors.transparent,
+ onPressed: _searchController.text.isNotEmpty ? _search : null,
+ color: AppColor.neutral20,
+ ).paddingOnly(end: 0),
+ ).paddingOnly(top: 16, start: 16, end: 16, bottom: 8),
+ ),
+ Expanded(
+ child: _searchableList.isEmpty
+ ? _isFirst
+ ? const SizedBox()
+ : NoDataFound(message: context.translation.noDeviceFound)
+ : LazyLoading(
+ nextPage: _assetInventoryProvider.nextPage,
+ onLazyLoad: () async {
+ if (_searchController.text.isNotEmpty) {
+ await _assetInventoryProvider.getAssets(search: search, isSearchBy: true, sessionId: widget.sessionId);
+ setState(() {
+ _searchableList.clear();
+ _searchableList.addAll(_assetInventoryProvider.searchDevices);
+ });
+ }
+ },
+ child: Column(
+ children: [
+ ListView.separated(
+ itemCount: _searchableList.length,
+ separatorBuilder: (listContext, itemIndex) => 8.height,
+ padding: const EdgeInsets.all(16),
+ itemBuilder: (listContext, itemIndex) {
+ // bool isSelected = selectedAssets.contains(_searchableList[itemIndex].id!);
+ // String title = isSelected ? "UnSelect" : "Select";
+ return InventoryAssetItemListView(
+ device: _searchableList[itemIndex],
+ // isSelected: isSelected,
+ onPressed: (device) {
+ // Navigator.of(context).pop();
+ Navigator.of(context).pop(device);
+ },
+ // selectButton: Text(title, style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context))),
+ );
+ },
+ ).expanded,
+ ],
+ ),
+ ),
+ )
+ ],
+ ));
+ }
+
+ void _search() async {
+ FocusScope.of(context).unfocus();
+ _formKey.currentState!.save();
+ _assetInventoryProvider.searchReset();
+ showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
+ await _assetInventoryProvider.getAssets(search: search, isSearchBy: true, sessionId: widget.sessionId);
+ setState(() {
+ _searchableList.clear();
+ _searchableList.addAll(_assetInventoryProvider.searchDevices);
+ _isFirst = false;
+ });
+ Navigator.pop(context);
+ }
+
+ _setValue(value) {
+ /// todo : check oracle code (no matched parameter)
+ /// //ontext.translation.assetName,
+ // context.translation.model,
+ // context.translation.manufacture,
+ // context.translation.snNumber,
+ // context.translation.siteName,
+ // // 'Building Name'.addTranslation,
+ // // 'Floor Name'.addTranslation,
+ // 'Department Name'.addTranslation,
+ switch (_selectedIndex) {
+ case 0:
+ search!.assetName = value;
+ break;
+ case 1:
+ search!.model = value;
+ break;
+ case 2:
+ search!.manufacturer = value;
+ break;
+ case 3:
+ search!.assetSerialNumber = value;
+ break;
+ case 4:
+ search!.site = value;
+ break;
+ case 5:
+ search!.department = value;
+ break;
+ default:
+ break;
+ }
+ }
+
+// bool _showResetButton() {
+// return (_searchController?.text?.isNotEmpty ?? false);
+// }
+}
+
+class InventoryAssetItemListView extends StatelessWidget {
+ final AssetInventoryModel device;
+ final Function(AssetInventoryModel) onPressed;
+ final Widget? selectButton;
+ final bool isSelected;
+
+ const InventoryAssetItemListView({Key? key, required this.device, required this.onPressed, this.selectButton, this.isSelected = false}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ width: 95,
+ height: 95,
+ decoration: ShapeDecoration(
+ color: context.isDark ? AppColor.neutral50 : AppColor.neutral30,
+ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
+ image: DecorationImage(
+ fit: BoxFit.cover,
+ image: NetworkImage(device.photo != null ? URLs.getFileUrl(device.photo!)! : "https://www.lasteelcraft.com/images/no-image-available.png"),
+ )),
+ ),
+ 15.width,
+ Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ device.assetName!.cleanupWhitespace.capitalizeFirstOfEach.heading6(context),
+ 8.height,
+ "${context.translation.assetNumber} : ${device.assetNumber}".bodyText(context),
+ "${context.translation.modelName} : ${device.model}".cleanupWhitespace.capitalizeFirstOfEach.bodyText(context),
+ ],
+ ),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ "${context.translation.serialNo} : ${device.serialNo}".bodyText(context).expanded,
+ 4.width,
+ selectButton ??
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ context.translation.viewDetails,
+ style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
+ ),
+ 4.width,
+ Icon(
+ Icons.arrow_forward,
+ color: AppColor.blueStatus(context),
+ size: 14,
+ )
+ ],
+ ),
+ ],
+ )
+ ],
+ ).expanded
+ ],
+ ).toShadowContainer(context, padding: 12, borderColor: isSelected ? AppColor.blueStatus(context) : Colors.transparent).onPress(() => onPressed(device));
+ }
+}
diff --git a/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart b/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart
new file mode 100644
index 00000000..c712c26c
--- /dev/null
+++ b/lib/modules/asset_inventory_module/provider/asset_inventory_provider.dart
@@ -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 _devices = [];
+ List _searchDevices = [];
+
+ List get devices => _devices;
+
+ List get searchDevices => _searchDevices;
+ SessionModel? sessionModel;
+
+ //TODO need to check i think don't need to create this obj
+ AssetInventoryResponse? assetInventoryResponse;
+ AssetInventoryResponse? siteFilterAssetResponse;
+
+ List sessionAssetList = [];
+ List siteFilterAssetList = [];
+
+ void reset() {
+ pageNo = 1;
+ 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 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 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 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 getAssetsInSession({
+ // required int sessionId,
+ // bool loadMore = false,
+ // }) async {
+ // // if (isLoading || nextPage) return -2;
+ //
+ // if (loadMore) {
+ // nextPage = true;
+ // pageNo += 1;
+ // } else {
+ // isLoading = true;
+ // pageNo = 1; // reset pagination
+ // }
+ //
+ // notifyListeners();
+ // log('Fetching page: $pageNo');
+ //
+ // try {
+ // final payload = {
+ // "pageSize": pageItemNumber,
+ // "pageNumber": pageNo,
+ // "sessionId": sessionId,
+ // };
+ //
+ // final response = await ApiManager.instance.post(URLs.getAssetsInSession, body: payload);
+ // stateCode = response.statusCode;
+ //
+ // if (response.statusCode >= 200 && response.statusCode < 300) {
+ // final Map jsonData = json.decode(response.body);
+ // final newResponse = AssetInventoryResponse.fromJson(jsonData);
+ //
+ // if (loadMore) {
+ // assetInventoryResponse?.assetList?.addAll(newResponse.assetList ?? []);
+ // assetInventoryResponse?.totalRows = newResponse.totalRows;
+ // } else {
+ // assetInventoryResponse = newResponse;
+ // }
+ //
+ // nextPage = (assetInventoryResponse?.assetList?.length ?? 0) < (assetInventoryResponse?.totalRows ?? 0);
+ // }
+ //
+ // isLoading = false;
+ // nextPage = false;
+ // notifyListeners();
+ // return response.statusCode;
+ // } catch (error) {
+ // isLoading = false;
+ // nextPage = false;
+ // stateCode = -1;
+ // notifyListeners();
+ // return -1;
+ // }
+ // }
+
+ Future getInventoryDetailsByFilter({
+ required Map payload,
+ bool loadMore = false,
+ }) async {
+ if (isLoading || isNextPageLoading) return -2;
+
+ if (loadMore) {
+ isNextPageLoading = true;
+ pageNo += 1;
+ } else {
+ isLoading = true;
+ pageNo = 1;
+ }
+
+ notifyListeners();
+ log('Fetching inventory page: $pageNo');
+
+ try {
+ final paginatedPayload = {
+ ...payload,
+ "pageSize": pageItemNumber,
+ "pageNumber": pageNo,
+ };
+
+ final response = await ApiManager.instance.post(URLs.getInventoryDetailsByFilter, body: paginatedPayload);
+ stateCode = response.statusCode;
+
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ final Map jsonData = json.decode(response.body);
+ final newResponse = AssetInventoryResponse.fromJson(jsonData);
+
+ if (loadMore) {
+ siteFilterAssetList.addAll(newResponse.assetList ?? []);
+ siteFilterAssetResponse?.totalRows = newResponse.totalRows;
+ } else {
+ siteFilterAssetResponse = newResponse;
+ siteFilterAssetList = newResponse.assetList ?? [];
+ }
+ nextPage = (siteFilterAssetList.length) < (siteFilterAssetResponse?.totalRows ?? 0);
+ } else {
+ siteFilterAssetList = [];
+ nextPage = false;
+ }
+
+ isLoading = false;
+ isNextPageLoading = false;
+ notifyListeners();
+ return response.statusCode;
+ } catch (error) {
+ isLoading = false;
+ isNextPageLoading = false;
+ nextPage = false;
+ stateCode = -1;
+ notifyListeners();
+ return -1;
+ }
+ }
+
+ Future searchAsset({
+ required Map payload,
+ }) async {
+ isLoading = true;
+ try {
+ final response = await ApiManager.instance.post(URLs.searchAsset, body: payload);
+ stateCode = response.statusCode;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ final Map jsonData = json.decode(response.body)["data"];
+ AssetInventoryModel model = AssetInventoryModel.fromJson(jsonData);
+ log('model json ${model.toJson()}');
+ isLoading = false;
+ notifyListeners();
+ return model;
+ } else {
+ isLoading = false;
+ notifyListeners();
+ return null;
+ }
+ } catch (error) {
+ isLoading = false;
+ stateCode = -1;
+ notifyListeners();
+ return null;
+ }
+ }
+
+ Future saveAssetInSession({
+ AssetInventoryModel? model,
+ }) async {
+ isLoading = true;
+ try {
+ 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 getClassification({
+ required Map 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 deleteAssetISession({required num id}) async {
+ try {
+ isLoading = true;
+ notifyListeners();
+ final response = await ApiManager.instance.get(URLs.deleteAssetInSession + "?id=$id");
+ stateCode = response.statusCode;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ isLoading = false;
+ notifyListeners();
+ return true;
+ }
+ isLoading = false;
+ notifyListeners();
+ return false;
+ } catch (e) {
+ log("Delete Asset [error] : $e");
+ isLoading = false;
+ notifyListeners();
+ return false;
+ }
+ }
+
+ Future> getAutoCompleteDetails({
+ bool? isManufacturer,
+ String? query,
+ int type = 0,
+ }) async {
+ try {
+ String url = '';
+ switch (type) {
+ //for model and manufacturer..
+ case 0:
+ url = URLs.getManufacturerOrModelAutoComplete;
+ break;
+ //for asset name..
+ case 1:
+ url = URLs.searchAssetName;
+ break;
+ //for supplier...
+ case 2:
+ url = URLs.getSuppliersAutoCompleteInventory;
+ break;
+ default:
+ url = URLs.getManufacturerOrModelAutoComplete;
+ }
+ final queryParams = {};
+ if (isManufacturer != null && type == 0) {
+ queryParams['isManufacturer'] = isManufacturer.toString();
+ }
+ if (query != null && query.isNotEmpty) {
+ queryParams['searchText'] = query;
+ }
+ if (queryParams.isNotEmpty) {
+ url += '?${Uri(queryParameters: queryParams).query}';
+ }
+ final response = await ApiManager.instance.get(url);
+
+ List list = [];
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ final data = json.decode(response.body)["data"];
+ list = (data as List).map((e) => Lookup.fromJson(e)).toList();
+ }
+ return list;
+ } catch (error) {
+ log('error $error');
+ return [];
+ }
+ }
+
+ Future getAssets({DeviceSearch? search, bool isQr = false, bool isSearchBy = false, num? sessionId}) async {
+ if (isLoading == true) return -2;
+ isLoading = true;
+ notifyListeners();
+ late Response response;
+ try {
+ final Map body = {
+ "pageSize": isSearchBy ? searchPageItemNumber : pageItemNumber,
+ "pageNumber": isSearchBy ? (searchDevices.length / searchPageItemNumber).ceil() + 1 : devices.length ~/ pageItemNumber + 1,
+ "sessionId": sessionId ?? 0,
+ "assetSerialNo": search?.assetSerialNumber ?? '',
+ "assetName": search?.assetName ?? '',
+ "model": search?.model ?? '',
+ "manufacturer": search?.manufacturer ?? '',
+ "supplier": search?.supplier ?? '',
+ "siteName": search?.site ?? '',
+ // "buildingName":search?.??'',
+ // "floorName": search?.f??'',
+ "departmentName": search?.department ?? '',
+ // "roomName": search?.room
+ };
+ // if (search != null) body.addAll(search.toJson());
+ response = await ApiManager.instance.post(URLs.getAssetsTemp, body: body);
+ } catch (error) {
+ isLoading = false;
+ stateCode = -1;
+ notifyListeners();
+ return -1;
+ }
+ stateCode = response.statusCode;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ // client's request was successfully received
+ List equipmentListJson = json.decode(response.body)["data"];
+ var dList = equipmentListJson.map((asset) => AssetInventoryModel.fromJson(asset)).toList() ?? [];
+ isSearchBy ? _searchDevices.addAll(dList) : _devices.addAll(dList);
+ nextPage = true;
+ } else {
+ nextPage = false;
+ }
+ isLoading = false;
+ notifyListeners();
+ return response.statusCode;
+ }
+
+ Future markAsComplete({
+ required Map payload,
+ }) async {
+ isLoading = true;
+ try {
+ final response = await ApiManager.instance.post(URLs.convertDetailToComplete, body: payload);
+ stateCode = response.statusCode;
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ isLoading = false;
+ notifyListeners();
+ return true;
+ } else {
+ isLoading = false;
+ notifyListeners();
+ return false;
+ }
+ } catch (error) {
+ isLoading = false;
+ notifyListeners();
+ return false;
+ }
+ }
+}
diff --git a/lib/modules/cm_module/views/components/service_request_detail_view.dart b/lib/modules/cm_module/views/components/service_request_detail_view.dart
index 8b8da1cd..440715e9 100644
--- a/lib/modules/cm_module/views/components/service_request_detail_view.dart
+++ b/lib/modules/cm_module/views/components/service_request_detail_view.dart
@@ -138,20 +138,20 @@ class _ServiceRequestDetailViewState extends State {
if (Provider.of(context, listen: false).showPriority) ...[
StatusLabel(
label: workOrder.priority?.name,
- id: workOrder.priority!.id!,
+ id: workOrder.priority!.value!,
radius: 4,
- textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.id!),
- backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.id!),
+ textColor: AppColor.getPriorityStatusTextColor(context, workOrder.priority!.value!),
+ backgroundColor: AppColor.getPriorityStatusColor(context, workOrder.priority!.value!),
),
8.width,
],
if (workOrder.itgFormWorkOrderStatus != null) ...[
StatusLabel(
label: workOrder.itgFormWorkOrderStatus,
- id: 0,
+ // id: 0,
radius: 4,
textColor: AppColor.getPriorityStatusTextColor(context, 82),
- backgroundColor: AppColor.getPriorityStatusColor(context, 0),
+ backgroundColor: AppColor.getPriorityStatusColor(context, 1000),
),
8.width,
],
diff --git a/lib/modules/pm_module/ppm_wo/ppm_details_page.dart b/lib/modules/pm_module/ppm_wo/ppm_details_page.dart
index 0ac5b3ae..85b1d569 100644
--- a/lib/modules/pm_module/ppm_wo/ppm_details_page.dart
+++ b/lib/modules/pm_module/ppm_wo/ppm_details_page.dart
@@ -120,16 +120,16 @@ class _PpmDetailsPageState extends State {
context: context,
)
] else ...[
- FooterActionButton.footerContainer(
- context: context,
- child: AppFilledButton(
- onPressed: () async {
- await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdatePpm(ppm: null, planPreventiveVisit: planPreventiveVisit)));
- getVisitData();
- },
- label: context.translation.viewDetails,
- ),
- )
+ // FooterActionButton.footerContainer(
+ // context: context,
+ // child: AppFilledButton(
+ // onPressed: () async {
+ // await Navigator.of(context).push(MaterialPageRoute(builder: (_) => UpdatePpm(ppm: null, planPreventiveVisit: planPreventiveVisit)));
+ // getVisitData();
+ // },
+ // label: context.translation.viewDetails,
+ // ),
+ // )
]
])
: const Center(child: NoDataFound());
diff --git a/lib/modules/pm_module/ppm_wo/update_ppm/ppm_external_details_form.dart b/lib/modules/pm_module/ppm_wo/update_ppm/ppm_external_details_form.dart
index 8b1be526..ad48a65f 100644
--- a/lib/modules/pm_module/ppm_wo/update_ppm/ppm_external_details_form.dart
+++ b/lib/modules/pm_module/ppm_wo/update_ppm/ppm_external_details_form.dart
@@ -58,7 +58,7 @@ class _PpmExternalDetailsFormState extends State {
final ppmProvider = Provider.of(context, listen: false);
return ListView.builder(
itemCount: widget.models!.length + 1,
- padding: const EdgeInsets.all(16),
+ padding: const EdgeInsets.only(left: 16, right: 16, top: 8, bottom: 16),
itemBuilder: (context, index) {
if (index == widget.models!.length) {
return Visibility(
@@ -190,7 +190,7 @@ class _ExternalDetailItemState extends State {
),
child: Icon(Icons.add, color: context.isDark ? null : AppColor.neutral60),
).onPress(() async {
- if(widget.model.supplier==null) {
+ if (widget.model.supplier == null) {
"Please select supplier".showToast;
return;
}
diff --git a/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart b/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart
index e4bd68ba..4441a434 100644
--- a/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart
+++ b/lib/modules/pm_module/ppm_wo/update_ppm/update_ppm.dart
@@ -108,7 +108,7 @@ class _UpdatePpmState extends State with TickerProviderStateMixin {
if (typeOfService == null) {
return;
}
- if (typeOfService?.id == 66) {
+ if (typeOfService?.value == 2) {
ppmProvider.totalTabs = 4;
} else {
ppmProvider.totalTabs = 3;
diff --git a/lib/modules/pm_module/ppm_wo/update_ppm/wo_info_form.dart b/lib/modules/pm_module/ppm_wo/update_ppm/wo_info_form.dart
index 3cef0f21..489ea245 100644
--- a/lib/modules/pm_module/ppm_wo/update_ppm/wo_info_form.dart
+++ b/lib/modules/pm_module/ppm_wo/update_ppm/wo_info_form.dart
@@ -299,7 +299,7 @@ class _WoInfoFormState extends State {
onSelect: (value) {
if (value != null) {
widget.planPreventiveVisit.typeOfService = value;
- if (widget.planPreventiveVisit.typeOfService?.id == 66) {
+ if (widget.planPreventiveVisit.typeOfService?.value == 2) {
ppmProvider.totalTabs = 4;
} else {
ppmProvider.totalTabs = 3;
diff --git a/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart b/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart
index 5e9ff9d6..612992e7 100644
--- a/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart
+++ b/lib/modules/tm_module/tasks_wo/task_request_detail_view.dart
@@ -1,3 +1,4 @@
+import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
@@ -8,12 +9,15 @@ import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/models/new_models/task_request/task_request_model.dart';
+import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
+import 'package:test_sa/new_views/common_widgets/working_time_tile.dart';
import 'package:test_sa/providers/task_request_provider/task_request_provider.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
+import 'package:test_sa/views/widgets/total_working_time_detail_bottomsheet.dart';
import '../../../../controllers/providers/api/user_provider.dart';
import '../../../../models/enums/user_types.dart';
@@ -61,7 +65,6 @@ class _TaskRequestDetailsViewState extends State {
Widget build(BuildContext context) {
userProvider ??= Provider.of(context, listen: false);
return Scaffold(
- // appBar: DefaultAppBar(title:taskProvider?.taskRequestModel?.taskType?.id==7?'Recall and Alert Details': context.translation.taskRequest),
appBar: DefaultAppBar(title: context.translation.taskRequest),
body: Consumer(builder: (context, taskProvider, child) {
TaskData? taskModel = taskProvider.taskRequestModel;
@@ -122,6 +125,7 @@ class _TaskRequestDetailsViewState extends State {
],
),
],
+ showWorkingTime(taskModel?.taskJobActivityEngineerTimers ?? []),
if ((taskProvider.taskRequestModel?.taskJobContactPersons ?? []).isNotEmpty) ...[contactInfoCard(context, taskProvider.taskRequestModel!)],
if (taskProvider.taskRequestModel?.callComment != null) ...[
const Divider().defaultStyle(context),
@@ -167,6 +171,55 @@ class _TaskRequestDetailsViewState extends State {
);
}
+ Widget showWorkingTime(List timer) {
+ if (context.userProvider.user!.type == UsersTypes.normal_user) return const SizedBox();
+
+ double totalWorkingHours = timer.fold(0.0, (sum, item) {
+ if (item.startDate == null || item.endDate == null) return sum;
+ try {
+ final start = DateTime.parse(item.startDate!);
+ final end = DateTime.parse(item.endDate!);
+
+ final diffInHours = end.difference(start).inSeconds / 3600.0; // convert to hours
+
+ return sum + diffInHours;
+ } catch (_) {
+ return sum;
+ }
+ });
+ String totalHourString = (totalWorkingHours > 0.0) ? ServiceRequestUtils.formatTotalWorkingHours(totalWorkingHours) : totalWorkingHours.toString();
+
+ return RichText(
+ text: TextSpan(
+ text: "${context.translation.totalWorkingTime}: ",
+ style: TextStyle(
+ fontSize: 14.toScreenWidth, fontWeight: FontWeight.w500, fontStyle: FontStyle.normal, decoration: TextDecoration.none, color: context.isDark ? AppColor.neutral10 : AppColor.neutral20),
+ children: [
+ TextSpan(text: "$totalHourString ", style: AppTextStyles.bodyText),
+ const WidgetSpan(
+ child: Icon(Icons.info_outline_rounded, color: AppColor.primary10, size: 14),
+ ),
+ ],
+ ),
+ ).onPress(() => showModalBottomSheet(
+ context: context,
+ isDismissible: true,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
+ ),
+ clipBehavior: Clip.antiAliasWithSaveLayer,
+ builder: (BuildContext context) => TotalWorkingTimeDetailBottomSheet(
+ timerList: timer.map((e) {
+ return TimerHistoryModel(
+ id: e.id,
+ startTime: e.startDate,
+ endTime: e.endDate,
+ workingHours: e.totalWorkingHour,
+ );
+ }).toList()),
+ ));
+ }
+
Widget contactInfoCard(BuildContext context, TaskData? taskModel) {
return Column(
mainAxisSize: MainAxisSize.min,
@@ -270,6 +323,16 @@ class _TaskRequestDetailsViewState extends State {
'${context.translation.assetNo}: ${taskModel.asset?.assetNumber ?? "-"}'.bodyText(context),
'${context.translation.manufacture}: ${taskModel.asset?.manufacturer ?? "-"}'.bodyText(context),
'${context.translation.model}: ${taskModel.asset?.model ?? "-"}'.bodyText(context),
+ '${context.translation.serialNo}: ${taskModel.asset?.serialNo ?? "-"}'.bodyText(context),
+ '${context.translation.assetType}: ${taskModel.asset?.assetTypeName ?? "-"}'.bodyText(context),
+ '${context.translation.site}: ${taskModel.asset?.siteName ?? "-"}'.bodyText(context),
+ '${context.translation.building}: ${taskModel.asset?.buildingName ?? "-"}'.bodyText(context),
+ '${context.translation.floor}: ${taskModel.asset?.floorName ?? "-"}'.bodyText(context),
+ '${context.translation.department}: ${taskModel.asset?.departmentName ?? "-"}'.bodyText(context),
+ '${context.translation.room}: ${taskModel.asset?.roomName ?? "-"}'.bodyText(context),
+ '${context.translation.supplier}: ${taskModel.asset?.supplierName ?? "-"}'.bodyText(context),
+ 'PO Number: ${taskModel.asset?.poNumber ?? "-"}'.bodyText(context),
+ '${context.translation.installationDate}: ${taskModel.asset?.installationDate?.toAssetDetailsFormat ?? "-"}'.bodyText(context),
],
)
: const SizedBox();
diff --git a/lib/modules/traf_module/asset_analytics_model.dart b/lib/modules/traf_module/asset_analytics_model.dart
new file mode 100644
index 00000000..2f265c1b
--- /dev/null
+++ b/lib/modules/traf_module/asset_analytics_model.dart
@@ -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 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 toJson() {
+ final Map data = new Map();
+ 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;
+ }
+}
diff --git a/lib/modules/traf_module/asset_auto_complete_field.dart b/lib/modules/traf_module/asset_auto_complete_field.dart
index 0abb378b..e215c4a7 100644
--- a/lib/modules/traf_module/asset_auto_complete_field.dart
+++ b/lib/modules/traf_module/asset_auto_complete_field.dart
@@ -105,7 +105,7 @@ class _AssetAutoCompleteFieldState extends State {
fillColor: AppColor.fieldBgColor(context),
errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60),
floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? null : AppColor.neutral20),
- labelText: context.translation.oracleCode,
+ labelText: "Name/Oracle Code",
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
suffixIcon: loading ? const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3.0).paddingOnly(end: 8) : null,
),
diff --git a/lib/modules/traf_module/create_traf_request_page.dart b/lib/modules/traf_module/create_traf_request_page.dart
index e2d066a9..66133805 100644
--- a/lib/modules/traf_module/create_traf_request_page.dart
+++ b/lib/modules/traf_module/create_traf_request_page.dart
@@ -165,6 +165,10 @@ class _CreateTRAFRequestPageState extends State {
AppTextFormField(
initialValue: "",
labelText: "How would the requested technology solve the current situation and/or serve the purpose?",
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
floatingLabelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
@@ -178,6 +182,10 @@ class _CreateTRAFRequestPageState extends State {
AppTextFormField(
initialValue: "",
labelText: "What is the current practice?",
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
@@ -191,12 +199,16 @@ class _CreateTRAFRequestPageState extends State {
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q1",
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
- textInputType: TextInputType.number,
+ textInputType: TextInputType.text,
onChange: (value) {
- trafRequest?.censusQ1 = int.tryParse(value);
+ trafRequest?.censusQ1 = value;
},
),
12.height,
@@ -204,12 +216,16 @@ class _CreateTRAFRequestPageState extends State {
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q2",
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
- textInputType: TextInputType.number,
+ textInputType: TextInputType.text,
onChange: (value) {
- trafRequest?.censusQ2 = int.tryParse(value);
+ trafRequest?.censusQ2 = value;
},
),
12.height,
@@ -217,12 +233,16 @@ class _CreateTRAFRequestPageState extends State {
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q3",
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
- textInputType: TextInputType.number,
+ textInputType: TextInputType.text,
onChange: (value) {
- trafRequest?.censusQ3 = int.tryParse(value);
+ trafRequest?.censusQ3 = value;
},
),
12.height,
@@ -230,12 +250,16 @@ class _CreateTRAFRequestPageState extends State {
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q4",
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
- textInputType: TextInputType.number,
+ textInputType: TextInputType.text,
onChange: (value) {
- trafRequest?.censusQ4 = int.tryParse(value);
+ trafRequest?.censusQ4 = value;
},
),
12.height,
@@ -264,7 +288,8 @@ class _CreateTRAFRequestPageState extends State {
dense: true,
contentPadding: EdgeInsets.zero,
title: Text("Name: ${userBasedOnSearch[index].userName ?? ""}"),
- subtitle: Text("Email: ${userBasedOnSearch[index].email ?? ""}\nPhone: ${userBasedOnSearch[index].phoneNumber ?? ""}"),
+ subtitle: Text(
+ "Position: ${userBasedOnSearch[index].position ?? "-"}\nEmail: ${userBasedOnSearch[index].email ?? ""}\nPhone: ${userBasedOnSearch[index].phoneNumber ?? ""}"),
trailing: const Icon(Icons.delete_rounded, color: Color(0xffF63939), size: 20).onPress(() {
userBasedOnSearch.removeAt(index);
setState(() {});
@@ -286,7 +311,7 @@ class _CreateTRAFRequestPageState extends State {
initialValue: isUsedSolelyOrShared,
onSelect: (value) {
isUsedSolelyOrShared = value;
- trafRequest?.usingSolelyOrSharedId = value?.value;
+ trafRequest?.usingSolelyOrSharedId = value?.id;
if (isUsedSolelyOrShared?.value != 1) {
departments = [];
trafRequest?.trafDepartments = [];
@@ -329,7 +354,7 @@ class _CreateTRAFRequestPageState extends State {
initialValue: otherServicesEffects,
onSelect: (value) {
otherServicesEffects = value;
- trafRequest?.isEffectedId = value?.value;
+ trafRequest?.isEffectedId = value?.id;
if (otherServicesEffects?.value != 1) {
trafRequest?.effectedServices = null;
FocusScope.of(context).unfocus();
@@ -347,6 +372,10 @@ class _CreateTRAFRequestPageState extends State {
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
node: otherServicesEffectsNode,
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
labelText: "List down these services and stat how would it be effected",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
@@ -367,7 +396,7 @@ class _CreateTRAFRequestPageState extends State {
initialValue: useInCombination,
onSelect: (value) {
useInCombination = value;
- trafRequest?.isCombinationId = value?.value;
+ trafRequest?.isCombinationId = value?.id;
if (useInCombination?.value != 1) {
trafRequest?.usedWithCombination = null;
FocusScope.of(context).unfocus();
@@ -384,6 +413,10 @@ class _CreateTRAFRequestPageState extends State {
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
node: useInCombinationNode,
+ validator: (value) {
+ if ((value ?? "").isEmpty) return "Mandatory";
+ return null;
+ },
labelText: "kindly describe in detail",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
@@ -430,14 +463,51 @@ class _CreateTRAFRequestPageState extends State {
}
void _verifyAndSubmit() async {
+ if (requestType == null) {
+ "Select request type".showToast;
+ return;
+ } else if (requestType?.value == 1 && trafRequest?.assetNDId == null) {
+ "Oracle Code missing".showToast;
+ return;
+ } else if (requestType?.value == 2 && trafRequest?.assetId == null) {
+ "Pick asset".showToast;
+ return;
+ }
+ if (!_formKey.currentState!.validate()) return;
+
trafRequest?.employeeId = context.userProvider.user?.userID;
trafRequest?.siteId = context.userProvider.user?.clientId;
trafRequest?.trafContacts = [];
trafRequest?.trafContacts = userBasedOnSearch.map((item) => TrafContacts(id: 0, trafId: 0, name: item.userName, userId: item.userId)).toList();
+ if ((trafRequest?.trafContacts ?? []).isEmpty) {
+ "Please specify users going to use technology".showToast;
+ return;
+ }
+ if (isUsedSolelyOrShared == null) {
+ "Please specify technology solely or shared".showToast;
+ return;
+ }
+ if (isUsedSolelyOrShared?.value == 1 && (trafRequest?.trafDepartments ?? []).isEmpty) {
+ "Please specify departments and relations".showToast;
+ return;
+ }
+
+ if (otherServicesEffects == null) {
+ "Please specify other services will be effected or not".showToast;
+ return;
+ }
+
+ if (useInCombination == null) {
+ "Please specify equipment used in combination or not".showToast;
+ return;
+ }
+
Utils.showLoading(context);
- await Provider.of(context, listen: false).addTraf(trafRequest!.toJson());
+ bool isSuccess = await Provider.of(context, listen: false).addTraf(trafRequest!.toJson());
Utils.hideLoading(context);
- Navigator.pop(context);
+ if (isSuccess) {
+ Navigator.pop(context);
+ }
}
}
diff --git a/lib/modules/traf_module/traf_request_detail_page.dart b/lib/modules/traf_module/traf_request_detail_page.dart
index 7283bf98..00f25512 100644
--- a/lib/modules/traf_module/traf_request_detail_page.dart
+++ b/lib/modules/traf_module/traf_request_detail_page.dart
@@ -13,7 +13,9 @@ import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
+import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
+import 'asset_analytics_model.dart';
import 'traf_request_model.dart';
class TrafRequestDetailPage extends StatefulWidget {
@@ -51,30 +53,32 @@ class _TrafRequestDetailPageState extends State {
builder: (_, isLoading, __) {
if (isLoading) return const ALoading();
TrafRequestProvider trafProvider = Provider.of(context, listen: false);
- return Column(
- children: [
- ListView(
- padding: const EdgeInsets.all(16),
- children: [
- requesterInformation(trafProvider.trafRequestDataModel!),
- 12.height,
- requestInformation(trafProvider.trafRequestDataModel!),
- 12.height,
- assetInformation(trafProvider.trafRequestDataModel!),
- ],
- ).expanded,
- // // if (isEngineer)
- // FooterActionButton.footerContainer(
- // context: context,
- // child: AppFilledButton(
- // buttonColor: AppColor.primary10,
- // label: "Update",
- // onPressed: () {
- // Navigator.pushNamed(context, UpdateTrafRequestPage.id);
- // }),
- // ),
- ],
- );
+ return trafProvider.trafRequestDataModel == null
+ ? const NoDataFound().center
+ : Column(
+ children: [
+ ListView(
+ padding: const EdgeInsets.all(16),
+ children: [
+ requesterInformation(trafProvider.trafRequestDataModel!),
+ 12.height,
+ requestInformation(trafProvider.trafRequestDataModel!),
+ 12.height,
+ assetInformation(trafProvider.trafRequestDataModel!),
+ ],
+ ).expanded,
+ // // if (isEngineer)
+ // FooterActionButton.footerContainer(
+ // context: context,
+ // child: AppFilledButton(
+ // buttonColor: AppColor.primary10,
+ // label: "Update",
+ // onPressed: () {
+ // Navigator.pushNamed(context, UpdateTrafRequestPage.id);
+ // }),
+ // ),
+ ],
+ );
},
));
}
@@ -90,13 +94,14 @@ class _TrafRequestDetailPageState extends State {
),
8.height,
'${context.translation.employeeId}: ${data.employeeIdForDisplay ?? '-'}'.bodyText(context),
- '${context.translation.name}: ${data.employeeName ?? '-'}'.bodyText(context), // todo ask shaheer
- '${context.translation.email}: ${data.employeeEmail ?? '-'}'.bodyText(context), // todo ask shaheer
- 'Position: ${data.positionName ?? '-'}'.bodyText(context), // todo ask shaheer
+ '${context.translation.name}: ${data.employeeName ?? '-'}'.bodyText(context),
+ '${context.translation.email}: ${data.employeeEmail ?? '-'}'.bodyText(context),
+ 'Position: ${data.positionName ?? '-'}'.bodyText(context),
'${context.translation.site}: ${data.siteName ?? '-'}'.bodyText(context),
- '${context.translation.department}: ${data.departments?.map((item) => item.departmentName).toList() ?? '-'}'.bodyText(context),
- 'Requester Extension: ${data.requesterExtensionName ?? '-'}'.bodyText(context),
- '${context.translation.extensionNo}: ${data.requesterExtensionNumber ?? '-'}'.bodyText(context),
+ '${context.translation.department}: ${data.departmentName}'.bodyText(context),
+ // 'Requester Extension: ${data.requesterExtensionName ?? '-'}'.bodyText(context),
+ 'Number/Contact Information: ${data.requesterContactNumber ?? '-'}'.bodyText(context),
+ 'Extension: ${data.requesterExtensionNumber ?? '-'}'.bodyText(context),
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
@@ -127,10 +132,22 @@ class _TrafRequestDetailPageState extends State {
.bodyText(context),
4.height,
'Is the requesting department going to use the technology solely or shared with other departments?:\n${data.usingSolelyOrSharedName ?? '-'}'.bodyText(context),
+ if ((data.departments ?? []).isNotEmpty) ...[
+ 4.height,
+ 'Technology used with other departments:\n${data.departments?.map((item) => item.departmentName).toList() ?? '-'}'.bodyText(context),
+ ],
4.height,
- 'Would other services be effected by acquiring the new equipment?:\n${data.effectedServices ?? '-'}'.bodyText(context),
+ 'Would other services be effected by acquiring the new equipment?:\n${data.isEffectedName ?? '-'}'.bodyText(context),
+ if ((data.effectedServices ?? "").isNotEmpty) ...[
+ 4.height,
+ 'List of services would it be effected:\n${data.effectedServices ?? '-'}'.bodyText(context),
+ ],
4.height,
- 'Is the equipment going to be used with combination of other equipment to accomplish a specific procedure?:\n${data.usedWithCombination ?? '-'}'.bodyText(context),
+ 'Is the equipment going to be used with combination of other equipment to accomplish a specific procedure?:\n${data.isCombinationName ?? '-'}'.bodyText(context),
+ if ((data.usedWithCombination ?? "").isNotEmpty) ...[
+ 4.height,
+ 'Equipment going to be used with combination of other equipments:\n${data.usedWithCombination ?? '-'}'.bodyText(context),
+ ],
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
@@ -149,16 +166,29 @@ class _TrafRequestDetailPageState extends State {
'${context.translation.model}: ${data.modelName ?? '-'}'.bodyText(context),
'${context.translation.manufacture}: ${data.manufacturerName ?? '-'}'.bodyText(context),
if (data.requestTypeId == 733) ...[
- 'Last price & PO: ${data.poNumber ?? '-'}'.bodyText(context),
- 'The quantity of the same asset: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Existing asset under SLA: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Age of the asset: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Total Maintenance Cost (TMC): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Net Book Value (NBV): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Mean Time Between Failure (MTBF): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Down Time (DT): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Up Time (UT): ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
- 'Purchased Price: ${data.qty ?? '-'}'.bodyText(context), // todo check with shaheer
+ FutureBuilder(
+ future: Provider.of(context, listen: false).getAssetAnalytics(data.assetId!),
+ builder: (cxt, snapshot) {
+ if (snapshot.connectionState == ConnectionState.waiting) {
+ return const SizedBox.square(dimension: 24, child: CircularProgressIndicator()).center;
+ }
+ if (snapshot.hasData) {
+ return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
+ 'Last price: ${snapshot.data?.lastPrice ?? '-'}'.bodyText(context),
+ 'PO: ${snapshot.data?.lastPONo ?? '-'}'.bodyText(context),
+ 'The quantity of the same asset: ${snapshot.data?.sameAssetQuantity ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Existing asset under SLA: ${snapshot.data?.slaStatus ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Age of the asset: ${snapshot.data?.assetAgeDescription ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Total Maintenance Cost (TMC): ${snapshot.data?.totalMaintenanceCost ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Net Book Value (NBV): ${snapshot.data?.netBookValue ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Mean Time Between Failure (MTBF): ${snapshot.data?.mtbfDescription ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Down Time (DT): ${snapshot.data?.downTimeDescription ?? '-'}'.bodyText(context), // todo check with shaheer
+ 'Up Time (UT): ${snapshot.data?.upTimeDescription ?? '-'}'.bodyText(context),
+ 'Purchased Price: ${snapshot.data?.purchasedPrice ?? '-'}'.bodyText(context),
+ ]);
+ }
+ return const SizedBox();
+ })
],
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
diff --git a/lib/modules/traf_module/traf_request_model.dart b/lib/modules/traf_module/traf_request_model.dart
index b5de3280..af3977be 100644
--- a/lib/modules/traf_module/traf_request_model.dart
+++ b/lib/modules/traf_module/traf_request_model.dart
@@ -51,12 +51,15 @@ class TrafRequestDataModel {
String? employeeEmail;
int? positionId;
String? positionName;
+ String? departmentId;
+ String? departmentName;
List? departments;
List? trafDepartments;
int? siteId;
String? siteName;
String? requesterExtensionNumber;
String? requesterExtensionName;
+ String? requesterContactNumber;
int? requesterExtensionPositionId;
String? requesterExtensionPositionName;
int? requestTypeId;
@@ -74,10 +77,10 @@ class TrafRequestDataModel {
int? qty;
String? purposeAnswer;
String? currentPractise;
- int? censusQ1;
- int? censusQ2;
- int? censusQ3;
- int? censusQ4;
+ String? censusQ1;
+ String? censusQ2;
+ String? censusQ3;
+ String? censusQ4;
List? trafContacts;
int? usingSolelyOrSharedId;
String? usingSolelyOrSharedName;
@@ -124,7 +127,7 @@ class TrafRequestDataModel {
String? approvalDocDate;
String? isAssigned;
String? poNumber;
- int? apiDirectorId;
+ String? apiDirectorId;
String? apiDirectorName;
int? apiDirectorApprovalId;
String? apiDirectorApprovalName;
@@ -146,12 +149,15 @@ class TrafRequestDataModel {
this.employeeEmail,
this.positionId,
this.positionName,
+ this.departmentId,
+ this.departmentName,
this.departments,
this.trafDepartments,
this.siteId,
this.siteName,
this.requesterExtensionNumber,
this.requesterExtensionName,
+ this.requesterContactNumber,
this.requesterExtensionPositionId,
this.requesterExtensionPositionName,
this.requestTypeId,
@@ -241,6 +247,8 @@ class TrafRequestDataModel {
employeeEmail = json['employeeEmail'];
positionId = json['positionId'];
positionName = json['positionName'];
+ departmentId = json['departmentId'];
+ departmentName = json['departmentName'];
if (json['departments'] != null) {
departments = [];
json['departments'].forEach((v) {
@@ -257,6 +265,7 @@ class TrafRequestDataModel {
siteName = json['siteName'];
requesterExtensionNumber = json['requesterExtensionNumber'];
requesterExtensionName = json['requesterExtensionName'];
+ requesterContactNumber = json['requesterContactNumber'];
requesterExtensionPositionId = json['requesterExtensionPositionId'];
requesterExtensionPositionName = json['requesterExtensionPositionName'];
requestTypeId = json['requestTypeId'];
@@ -363,6 +372,8 @@ class TrafRequestDataModel {
data['employeeEmail'] = this.employeeEmail;
data['positionId'] = this.positionId;
data['positionName'] = this.positionName;
+ data['departmentId'] = this.departmentId;
+ data['departmentName'] = this.departmentName;
if (this.departments != null) {
data['departments'] = this.departments!.map((v) => v.toJson()).toList();
}
@@ -373,6 +384,7 @@ class TrafRequestDataModel {
data['siteName'] = this.siteName;
data['requesterExtensionNumber'] = this.requesterExtensionNumber;
data['requesterExtensionName'] = this.requesterExtensionName;
+ data['requesterContactNumber'] = this.requesterContactNumber;
data['requesterExtensionPositionId'] = this.requesterExtensionPositionId;
data['requesterExtensionPositionName'] = this.requesterExtensionPositionName;
data['requestTypeId'] = this.requestTypeId;
diff --git a/lib/modules/traf_module/traf_request_provider.dart b/lib/modules/traf_module/traf_request_provider.dart
index 1f1dd385..346f7351 100644
--- a/lib/modules/traf_module/traf_request_provider.dart
+++ b/lib/modules/traf_module/traf_request_provider.dart
@@ -5,6 +5,7 @@ import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
+import 'asset_analytics_model.dart';
import 'traf_request_model.dart';
class TrafRequestProvider extends ChangeNotifier {
@@ -12,25 +13,21 @@ class TrafRequestProvider extends ChangeNotifier {
TrafRequestDataModel? trafRequestDataModel;
- Future addTraf(Map body) async {
+ Future addTraf(Map body) async {
try {
- isLoading = true;
- notifyListeners();
Response response = await ApiManager.instance.post(URLs.addTRAF, body: body);
if (response.statusCode >= 200 && response.statusCode < 300) {
// trafRequestDataModel = TrafRequestDataModel.fromJson(json.decode(response.body)["data"]);
+ return true;
}
- isLoading = false;
- notifyListeners();
- return 0;
+ return false;
} catch (error) {
- isLoading = false;
- notifyListeners();
- return -1;
+ return false;
}
}
Future getTRAFById(int trafId) async {
+ trafRequestDataModel = null;
try {
isLoading = true;
notifyListeners();
@@ -47,4 +44,16 @@ class TrafRequestProvider extends ChangeNotifier {
return -1;
}
}
+
+ Future 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;
+ }
}
diff --git a/lib/modules/traf_module/users_auto_complete_field.dart b/lib/modules/traf_module/users_auto_complete_field.dart
index 12060844..c5d04db7 100644
--- a/lib/modules/traf_module/users_auto_complete_field.dart
+++ b/lib/modules/traf_module/users_auto_complete_field.dart
@@ -81,13 +81,13 @@ class _UsersAutoCompleteFieldState extends State {
loading = true;
});
}
- List workOrders = (await _TechnologyUsersProvider.getUsersBasedOnSearch(textEditingValue.text));
+ List workOrders = (await _TechnologyUsersProvider.getUsersBasedOnSearch(context.userProvider.user!.clientId!, textEditingValue.text));
setState(() {
loading = false;
});
return workOrders;
},
- displayStringForOption: (UsersBasedOnSearchModel option) => widget.byName ? option.userName ?? "" : option.employeeId ?? "",
+ displayStringForOption: (UsersBasedOnSearchModel option) => widget.byName ? "${option.userName ?? "-"} (Nurse)" ?? "" : option.employeeId ?? "",
fieldViewBuilder: (BuildContext context, TextEditingController fieldTextEditingController, FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) {
return TextField(
controller: _controller,
diff --git a/lib/new_views/app_style/app_color.dart b/lib/new_views/app_style/app_color.dart
index 7b7df7d4..f8c42ce9 100644
--- a/lib/new_views/app_style/app_color.dart
+++ b/lib/new_views/app_style/app_color.dart
@@ -264,6 +264,11 @@ class AppColor {
return green15;
case 370:
return green15;
+ case 0:
+ return green15;
+ case 1:
+ //high priority
+ return white10;
case 82:
//high priority
return white10;
@@ -279,9 +284,13 @@ class AppColor {
return greenStatus(context);
case 370:
return greenStatus(context);
+ case 0:
+ return greenStatus(context);
//high priority
case 82:
return redStatus(context);
+ case 1:
+ return redStatus(context);
default:
return blueStatus(context);
}
diff --git a/lib/new_views/common_widgets/app_filled_button.dart b/lib/new_views/common_widgets/app_filled_button.dart
index 8e1e67f2..f543615a 100644
--- a/lib/new_views/common_widgets/app_filled_button.dart
+++ b/lib/new_views/common_widgets/app_filled_button.dart
@@ -50,8 +50,8 @@ class AppFilledButton extends StatelessWidget {
),
child: loading
? SizedBox(
- width: 24,
- height: 24,
+ width: 24.toScreenHeight,
+ height: 24.toScreenHeight,
child: CircularProgressIndicator(
color: textColor ?? AppColor.background(context),
strokeWidth: 2,
diff --git a/lib/new_views/common_widgets/multiple_item_drop_down_menu.dart b/lib/new_views/common_widgets/multiple_item_drop_down_menu.dart
index d0df92fa..9adf0b97 100644
--- a/lib/new_views/common_widgets/multiple_item_drop_down_menu.dart
+++ b/lib/new_views/common_widgets/multiple_item_drop_down_menu.dart
@@ -210,7 +210,7 @@ class _MultipleItemDropDownMenuState {
types["System Internal Audit".addTranslation] = 11;
}
- if (context.settingProvider.isUserFlowMedical) {
+ if (context.settingProvider.isUserFlowMedical && isEngineer) {
types['Recall and Alert'] = 7;
}
@@ -125,6 +126,7 @@ class _AllRequestsFilterPageState extends State {
body: Column(
children: [
SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
@@ -208,11 +210,11 @@ class _AllRequestsFilterPageState extends State {
// setState(() {});
// }),
],
- ).paddingOnly(start: 16, end: 16),
+ ),
).expanded,
- AppFilledButton(onPressed: _search, label: context.translation.applyFilter).paddingOnly(start: 16, end: 16),
+ FooterActionButton.footerContainer(context: context, child: AppFilledButton(onPressed: _search, label: context.translation.applyFilter))
],
- ).paddingOnly(top: 16, bottom: 16),
+ ),
);
}
diff --git a/lib/new_views/pages/land_page/my_request/all_requests_search_page.dart b/lib/new_views/pages/land_page/my_request/all_requests_search_page.dart
index 35b5210b..bde4ba6f 100644
--- a/lib/new_views/pages/land_page/my_request/all_requests_search_page.dart
+++ b/lib/new_views/pages/land_page/my_request/all_requests_search_page.dart
@@ -7,6 +7,7 @@ import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
+import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
@@ -90,6 +91,7 @@ class _AllRequestsSearchPageState extends State {
child: Column(
children: [
SingleChildScrollView(
+ padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -124,9 +126,9 @@ class _AllRequestsSearchPageState extends State {
],
),
).expanded,
- AppFilledButton(onPressed: _search, label: context.translation.search),
+ FooterActionButton.footerContainer(context: context, child: AppFilledButton(onPressed: _search, label: context.translation.search)),
],
- ).paddingAll(16),
+ ),
),
);
}
diff --git a/lib/new_views/pages/land_page/my_request/my_requests_page.dart b/lib/new_views/pages/land_page/my_request/my_requests_page.dart
index edc4e526..06d1fb23 100644
--- a/lib/new_views/pages/land_page/my_request/my_requests_page.dart
+++ b/lib/new_views/pages/land_page/my_request/my_requests_page.dart
@@ -5,10 +5,12 @@ import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/all_requests_provider.dart';
+import 'package:test_sa/controllers/providers/api/device_transfer_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
+import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/user_types.dart';
@@ -51,9 +53,12 @@ class _MyRequestsPageState extends State {
//TODO unCommit this to enable task
requestsList.add(Request(6, context.translation.taskRequest));
//after confirm name add this to translation...
- if (context.settingProvider.isUserFlowMedical) {
+ if (context.settingProvider.isUserFlowMedical && Provider.of(context, listen: false).user!.type != UsersTypes.normal_user) {
requestsList.add(Request(7, 'Recall and Alert'));
}
+ if (Provider.of(context, listen: false).user!.type != UsersTypes.normal_user) {
+ requestsList.add(Request(8, 'Inventory Session'.addTranslation));
+ }
if (context.userProvider.user!.type == UsersTypes.normal_user) {
requestsList.add(Request(9, 'TRAF'));
}
diff --git a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart
index 97e9bf58..750abfd7 100644
--- a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart
+++ b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart
@@ -3,6 +3,7 @@ import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/models/new_models/dashboard_detail.dart';
import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart';
import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart';
+import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/modules/traf_module/traf_request_item_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
@@ -48,54 +49,35 @@ class RequestPaginatedListview extends StatelessWidget {
}
Widget _buildRequestItem(Data request) {
- //TODO need to replace with switch statement
- bool isServiceRequest = request.transactionNo == 1;
- bool isGasRefill = request.transactionNo == 2;
- bool isAssetTransfer = request.transactionNo == 3;
- bool isPPMs = request.transactionNo == 4;
- bool isRecurrentTask = request.transactionNo == 5;
- bool isTask = request.transactionNo == 6;
- bool isTRAF = request.transactionNo == 9;
- bool isEquipmentInternalAudit = request.transactionNo == 10;
- bool isSystemInternalAudit = request.transactionNo == 11;
-
- if (isServiceRequest) {
- return ServiceRequestItemView(requestData: request, refreshData: false);
- } else if (isGasRefill) {
- return GasRefillItemView(requestData: request);
- } else if (isPPMs) {
- return PpmItemView(requestData: request);
- } else if (isAssetTransfer) {
- return DeviceItemView(requestData: request);
- } else if (isRecurrentTask) {
- return RecurrentWoItemView(requestData: request);
- } else if (isTask) {
- return TaskRequestItemView(requestData: request);
- } else if (isTRAF) {
- return TrafRequestItemView(requestData: request);
- } else if (isEquipmentInternalAudit) {
- return EquipmentInternalAuditItemView(requestData: request);
- } else if (isSystemInternalAudit) {
- return SystemInternalAuditItemView(requestData: request);
- } else {
- return Container(
- height: 100,
- width: double.infinity,
- color: Colors.grey,
- );
+ switch (request.transactionNo) {
+ case 1:
+ return ServiceRequestItemView(requestData: request);
+ case 2:
+ return GasRefillItemView(requestData: request);
+ case 3:
+ return DeviceItemView(requestData: request);
+ case 4:
+ return PpmItemView(requestData: request);
+ case 5:
+ return RecurrentWoItemView(requestData: request);
+ case 6:
+ return TaskRequestItemView(requestData: request);
+ case 7:
+ return TaskRequestItemView(requestData: request);
+ case 8:
+ return InventorySessionItemView(requestData: request);
+ case 9:
+ return TrafRequestItemView(requestData: request);
+ case 10:
+ return EquipmentInternalAuditItemView(requestData: request);
+ case 11:
+ return SystemInternalAuditItemView(requestData: request);
+ default:
+ return Container(
+ height: 100,
+ width: double.infinity,
+ color: Colors.grey,
+ );
}
}
}
-
-// return Column(
-// mainAxisSize: MainAxisSize.min,
-// children: List.generate(isLoading ? 6 : list.length, (index) {
-// // if (isLoading) {
-// // return const SizedBox().toRequestShimmer(context, isLoading);
-// // }
-// // else {
-// return Padding(
-// padding: EdgeInsets.symmetric(vertical: 10.toScreenHeight),
-// child: _buildRequestItem(list[index]));
-// // }
-// }));
diff --git a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart
index 54639c40..b8d1f6eb 100644
--- a/lib/new_views/pages/land_page/widgets/request_item_view_list.dart
+++ b/lib/new_views/pages/land_page/widgets/request_item_view_list.dart
@@ -8,6 +8,7 @@ import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/all_requests_and_count_model.dart';
import 'package:test_sa/modules/internal_audit_module/pages/equipment_internal_audit/equipment_internal_audit_item_view.dart';
import 'package:test_sa/modules/internal_audit_module/pages/system_internal_audit/system_internal_audit_item_view.dart';
+import 'package:test_sa/modules/asset_inventory_module/pages/inventory_session_item_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/task_request_item_view.dart';
import 'package:test_sa/modules/traf_module/traf_request_item_view.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
@@ -58,6 +59,8 @@ class RequestItemViewList extends StatelessWidget {
return TaskRequestItemView(requestDetails: list[index]);
case 7:
return TaskRequestItemView(requestDetails: list[index]);
+ case 8:
+ return InventorySessionItemView(requestDetails: list[index]);
case 9:
return TrafRequestItemView(requestDetails: list[index]);
//Need to verify the type No..
diff --git a/lib/new_views/pages/login_page.dart b/lib/new_views/pages/login_page.dart
index 35eb9134..8c54e927 100644
--- a/lib/new_views/pages/login_page.dart
+++ b/lib/new_views/pages/login_page.dart
@@ -110,8 +110,9 @@ class _LoginPageState extends State {
backgroundColor: AppColor.fieldBgColor(context),
validator: (value) => Validator.hasValue(value!) ? null : context.translation.requiredField,
labelText: context.translation.username,
- style: TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
- labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: 11, color: context.isDark ? Colors.white : const Color(0xff767676)),
+ style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
+ floatingLabelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
+ labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff767676)),
textInputType: TextInputType.text,
showWithoutDecoration: true,
contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 12.toScreenHeight),
@@ -125,8 +126,9 @@ class _LoginPageState extends State {
showWithoutDecoration: true,
labelText: context.translation.password,
backgroundColor: AppColor.fieldBgColor(context),
- style: TextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
- labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: 11, color: context.isDark ? Colors.white : const Color(0xff767676)),
+ style: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
+ labelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff767676)),
+ floatingLabelStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: context.isTablet() ? 16 : 12, color: context.isDark ? Colors.white : const Color(0xff3B3D4A)),
contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 12.toScreenHeight),
obscureText: !_passwordVisible,
suffixIcon: Icon(
diff --git a/lib/views/pages/user/profile_page.dart b/lib/views/pages/user/profile_page.dart
index 22082ca1..9af6bb61 100644
--- a/lib/views/pages/user/profile_page.dart
+++ b/lib/views/pages/user/profile_page.dart
@@ -175,7 +175,7 @@ class _ProfilePageState extends State {
16.height,
AppFilledButton(
label: "Update Information",
- buttonColor: context.isDark? AppColor.primary10:AppColor.neutral50,
+ buttonColor: context.isDark ? AppColor.primary10 : AppColor.neutral50,
onPressed: () {
context.showBottomSheet(
UpdateUserContactInfoBottomSheet(
diff --git a/lib/views/widgets/equipment/asset_picker.dart b/lib/views/widgets/equipment/asset_picker.dart
index a9d8e5f0..b5f029d5 100644
--- a/lib/views/widgets/equipment/asset_picker.dart
+++ b/lib/views/widgets/equipment/asset_picker.dart
@@ -17,11 +17,16 @@ class AssetPicker extends StatelessWidget {
final List deviceList;
final bool editable;
final bool showAssetInfo;
+ final bool showBorder;
final Color? borderColor;
final Color? buttonColor;
+ final Color? iconColor;
+ final Color? labelColor;
+ final String? label;
Color? backgroundColor;
final bool forPPM;
final bool showLoading;
+ final bool enablePickManually;
final bool multiSelection;
AssetPicker(
@@ -34,10 +39,14 @@ class AssetPicker extends StatelessWidget {
this.onAssetRemove,
this.borderColor,
this.buttonColor,
+ this.label,
+ this.iconColor,
+ this.labelColor,
this.backgroundColor,
this.showAssetInfo = true,
+ this.showBorder = false,
this.multiSelection = false,
- this.forPPM = false,
+ this.forPPM = false, this.enablePickManually = true,
this.showLoading = false})
: assert(
multiSelection == false || onMultiAssetPick != null,
@@ -57,15 +66,16 @@ class AssetPicker extends StatelessWidget {
decoration: BoxDecoration(
color: buttonColor ?? backgroundColor ?? AppColor.blueStatus(context),
borderRadius: BorderRadius.circular(10),
+ border: showBorder?Border.all(color: borderColor ?? AppColor.blueStatus(context), width: 2):null,
// boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14)],
),
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
- "scan_asset".toSvgAsset(height: 22, fit: BoxFit.fitHeight, color: context.isDark ? AppColor.neutral20 : Colors.white),
+ "scan_asset".toSvgAsset(height: 22, fit: BoxFit.fitHeight, color: context.isDark ? AppColor.neutral20 :iconColor?? Colors.white),
8.width,
- "Scan or Pick Asset".bodyText(context).custom(color: context.isDark ? AppColor.neutral20 : Colors.white),
+ ' ${label??"Scan or Pick Asset"}'.bodyText(context).custom(color: context.isDark ? AppColor.neutral20 : labelColor?? Colors.white),
],
),
).onPress(() async {
@@ -74,6 +84,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr(
title: context.translation.assetScan,
multiSelection: multiSelection,
+ enablePickManually: enablePickManually,
))) as List?;
if (device?.isNotEmpty ?? false) {
onMultiAssetPick!(device!);
@@ -83,6 +94,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr(
title: context.translation.assetScan,
multiSelection: multiSelection,
+ enablePickManually: enablePickManually,
))) as Asset?;
if (device != null) {
onPick!(device);
@@ -112,6 +124,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr(
title: context.translation.assetScan,
multiSelection: multiSelection,
+ enablePickManually: enablePickManually,
))) as List?;
if (device?.isNotEmpty ?? false) {
onMultiAssetPick!(device!);
@@ -121,6 +134,7 @@ class AssetPicker extends StatelessWidget {
builder: (context) => AssetScanQr(
title: context.translation.assetScan,
multiSelection: multiSelection,
+ enablePickManually: enablePickManually,
))) as Asset?;
if (device != null) {
onPick!(device);
@@ -131,7 +145,7 @@ class AssetPicker extends StatelessWidget {
if (deviceList.isNotEmpty && showAssetInfo)
ListView.separated(
shrinkWrap: true,
- padding: EdgeInsets.only(top: 16),
+ padding: const EdgeInsets.only(top: 16),
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (cxt, index) => _assetInfoView(deviceList[index], context),
separatorBuilder: (cxt, index) => 12.height,
@@ -195,10 +209,10 @@ class AssetPicker extends StatelessWidget {
],
),
8.height,
- "${context.translation.assetNo}: ${device!.assetNumber}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
+ "${context.translation.assetNo}: ${device.assetNumber}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
2.height,
// "${context.translation.manufacture}: ${device.modelDefinition?.manufacturerName}".bodyText(context),
- "${context.translation.model}: ${device!.modelDefinition?.modelName}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
+ "${context.translation.model}: ${device.modelDefinition?.modelName}".bodyText2(context).toShimmer(isShow: showLoading,context: context),
// "${context.translation.serialNumber}: ${device.assetNumber}".bodyText(context),
// const Divider().defaultStyle(context),
// "${context.translation.department}: ${device.department?.departmentName}".bodyText(context),
diff --git a/lib/views/widgets/qr/asset_scan_qr.dart b/lib/views/widgets/qr/asset_scan_qr.dart
index 16b76dbd..c39483a6 100644
--- a/lib/views/widgets/qr/asset_scan_qr.dart
+++ b/lib/views/widgets/qr/asset_scan_qr.dart
@@ -20,9 +20,10 @@ import '../../pages/device_transfer/search_device_page.dart';
class AssetScanQr extends StatefulWidget {
static const String id = "/asset-scan-qr";
- const AssetScanQr({Key? key, required this.title, this.multiSelection = false}) : super(key: key);
+ const AssetScanQr({Key? key, required this.title, this.multiSelection = false,this.enablePickManually = true}) : super(key: key);
final String title;
final bool multiSelection;
+ final bool enablePickManually;
@override
_AssetScanQrState createState() => _AssetScanQrState();
@@ -86,15 +87,23 @@ class _AssetScanQrState extends State {
controller.scannedDataStream.listen((scanData) async {
if (!_scanDone) {
_scanDone = true;
- final result = await _getDevice(scanData.code!, isQr: true);
- if (result.isNotEmpty) {
- if (widget.multiSelection) {
- Navigator.of(context).pop([result[0]]);
+ if(!widget.enablePickManually){
+ if(scanData.code!=null){
+ Navigator.of(context).pop(Asset(assetNumber: scanData.code!));
+ }else{
+ _scanDone = false;
+ }
+ }else{
+ final result = await _getDevice(scanData.code!, isQr: true);
+ if (result.isNotEmpty) {
+ if (widget.multiSelection) {
+ Navigator.of(context).pop([result[0]]);
+ } else {
+ Navigator.of(context).pop(result[0]);
+ }
} else {
- Navigator.of(context).pop(result[0]);
+ _scanDone = false;
}
- } else {
- _scanDone = false;
}
}
});
@@ -109,7 +118,8 @@ class _AssetScanQrState extends State {
),
],
).expanded,
- FooterActionButton.footerContainer(
+ if(widget.enablePickManually)
+ FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
label: context.translation.pickManually,
diff --git a/lib/views/widgets/requests/request_status.dart b/lib/views/widgets/requests/request_status.dart
index b304eb51..272ddf42 100644
--- a/lib/views/widgets/requests/request_status.dart
+++ b/lib/views/widgets/requests/request_status.dart
@@ -11,23 +11,23 @@ class StatusLabel extends StatelessWidget {
final double radius;
final bool labelInCenter;
- StatusLabel({Key? key, this.id = 0, this.label, this.backgroundColor, this.textColor, this.isPriority = false, this.radius = 4,this.labelInCenter=false}) : super(key: key);
+ StatusLabel({Key? key, this.id = 0, this.label, this.backgroundColor, this.textColor, this.isPriority = false, this.radius = 4, this.labelInCenter = false}) : super(key: key);
@override
Widget build(BuildContext context) {
- if (id == 82) label = context.translation.highPriority;
- if (id == 81) label = context.translation.lowPriority;
if (label?.toLowerCase() == 'In progress'.toLowerCase()) label = context.translation.inProgress;
if (label?.toLowerCase() == 'Completed'.toLowerCase()) label = context.translation.completed;
if (label?.toLowerCase() == 'Open'.toLowerCase()) label = context.translation.open;
if (label?.toLowerCase() == 'Closed'.toLowerCase()) label = context.translation.closed;
if (label?.toLowerCase() == 'Low'.toLowerCase()) label = context.translation.lowPriority;
+ if (label?.toLowerCase() == 'No'.toLowerCase()) label = context.translation.lowPriority;
if (label?.toLowerCase() == 'High'.toLowerCase()) label = context.translation.highPriority;
+ if (label?.toLowerCase() == 'Yes'.toLowerCase()) label = context.translation.highPriority;
if (label?.toLowerCase() == 'Waiting for quotation'.toLowerCase()) label = context.translation.waitingForQuotation;
return Container(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 10),
- alignment: labelInCenter ? Alignment.center: null,
+ alignment: labelInCenter ? Alignment.center : null,
decoration: ShapeDecoration(
color: backgroundColor,
shape: RoundedRectangleBorder(
diff --git a/pubspec.lock b/pubspec.lock
index fdc4903d..902236f8 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1570,6 +1570,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index a7cf4381..e7584098 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
-version: 1.3.10+29
+version: 1.3.11+30
environment:
sdk: ">=3.5.0 <4.0.0"
@@ -95,6 +95,7 @@ dependencies:
safe_device: ^1.2.1
toggle_switch: ^2.3.0
clipboard: ^2.0.2
+ tree_view_flutter: ^1.0.2
local_auth_darwin: any
dev_dependencies: