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

# Conflicts:
#	lib/controllers/api_routes/urls.dart
#	lib/controllers/providers/api/all_requests_provider.dart
#	lib/dashboard_latest/widgets/request_category_list.dart
#	lib/models/new_models/dashboard_detail.dart
#	lib/new_views/pages/land_page/my_request/my_requests_page.dart
#	lib/new_views/pages/land_page/requests/request_paginated_listview.dart
#	lib/new_views/pages/land_page/widgets/request_item_view_list.dart
design_3.0_GlobalHealth
Sikander Saleem 5 days ago
commit facf80b07e

@ -232,6 +232,14 @@ class URLs {
static get getServiceReportReasonsNew => "$_baseUrl/Lookups/GetLookupReasonNew?lookupEnum=505";
static get getTrafRequestTypeLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=416";
static get getYesNoRequestTypeLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=4";
static get getClassificationTypeLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=450";
static get getRecommendationTypeLookup => "$_baseUrl/Lookups/GetLookup?lookupEnum=451";
static get getWoFrames => "$_baseUrl/Lookups/GetLookup?lookupEnum=1254";
static get getServiceReportRetirementType => "$_baseUrl/Lookups/GetLookup?lookupEnum=415";
@ -253,6 +261,11 @@ class URLs {
static get getCallRequestForWorkOrder => "$_baseUrl/CallRequest/GetCallRequestForWorkOrder"; // get
static get attachmentBaseUrl => "https://atomsmdev.hmg.com/v2/mobile/Files/DownloadFile?fileName=";
//Traf
static get addTRAF => "$_baseUrl/TRAF/AddTRAF"; // get
static get getTRAFById => "$_baseUrl/TRAF/GetTRAFById"; // get
static get getAssetNDAutoCompleteByDynamicCodes => "$_baseUrl/AssetNameDefinition/GetAssetNDAutoCompleteByDynamicCodes"; // get// get
//gas refill
static get getGasTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=606"; // get
// todo check edits with backend
@ -287,6 +300,7 @@ class URLs {
static get getTaskEvaluatorUser => "$_baseUrl/Account/GetUserByRoleValue?value=R-2"; // get
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
// pentry
static get getPentry => "$_baseUrl/return/pentry/details"; // get
@ -324,4 +338,5 @@ class URLs {
static get getAssetsTemp => '$_baseUrl/AssetInventory/GetAssetsTemp';
static get convertDetailToComplete => '$_baseUrl/AssetInventory/ConvertDetailToComplete';
static get getDepartmentBasedOnSite => "$_baseUrl/TRAFDataSource/GetDepartmentBasedOnSite"; // add
}

@ -134,18 +134,27 @@ class AllRequestsProvider extends ChangeNotifier {
List<int> getStatues(BuildContext context) {
List<int> list = [1, 2, 3, 4];
if (context.userProvider.user!.type != UsersTypes.normal_user) {
if (context.userProvider.isAssessor) {
list = [9];
return list;
}
if (!context.userProvider.isNurse) {
list.add(5);
}
list.add(6); // task module
if (context.settingProvider.isUserFlowMedical && context.userProvider.user!.type != UsersTypes.normal_user) {
if (context.settingProvider.isUserFlowMedical && !context.userProvider.isNurse) {
list.add(7); // task mod
}
if (context.userProvider.user!.type != UsersTypes.normal_user) {
if (!context.userProvider.isNurse) {
list.add(8); //
}
if (context.userProvider.isNurse) {
list.add(9); //
}
return list;
}

@ -0,0 +1,120 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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/models/new_models/asset_nd_auto_complete_by_dynamic_codes_model.dart';
import 'package:test_sa/models/service_request/spare_parts.dart';
class OracleCodeProvider extends ChangeNotifier {
// number of items call in each request
final pageItemNumber = 20;
//reset provider data
void reset() {
_parts = null;
_stateCode = null;
}
// state code of current request to defied error message
// like 400 customer request failed
// 500 service not available
int? _stateCode;
int? get stateCode => _stateCode;
// true if there is next pagein product list and false if not
bool _nextPage = true;
bool get nextPage => _nextPage;
// contain user data
// when user not login or register _user = null
List<SparePartsWorkOrders>? _parts;
List<SparePartsWorkOrders>? get parts => _parts;
// when categories in-process _loading = true
// done _loading = true
// failed _loading = false
bool _loading = false;
bool get isLoading => _loading;
set isLoading(bool isLoading) {
_loading = isLoading;
notifyListeners();
}
/// return -2 if request in progress
/// return -1 if error happen when sending request
/// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
// Future<int> getParts({String? title}) async {
// if (_loading == true) return -2;
// _loading = true;
// notifyListeners();
// late Response response;
// try {
// response = await ApiManager.instance.post(URLs.getPartNumber, body: {if (title != null && title.isNotEmpty) "partName": title});
// _stateCode = response.statusCode;
// if (response.statusCode >= 200 && response.statusCode < 300) {
// // client's request was successfully received
// List categoriesListJson = json.decode(utf8.decode(response.bodyBytes));
// List<SparePart> page = categoriesListJson.map((part) => SparePart.fromJson(part)).toList();
// _parts ??= [];
// _parts!.addAll(page.map((e) => SparePartsWorkOrders(sparePart: e)).toList());
// _nextPage = page.length >= pageItemNumber;
// }
// _loading = false;
// notifyListeners();
// return response.statusCode;
// } catch (error) {
// _loading = false;
// _stateCode = -1;
// notifyListeners();
// return -1;
// }
// }
/// return -2 if request in progress
/// return -1 if error happen when sending request
/// return state code if request complete may be 200, 404 or 403
/// for more details check http state manager
/// lib\controllers\http_status_manger\http_status_manger.dart
Future<List<AssetNDAutoCompleteByDynamicCodesModel>> getAssetByOracleCode(String oracleCode) async {
late Response response;
try {
response = await ApiManager.instance.post(URLs.getAssetNDAutoCompleteByDynamicCodes, body: {"codeValue": oracleCode});
List<AssetNDAutoCompleteByDynamicCodesModel> page = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(response.body)["data"];
page = categoriesListJson.map((part) => AssetNDAutoCompleteByDynamicCodesModel.fromJson(part)).toList();
}
return page;
} catch (error) {
return [];
}
}
// // Implement this only for spare part request for now show and search on display name ....
//
// Future<List<SparePart>> getPartsListByDisplayName({num? assetId, String? displayName}) async {
// late Response response;
// try {
// response = await ApiManager.instance.post(URLs.getPartNumber, body: {"displayName": displayName, });
// List<SparePart> page = [];
// if (response.statusCode >= 200 && response.statusCode < 300) {
// // client's request was successfully received
// List categoriesListJson = json.decode(response.body)["data"];
// page = categoriesListJson.map((part) => SparePart.fromJson(part,true)).toList();
// }
// return page;
// } catch (error) {
// return [];
// }
// }
}

@ -0,0 +1,64 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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/models/new_models/asset_nd_auto_complete_by_dynamic_codes_model.dart';
import 'package:test_sa/models/new_models/users_based_on_search_model.dart';
import 'package:test_sa/models/service_request/spare_parts.dart';
class UserSearchProvider extends ChangeNotifier {
// number of items call in each request
final pageItemNumber = 20;
//reset provider data
void reset() {
_parts = null;
_stateCode = null;
}
// state code of current request to defied error message
// like 400 customer request failed
// 500 service not available
int? _stateCode;
int? get stateCode => _stateCode;
// true if there is next pagein product list and false if not
bool _nextPage = true;
bool get nextPage => _nextPage;
// contain user data
// when user not login or register _user = null
List<SparePartsWorkOrders>? _parts;
List<SparePartsWorkOrders>? get parts => _parts;
bool _loading = false;
bool get isLoading => _loading;
set isLoading(bool isLoading) {
_loading = isLoading;
notifyListeners();
}
Future<List<UsersBasedOnSearchModel>> getUsersBasedOnSearch(String query) async {
late Response response;
try {
response = await ApiManager.instance.get(URLs.getUsersBasedOnSearch + "?searchText=$query");
List<UsersBasedOnSearchModel> page = [];
if (response.statusCode >= 200 && response.statusCode < 300) {
// client's request was successfully received
List categoriesListJson = json.decode(response.body);
page = categoriesListJson.map((part) => UsersBasedOnSearchModel.fromJson(part)).toList();
}
return page;
} catch (error) {
return [];
}
}
}

@ -8,6 +8,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 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/new_models/general_response_model.dart';
import 'package:test_sa/models/new_models/update_password.dart';
import 'package:test_sa/models/new_models/verify_otp_model.dart';
@ -39,6 +40,12 @@ class UserProvider extends ChangeNotifier {
File? profileImage;
bool get isEngineer => user!.type == UsersTypes.engineer;
bool get isNurse => user!.type == UsersTypes.normal_user;
bool get isAssessor => user!.type == UsersTypes.assessor || user!.type == UsersTypes.assessorTl;
VerifyOtpModel _verifyOtpModel = VerifyOtpModel();
SwipeTransaction _swipeTransactionModel = SwipeTransaction();
List<SwipeHistory> _swipeHistory = [];

@ -106,7 +106,7 @@ class DashBoardProvider extends ChangeNotifier {
isAllCountLoading = true;
notifyListeners();
String url = '';
if (usersType == UsersTypes.engineer) {
if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
url = URLs.engineerDashboardCountUrl;
} else {
url = URLs.nurseDashboardCountUrl;
@ -241,7 +241,7 @@ class DashBoardProvider extends ChangeNotifier {
Response response;
String url = '';
if (usersType == UsersTypes.engineer) {
if (usersType == UsersTypes.engineer || usersType == UsersTypes.assessor || usersType == UsersTypes.assessorTl) {
//need to check pagination for not assigned task @waseem.
//these checks are to call different apis for dashboard for engineer...

@ -4,6 +4,7 @@ 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/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';
import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart';
@ -49,10 +50,12 @@ class RequestCategoryList extends StatelessWidget {
return RecurrentWoItemView(requestData: request);
case 6:
return TaskRequestItemView(requestData: request);
case 7:
case 7:
return TaskRequestItemView(requestData: request);
case 8:
case 8:
return InventorySessionItemView(requestData: request);
case 9:
return TrafRequestItemView(requestData: request);
default:
return Container(
height: 100,

@ -16,8 +16,10 @@ import 'package:test_sa/controllers/providers/api/devices_provider.dart';
import 'package:test_sa/controllers/providers/api/gas_refill_provider.dart';
import 'package:test_sa/controllers/providers/api/hospitals_provider.dart';
import 'package:test_sa/controllers/providers/api/notifications_provider.dart';
import 'package:test_sa/controllers/providers/api/oracle_code_provider.dart';
import 'package:test_sa/controllers/providers/api/parts_provider.dart';
import 'package:test_sa/controllers/providers/api/ppm_provider.dart';
import 'package:test_sa/controllers/providers/api/search_user_provider.dart';
import 'package:test_sa/controllers/providers/api/service_requests_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/employee/nurse_provider.dart';
import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_assistants_employee_provider.dart';
@ -29,6 +31,9 @@ import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_
import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart';
import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart';
import 'package:test_sa/modules/traf_module/create_traf_request_page.dart';
import 'package:test_sa/modules/traf_module/traf_request_provider.dart';
import 'package:test_sa/modules/traf_module/update_traf_request_page.dart';
import 'package:test_sa/new_views/app_style/app_themes.dart';
import 'package:test_sa/new_views/pages/help_center_page.dart';
import 'package:test_sa/new_views/pages/land_page/land_page.dart';
@ -48,6 +53,7 @@ import 'package:test_sa/providers/gas_request_providers/gas_status_provider.dart
import 'package:test_sa/providers/gas_request_providers/gas_types_provider.dart';
import 'package:test_sa/providers/gas_request_providers/site_provider.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/providers/lookups/recommendation_lookup_provider.dart';
import 'package:test_sa/providers/ppm_asset_availability_provider.dart';
import 'package:test_sa/providers/ppm_checklist_status_provider.dart';
import 'package:test_sa/providers/ppm_device_status_provider.dart';
@ -94,6 +100,10 @@ import 'controllers/providers/api/user_provider.dart';
import 'controllers/providers/settings/setting_provider.dart';
import 'dashboard_latest/dashboard_provider.dart';
import 'new_views/pages/gas_refill_request_form.dart';
import 'providers/lookups/classification_lookup_provider.dart';
import 'providers/lookups/department_lookup_provider.dart';
import 'providers/lookups/request_type_lookup_provider.dart';
import 'providers/lookups/yes_no_lookup_provider.dart';
import 'providers/service_request_providers/loan_availability_provider.dart';
import 'providers/service_request_providers/reject_reason_provider.dart';
@ -122,7 +132,8 @@ void main() async {
} else {
await Firebase.initializeApp();
}
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(statusBarColor: Colors.transparent,
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.dark,
));
@ -180,21 +191,18 @@ class MyApp extends StatelessWidget {
//new providers according to new Api's..
ChangeNotifierProvider(create: (_) => DashBoardProvider()),
ChangeNotifierProvider(create: (_) => ServiceRequestDetailProvider()),
// ChangeNotifierProvider(create: (_) => PreventiveMaintenanceVisitsProvider()),
ChangeNotifierProvider(create: (_) => ClassificationLookupProvider()),
ChangeNotifierProvider(create: (_) => RecommendationLookupProvider()),
ChangeNotifierProvider(create: (_) => PpmProvider()),
ChangeNotifierProvider(create: (_) => PartsProvider()),
///todo deleted
//ChangeNotifierProvider(create: (_) => ServiceReportReasonsProvider()),
//ChangeNotifierProvider(create: (_) => ServiceReportStatusProvider()),
///todo deleted
//ChangeNotifierProvider(create: (_) => ServiceReportEquipmentStatusProvider()),
//ChangeNotifierProvider(create: (_) => ServiceReportTypesProvider()),
ChangeNotifierProvider(create: (_) => RequestTypeLookupProvider()),
ChangeNotifierProvider(create: (_) => YesNoLookupProvider()),
ChangeNotifierProvider(create: (_) => ServiceStatusProvider()),
ChangeNotifierProvider(create: (_) => ServiceReportLastCallsProvider()),
///todo deleted
//ChangeNotifierProvider(create: (_) => GasCylinderSizesProvider()),
ChangeNotifierProvider(create: (_) => OracleCodeProvider()),
///todo deleted
//ChangeNotifierProvider(create: (_) => GasCylinderTypesProvider()),
ChangeNotifierProvider(create: (_) => GasStatusProvider()),
@ -203,8 +211,10 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => DeviceTransferProvider()),
ChangeNotifierProvider(create: (_) => AssetTransferStatusProvider()),
///todo deleted
//ChangeNotifierProvider(create: (_) => AssignedToProvider()),
ChangeNotifierProvider(create: (_) => TrafRequestProvider()),
ChangeNotifierProvider(create: (_) => DepartmentLookupProvider()),
ChangeNotifierProvider(create: (_) => UserSearchProvider()),
///todo deleted
//ChangeNotifierProvider(create: (_) => PentryTaskStatusProvider()),
//ChangeNotifierProvider(create: (_) => PentryVisitStatusProvider()),
@ -314,7 +324,8 @@ class MyApp extends StatelessWidget {
GasRefillRequestForm.routeName: (_) => const GasRefillRequestForm(),
// ServiceRequestsPage.id: (_) => const ServiceRequestsPage(),
CreateTaskView.id: (_) => const CreateTaskView(),
//ReportIssuesPage.id: (_) => ReportIssuesPage(),
CreateTRAFRequestPage.id: (_) => CreateTRAFRequestPage(),
UpdateTrafRequestPage.id: (_) => UpdateTrafRequestPage(),
RequestGasRefill.id: (_) => const RequestGasRefill(),
UpdateGasRefillRequest.id: (_) => const UpdateGasRefillRequest(),
// CreateServiceRequestPage.id: (_) => const CreateServiceRequestPage(),

@ -2,4 +2,6 @@ enum UsersTypes {
engineer, // 0
normal_user, // 1
nurse, // 1
assessor,
assessorTl
}

@ -0,0 +1,27 @@
class AssetNDAutoCompleteByDynamicCodesModel {
int? id;
String? assetName;
int? codeTypeId;
String? codeValue;
String? displayName;
AssetNDAutoCompleteByDynamicCodesModel({this.id, this.assetName, this.codeTypeId, this.codeValue, this.displayName});
AssetNDAutoCompleteByDynamicCodesModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
assetName = json['assetName'];
codeTypeId = json['codeTypeId'];
codeValue = json['codeValue'];
displayName = json['displayName'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['assetName'] = this.assetName;
data['codeTypeId'] = this.codeTypeId;
data['codeValue'] = this.codeValue;
data['displayName'] = this.displayName;
return data;
}
}

@ -0,0 +1,101 @@
import 'package:test_sa/models/new_models/room_model.dart';
import '../base.dart';
class TrafDepartment extends Base {
TrafDepartment({
this.departmentName, this.departmentCode, this.ntCode, this.costCenterNumber, this.costCenterName, this.name, this.id, this.createdBy, this.createdDate, this.modifiedBy, this.modifiedDate
}) : super(identifier: id?.toString() ?? '', name: departmentName); // Handle potential null id
TrafDepartment.fromJson(Map<String, dynamic> json) {
departmentName = json['departmentName'] ?? json['name'];
departmentCode = json['departmentCode'];
ntCode = json['ntCode'];
costCenterNumber = json['costCenterNumber'];
costCenterName = json['costCenterName'];
name = json['name'];
id = json['id'];
createdBy = json['createdBy'];
createdDate = json['createdDate'];
modifiedBy = json['modifiedBy'];
modifiedDate = json['modifiedDate'];
}
num? id; // Now nullable
String? departmentName; // Now nullable
String? departmentCode; // Now nullable
String? ntCode;
String? costCenterNumber;
String? costCenterName;
String? name;
String? createdBy;
String? createdDate;
String? modifiedBy;
String? modifiedDate;
// TrafDepartment copyWith({
// num? id, // Parameters are now nullable
// String? departmentName,
// String? departmentCode,
// String? departmentId,
// String? ntCode,
// List<Rooms>? rooms,
// }) =>
// TrafDepartment(
// id: id ?? this.id,
// departmentName: departmentName ?? this.departmentName,
// departmentCode: departmentCode ?? this.departmentCode,
// departmentId: departmentId ?? this.departmentId,
// ntCode: ntCode ?? this.ntCode,
// rooms: rooms ?? this.rooms,
// );
}
// class TrafDepartment extends Base {
// String? departmentName;
// String? departmentCode;
// Null? ntCode;
// Null? costCenterNumber;
// Null? costCenterName;
// String? name;
// int? id;
// String? createdBy;
// String? createdDate;
// Null? modifiedBy;
// Null? modifiedDate;
//
// TrafDepartment(
// {this.departmentName, this.departmentCode, this.ntCode, this.costCenterNumber, this.costCenterName, this.name, this.id, this.createdBy, this.createdDate, this.modifiedBy, this.modifiedDate});
//
// TrafDepartment.fromJson(Map<String, dynamic> json) {
// departmentName = json['departmentName'];
// departmentCode = json['departmentCode'];
// ntCode = json['ntCode'];
// costCenterNumber = json['costCenterNumber'];
// costCenterName = json['costCenterName'];
// name = json['name'];
// id = json['id'];
// createdBy = json['createdBy'];
// createdDate = json['createdDate'];
// modifiedBy = json['modifiedBy'];
// modifiedDate = json['modifiedDate'];
// }
//
// Map<String, dynamic> toJson() {
// final Map<String, dynamic> data = new Map<String, dynamic>();
// data['departmentName'] = this.departmentName;
// data['departmentCode'] = this.departmentCode;
// data['ntCode'] = this.ntCode;
// data['costCenterNumber'] = this.costCenterNumber;
// data['costCenterName'] = this.costCenterName;
// data['name'] = this.name;
// data['id'] = this.id;
// data['createdBy'] = this.createdBy;
// data['createdDate'] = this.createdDate;
// data['modifiedBy'] = this.modifiedBy;
// data['modifiedDate'] = this.modifiedDate;
// return data;
// }
// }

@ -0,0 +1,44 @@
class UsersBasedOnSearchModel {
String? userId;
String? userName;
String? email;
String? employeeId;
int? languageId;
String? extensionNo;
String? phoneNumber;
bool? isActive;
UsersBasedOnSearchModel(
{this.userId,
this.userName,
this.email,
this.employeeId,
this.languageId,
this.extensionNo,
this.phoneNumber,
this.isActive});
UsersBasedOnSearchModel.fromJson(Map<String, dynamic> json) {
userId = json['userId'];
userName = json['userName'];
email = json['email'];
employeeId = json['employeeId'];
languageId = json['languageId'];
extensionNo = json['extensionNo'];
phoneNumber = json['phoneNumber'];
isActive = json['isActive'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['userId'] = this.userId;
data['userName'] = this.userName;
data['email'] = this.email;
data['employeeId'] = this.employeeId;
data['languageId'] = this.languageId;
data['extensionNo'] = this.extensionNo;
data['phoneNumber'] = this.phoneNumber;
data['isActive'] = this.isActive;
return data;
}
}

@ -103,11 +103,16 @@ class User {
return UsersTypes.normal_user;
case "R-33": // Head Nurse Role
return UsersTypes.normal_user;
case "R-32": // Head Nurse Role
return UsersTypes.assessor;
case "R-19": // Head Nurse Role
return UsersTypes.assessorTl;
default:
return null;
}
}
Map<String, dynamic> toUpdateProfileJson() {
Map<String, dynamic> jsonObject = {};
// if (departmentId != null) jsonObject["department"] = departmentId;

@ -0,0 +1,132 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/oracle_code_provider.dart';
import 'package:test_sa/controllers/providers/api/parts_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/widget_extensions.dart';
import 'package:test_sa/models/new_models/asset_nd_auto_complete_by_dynamic_codes_model.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 '../../../models/service_request/spare_parts.dart';
import '../../../new_views/app_style/app_text_style.dart';
class AssetAutoCompleteField extends StatefulWidget {
final String initialValue;
final num? assetId;
final bool clearAfterPick, byName;
final Function(AssetNDAutoCompleteByDynamicCodesModel) onPick;
const AssetAutoCompleteField({Key? key, required this.byName, required this.initialValue, this.assetId, required this.onPick, this.clearAfterPick = true}) : super(key: key);
@override
_AssetAutoCompleteFieldState createState() => _AssetAutoCompleteFieldState();
}
class _AssetAutoCompleteFieldState extends State<AssetAutoCompleteField> {
late OracleCodeProvider _oracleCodeProvider;
late TextEditingController _controller;
bool loading = false;
@override
void initState() {
_controller = TextEditingController(text: widget.initialValue);
super.initState();
_oracleCodeProvider = Provider.of<OracleCodeProvider>(context, listen: false);
}
@override
void didUpdateWidget(covariant AssetAutoCompleteField 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) {
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<AssetNDAutoCompleteByDynamicCodesModel>(
optionsBuilder: (TextEditingValue textEditingValue) async {
if (textEditingValue.text.isEmpty) {
if (loading) {
setState(() {
loading = false;
});
}
return const Iterable<AssetNDAutoCompleteByDynamicCodesModel>.empty();
}
if (!loading) {
setState(() {
loading = true;
});
}
List<AssetNDAutoCompleteByDynamicCodesModel> workOrders = (await _oracleCodeProvider.getAssetByOracleCode(textEditingValue.text));
setState(() {
loading = false;
});
return workOrders;
},
displayStringForOption: (AssetNDAutoCompleteByDynamicCodesModel option) => widget.byName ? option.displayName ?? "" : option.codeValue ?? "",
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(maxHeight: 24, maxWidth: 24 + 8),
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: context.translation.oracleCode,
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
suffixIcon: loading ? const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3.0).paddingOnly(end: 8) : null,
),
textInputAction: TextInputAction.search,
onChanged: (text) {
fieldTextEditingController.text = text;
},
onSubmitted: (String value) {
onFieldSubmitted();
},
);
},
onSelected: (AssetNDAutoCompleteByDynamicCodesModel selection) {
if (widget.clearAfterPick) {
_controller.clear();
} else {
_controller.text = widget.byName ? (selection.displayName ?? "") : (selection.codeValue ?? "");
}
widget.onPick(selection);
},
),
);
}
}

@ -0,0 +1,443 @@
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/helper/utils.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/new_models/traf_department.dart';
import 'package:test_sa/models/new_models/users_based_on_search_model.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/modules/traf_module/asset_auto_complete_field.dart';
import 'package:test_sa/modules/traf_module/traf_request_detail_page.dart';
import 'package:test_sa/modules/traf_module/update_traf_request_page.dart';
import 'package:test_sa/modules/traf_module/users_auto_complete_field.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_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/multiple_item_drop_down_menu.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/providers/lookups/department_lookup_provider.dart';
import 'package:test_sa/providers/lookups/request_type_lookup_provider.dart';
import 'package:test_sa/providers/lookups/yes_no_lookup_provider.dart';
import 'package:test_sa/views/widgets/equipment/asset_picker.dart';
import 'traf_request_model.dart';
import 'traf_request_provider.dart';
class CreateTRAFRequestPage extends StatefulWidget {
static const String id = "/create-TRAF";
CreateTRAFRequestPage({Key? key}) : super(key: key);
@override
_CreateTRAFRequestPageState createState() {
return _CreateTRAFRequestPageState();
}
}
class _CreateTRAFRequestPageState extends State<CreateTRAFRequestPage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
bool _acknowledgement = false;
Asset? asset;
Lookup? requestType;
Lookup? isUsedSolelyOrShared;
Lookup? otherServicesEffects;
Lookup? useInCombination;
TrafRequestDataModel? trafRequest;
List<Lookup> abc = [];
List<TrafDepartment> departments = [];
List<UsersBasedOnSearchModel> userBasedOnSearch = [];
FocusNode otherServicesEffectsNode = FocusNode();
FocusNode useInCombinationNode = FocusNode();
FocusNode departmentNode = FocusNode();
@override
void initState() {
super.initState();
trafRequest = TrafRequestDataModel(id: 0, attachments: [], departments: [], qty: 1);
resetProviders();
}
void resetProviders() {
Provider.of<RequestTypeLookupProvider>(context, listen: false).reset();
// Provider.of<YesNoLookupProvider>(context, listen: false).reset();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const DefaultAppBar(title: "TRAF Request"),
body: Form(
key: _formKey,
child: Column(
children: [
ListView(padding: const EdgeInsets.all(16), children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// SingleItemDropDownMenu<TaskType, TaskTypeProvider>(
// context: context,
// height: 56.toScreenHeight,
// title: context.translation.taskType,
// showShadow: false,
// backgroundColor: AppColor.fieldBgColor(context),
// showAsBottomSheet: true,
// initialValue: selectedType,
// onSelect: (type) {},
// ),
SingleItemDropDownMenu<Lookup, RequestTypeLookupProvider>(
context: context,
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
title: context.translation.requestType,
initialValue: requestType,
onSelect: (value) {
requestType = value;
trafRequest?.requestTypeId = value?.id;
if (requestType?.value == 1) {
trafRequest?.assetId = null;
// trafRequest?.qty = 0;
} else if (requestType?.value == 2) {
trafRequest?.assetNDId = null;
}
setState(() {});
},
),
if (requestType?.value == 1) ...[
12.height,
AssetAutoCompleteField(
clearAfterPick: false,
byName: true,
initialValue: "",
onPick: (asset) {
trafRequest?.assetNDId = asset.id;
// model.partCatalogItem = PartCatalogItem(id: part.sparePart?.id, partNumber: part.sparePart?.partNo, partName: part.sparePart?.partName, oracleCode: part.sparePart?.oracleCode);
// setState(() {});
},
),
],
if (requestType?.value == 2) ...[
12.height,
AssetPicker(
device: asset,
editable: false,
showLoading: false,
borderColor: AppColor.black20,
backgroundColor: AppColor.white936,
onPick: (asset) async {
this.asset = asset;
trafRequest?.assetId = asset.id?.toInt();
// trafRequest?.qty = 1;
setState(() {});
// pendingAssetServiceRequest = null;
// _serviceRequest.device = asset;
// await checkAssetForPendingServiceRequest(asset.id!.toInt());
// if (pendingAssetServiceRequest != null && pendingAssetServiceRequest!.details!.isNotEmpty) {
// showPendingRequestBottomSheet();
// }
},
),
],
12.height,
Text(
"Request Details",
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontWeight: FontWeight.w600),
),
12.height,
AppTextFormField(
initialValue: "",
labelText: "How would the requested technology solve the current situation and/or serve the purpose?",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
floatingLabelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
makeMultiLinesNull: true,
onChange: (value) {
trafRequest?.purposeAnswer = value;
},
),
12.height,
AppTextFormField(
initialValue: "",
labelText: "What is the current practice?",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
makeMultiLinesNull: true,
onChange: (value) {
trafRequest?.currentPractise = value;
},
),
12.height,
AppTextFormField(
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q1",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
textInputType: TextInputType.number,
onChange: (value) {
trafRequest?.censusQ1 = int.tryParse(value);
},
),
12.height,
AppTextFormField(
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q2",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
textInputType: TextInputType.number,
onChange: (value) {
trafRequest?.censusQ2 = int.tryParse(value);
},
),
12.height,
AppTextFormField(
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q3",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
textInputType: TextInputType.number,
onChange: (value) {
trafRequest?.censusQ3 = int.tryParse(value);
},
),
12.height,
AppTextFormField(
initialValue: "",
makeMultiLinesNull: true,
labelText: "Census Q4",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
textInputType: TextInputType.number,
onChange: (value) {
trafRequest?.censusQ4 = int.tryParse(value);
},
),
12.height,
SearchUserAutoCompleteField(
clearAfterPick: true,
byName: true,
initialValue: "",
onPick: (user) {
userBasedOnSearch.add(user);
FocusScope.of(context).unfocus();
// model.partCatalogItem = PartCatalogItem(id: part.sparePart?.id, partNumber: part.sparePart?.partNo, partName: part.sparePart?.partName, oracleCode: part.sparePart?.oracleCode);
setState(() {});
},
),
if (userBasedOnSearch.isNotEmpty) ...[
// 12.height,
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.only(left: 12, right: 12),
itemBuilder: (cxt, index) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
dense: true,
contentPadding: EdgeInsets.zero,
title: Text("Name: ${userBasedOnSearch[index].userName ?? ""}"),
subtitle: Text("Email: ${userBasedOnSearch[index].email ?? ""}\nPhone: ${userBasedOnSearch[index].phoneNumber ?? ""}"),
trailing: const Icon(Icons.delete_rounded, color: Color(0xffF63939), size: 20).onPress(() {
userBasedOnSearch.removeAt(index);
setState(() {});
}),
),
],
),
separatorBuilder: (cxt, index) => Divider(thickness: 1, height: 1, color: context.isDark ? AppColor.neutral20 : AppColor.neutral30),
itemCount: userBasedOnSearch.length)
],
12.height,
SingleItemDropDownMenu<Lookup, YesNoLookupProvider>(
context: context,
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
height: 80,
title: "Is the requesting department going to use the technology solely or shared with other departments?",
initialValue: isUsedSolelyOrShared,
onSelect: (value) {
isUsedSolelyOrShared = value;
trafRequest?.usingSolelyOrSharedId = value?.value;
if (isUsedSolelyOrShared?.value != 1) {
departments = [];
trafRequest?.trafDepartments = [];
Provider.of<DepartmentLookupProvider>(context, listen: false).reset();
FocusScope.of(context).unfocus();
} else {
departmentNode.requestFocus();
}
setState(() {});
},
),
if (isUsedSolelyOrShared?.value == 1) ...[
12.height,
Focus(
focusNode: departmentNode,
child: MultipleItemDropDownMenu<TrafDepartment, DepartmentLookupProvider>(
context: context,
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
showCancel: true,
requestById: context.userProvider.user?.clientId,
title: "Please specify departments and relations",
initialValue: departments,
onSelect: (value) {
departments = value ?? [];
trafRequest?.trafDepartments = departments.map((element) => Departments(id: 0, trafId: 0, departmentId: element.id!.toInt())).toList();
},
),
),
],
12.height,
SingleItemDropDownMenu<Lookup, YesNoLookupProvider>(
context: context,
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
height: 80,
title: "Would other services be effected by acquiring the new equipment?",
initialValue: otherServicesEffects,
onSelect: (value) {
otherServicesEffects = value;
trafRequest?.isEffectedId = value?.value;
if (otherServicesEffects?.value != 1) {
trafRequest?.effectedServices = null;
FocusScope.of(context).unfocus();
} else {
otherServicesEffectsNode.requestFocus();
}
setState(() {});
},
),
if (otherServicesEffects?.value == 1) ...[
12.height,
AppTextFormField(
initialValue: "",
// makeMultiLinesNull: true,
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
node: otherServicesEffectsNode,
labelText: "List down these services and stat how would it be effected",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
onChange: (value) {
trafRequest?.effectedServices = value;
},
),
],
12.height,
SingleItemDropDownMenu<Lookup, YesNoLookupProvider>(
context: context,
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
height: 80,
title: "Is the equipment going to be used with combination of other equipment to accomplish a specific procedure?",
initialValue: useInCombination,
onSelect: (value) {
useInCombination = value;
trafRequest?.isCombinationId = value?.value;
if (useInCombination?.value != 1) {
trafRequest?.usedWithCombination = null;
FocusScope.of(context).unfocus();
} else {
useInCombinationNode.requestFocus();
}
setState(() {});
},
),
if (useInCombination?.value == 1) ...[
12.height,
AppTextFormField(
initialValue: "",
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
node: useInCombinationNode,
labelText: "kindly describe in detail",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
onChange: (value) {
trafRequest?.usedWithCombination = value;
},
),
]
],
).toShadowContainer(context, padding: 12, borderRadius: 20),
16.height,
Row(
children: [
Checkbox(
value: _acknowledgement,
visualDensity: const VisualDensity(horizontal: -4.0, vertical: -4.0),
activeColor: AppColor.blueStatus(context),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
onChanged: (value) {
setState(() {
_acknowledgement = value!;
});
}),
12.width,
"I acknowledge the information filled above is correct".addTranslation.bodyText(context).custom(color: context.isDark ? AppColor.primary50 : AppColor.neutral120).expanded,
],
),
]).expanded,
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
buttonColor: AppColor.primary10,
label: context.translation.submitRequest,
disableButton: !_acknowledgement,
onPressed: _verifyAndSubmit,
// buttonColor: AppColor.primary10,
),
),
],
),
),
);
}
void _verifyAndSubmit() async {
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();
Utils.showLoading(context);
await Provider.of<TrafRequestProvider>(context, listen: false).addTraf(trafRequest!.toJson());
Utils.hideLoading(context);
Navigator.pop(context);
}
}

@ -0,0 +1,166 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/modules/traf_module/traf_request_provider.dart';
import 'package:test_sa/modules/traf_module/update_traf_request_page.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/loaders/app_loading.dart';
import 'traf_request_model.dart';
class TrafRequestDetailPage extends StatefulWidget {
static const String id = "/details-TRAF";
final int trafId;
TrafRequestDetailPage({Key? key, required this.trafId}) : super(key: key);
@override
_TrafRequestDetailPageState createState() {
return _TrafRequestDetailPageState();
}
}
class _TrafRequestDetailPageState extends State<TrafRequestDetailPage> {
@override
void initState() {
super.initState();
Provider.of<TrafRequestProvider>(context, listen: false).getTRAFById(widget.trafId);
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
bool isEngineer = (Provider.of<UserProvider>(context, listen: false).user?.type) == UsersTypes.engineer;
return Scaffold(
appBar: const DefaultAppBar(title: "TRAF Request"),
body: Selector<TrafRequestProvider, bool>(
selector: (_, myModel) => myModel.isLoading, // Selects only the userName
builder: (_, isLoading, __) {
if (isLoading) return const ALoading();
TrafRequestProvider trafProvider = Provider.of<TrafRequestProvider>(context, listen: false);
return Column(
children: [
ListView(
padding: const EdgeInsets.all(16),
children: [
requesterInformation(trafProvider.trafRequestDataModel!),
12.height,
requestInformation(trafProvider.trafRequestDataModel!),
12.height,
assetInformation(trafProvider.trafRequestDataModel!),
],
).expanded,
// // if (isEngineer)
// FooterActionButton.footerContainer(
// context: context,
// child: AppFilledButton(
// buttonColor: AppColor.primary10,
// label: "Update",
// onPressed: () {
// Navigator.pushNamed(context, UpdateTrafRequestPage.id);
// }),
// ),
],
);
},
));
}
Widget requesterInformation(TrafRequestDataModel data) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Requester Information",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
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.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),
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
Widget requestInformation(TrafRequestDataModel data) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Request Information",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
8.height,
'TRAF No: ${data.reqCode ?? '-'}'.bodyText(context),
'Request type: ${data.requestTypeName ?? '-'}'.bodyText(context),
4.height,
'How would the requested technology solve the current situation and/or serve the purpose?: ${data.purposeAnswer ?? '-'}'.bodyText(context),
4.height,
'What is the current practice?: ${data.currentPractise ?? '-'}'.bodyText(context),
4.height,
'Census Q1: ${data.censusQ1 ?? '-'}'.bodyText(context),
'Census Q2: ${data.censusQ2 ?? '-'}'.bodyText(context),
'Census Q3: ${data.censusQ3 ?? '-'}'.bodyText(context),
'Census Q4: ${data.censusQ4 ?? '-'}'.bodyText(context),
4.height,
'List down names & contact information of users going to use the technology & specify if they are part-time or full time?:\n${data.trafContacts?.map((item) => item.name).toList() ?? '-'}'
.bodyText(context),
4.height,
'Is the requesting department going to use the technology solely or shared with other departments?:\n${data.usingSolelyOrSharedName ?? '-'}'.bodyText(context),
4.height,
'Would other services be effected by acquiring the new equipment?:\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),
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
Widget assetInformation(TrafRequestDataModel data) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Asset Information",
style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
8.height,
'${context.translation.assetName}: ${data.assetName ?? '-'}'.bodyText(context),
'${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
],
],
).toShadowContainer(context, borderRadius: 20, padding: 12);
}
}

@ -0,0 +1,125 @@
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/new_views/app_style/app_color.dart';
import 'package:test_sa/views/widgets/requests/request_status.dart';
import 'traf_request_detail_page.dart';
class TrafRequestItemView extends StatelessWidget {
final Data? requestData;
final RequestsDetails? requestDetails;
final bool showShadow;
const TrafRequestItemView({Key? key, this.requestData, this.requestDetails, this.showShadow = true}) : super(key: key);
@override
Widget build(BuildContext context) {
if (requestData != null) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// StatusLabel(
// label: requestData!.priorityName!,
// textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.priorityName!),
// backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.priorityName!),
// ),
// 8.width,
StatusLabel(
label: requestData!.statusName!,
textColor: AppColor.getRequestStatusTextColorByName(context, requestData!.statusName!),
backgroundColor: AppColor.getRequestStatusColorByName(context, requestData!.statusName!),
),
1.width.expanded,
Text(
requestData!.transactionDate?.toServiceRequestCardFormat ?? "",
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
),
],
),
8.height,
(requestData?.typeTransaction ?? "TRAF Request").heading5(context),
infoWidget(label: context.translation.requestType, value: requestData?.requestTypeName, context: context),
infoWidget(label: "TRAF No", value: requestData?.requestNo, 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.push(context, MaterialPageRoute(builder: (context) => TrafRequestDetailPage(trafId: requestData!.id!)));
});
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// StatusLabel(
// label: requestDetails!.priority!,
// textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.priority!),
// backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.priority!),
// ),
// 8.width,
StatusLabel(
label: requestDetails!.status!,
textColor: AppColor.getRequestStatusTextColorByName(context, requestDetails?.status!),
backgroundColor: AppColor.getRequestStatusColorByName(context, requestDetails?.status!),
),
1.width.expanded,
Text(
requestDetails!.date?.toServiceRequestCardFormat ?? "",
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
),
],
),
8.height,
(requestDetails?.nameOfType ?? "TRAF Request").heading5(context),
8.height,
infoWidget(label: context.translation.requestType, value: requestDetails!.requestType, context: context),
infoWidget(label: "TRAF No", value: requestDetails!.requestNo, context: context),
infoWidget(label: context.translation.site, value: requestDetails!.site, context: context),
8.height,
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
context.translation.viewDetails,
style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context)),
),
4.width,
Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14)
],
),
],
).toShadowContainer(context, withShadow: showShadow).onPress(() async {
Navigator.push(context, MaterialPageRoute(builder: (context) => TrafRequestDetailPage(trafId: requestDetails!.id!)));
});
}
Widget infoWidget({required String label, String? value, required BuildContext context}) {
if (value != null && value.isNotEmpty) {
return '$label: $value'.bodyText(context);
}
return const SizedBox();
}
}

@ -0,0 +1,574 @@
class TrafRequestModel {
List<TrafRequestDataModel>? trafRequestDataModel;
int? totalRows;
int? count;
String? message;
String? title;
String? innerMessage;
int? responseCode;
bool? isSuccess;
TrafRequestModel({this.trafRequestDataModel, this.totalRows, this.count, this.message, this.title, this.innerMessage, this.responseCode, this.isSuccess});
TrafRequestModel.fromJson(Map<String, dynamic> json) {
if (json['TrafRequestDataModel'] != null) {
trafRequestDataModel = <TrafRequestDataModel>[];
json['TrafRequestDataModel'].forEach((v) {
trafRequestDataModel!.add(new TrafRequestDataModel.fromJson(v));
});
}
totalRows = json['totalRows'];
count = json['count'];
message = json['message'];
title = json['title'];
innerMessage = json['innerMessage'];
responseCode = json['responseCode'];
isSuccess = json['isSuccess'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.trafRequestDataModel != null) {
data['TrafRequestDataModel'] = this.trafRequestDataModel!.map((v) => v.toJson()).toList();
}
data['totalRows'] = this.totalRows;
data['count'] = this.count;
data['message'] = this.message;
data['title'] = this.title;
data['innerMessage'] = this.innerMessage;
data['responseCode'] = this.responseCode;
data['isSuccess'] = this.isSuccess;
return data;
}
}
class TrafRequestDataModel {
int? reqNo;
String? reqCode;
String? employeeId;
String? employeeIdForDisplay;
String? employeeName;
String? employeeEmail;
int? positionId;
String? positionName;
List<Departments>? departments;
List<Departments>? trafDepartments;
int? siteId;
String? siteName;
String? requesterExtensionNumber;
String? requesterExtensionName;
int? requesterExtensionPositionId;
String? requesterExtensionPositionName;
int? requestTypeId;
String? requestTypeName;
int? assetNDId;
int? modelId;
String? modelName;
int? manufacturerId;
String? manufacturerName;
int? assetId;
String? assetSerialNo;
String? assetNumber;
String? assetName;
int? assetAssetNDId;
int? qty;
String? purposeAnswer;
String? currentPractise;
int? censusQ1;
int? censusQ2;
int? censusQ3;
int? censusQ4;
List<TrafContacts>? trafContacts;
int? usingSolelyOrSharedId;
String? usingSolelyOrSharedName;
int? isEffectedId;
String? isEffectedName;
String? effectedServices;
int? isCombinationId;
String? isCombinationName;
String? usedWithCombination;
String? comment;
List<Attachments>? attachments;
int? isBudgetId;
String? isBudgetName;
String? firstLineManagerId;
String? firstLineManagerName;
int? firstLineManagerApprovalId;
String? firstLineManagerApprovalName;
int? tlapiId;
String? tlapiName;
String? assessorEmployeeId;
String? assessorEmployeeName;
String? secondLineManagerId;
String? secondLineManagerName;
int? secondLineManagerApprovalId;
String? secondLineManagerApprovalName;
String? hospitalManagementId;
String? hospitalManagementName;
int? hospitalManagementApprovalId;
String? hospitalManagementApprovalName;
List<OracleCodes>? oracleCodes;
String? assessorTeamLeaderId;
String? assessorTeamLeaderName;
int? assessorTeamLeaderApprovalId;
String? assessorTeamLeaderApprovalName;
int? statusOfDRId;
String? statusOfDRName;
int? statusOfRequesterId;
String? statusOfRequesterName;
bool? approved;
String? approvalUserId;
String? approvalUserName;
String? approvalDate;
String? docDate;
String? approvalDocDate;
String? isAssigned;
String? poNumber;
int? apiDirectorId;
String? apiDirectorName;
int? apiDirectorApprovalId;
String? apiDirectorApprovalName;
List<int>? trafAssessIds;
List<int>? trafPRIds;
List<int>? trafOfferIds;
int? id;
String? createdBy;
String? createdDate;
String? modifiedBy;
String? modifiedDate;
TrafRequestDataModel(
{this.reqNo,
this.reqCode,
this.employeeId,
this.employeeIdForDisplay,
this.employeeName,
this.employeeEmail,
this.positionId,
this.positionName,
this.departments,
this.trafDepartments,
this.siteId,
this.siteName,
this.requesterExtensionNumber,
this.requesterExtensionName,
this.requesterExtensionPositionId,
this.requesterExtensionPositionName,
this.requestTypeId,
this.requestTypeName,
this.assetNDId,
this.modelId,
this.modelName,
this.manufacturerId,
this.manufacturerName,
this.assetId,
this.assetSerialNo,
this.assetNumber,
this.assetName,
this.assetAssetNDId,
this.qty,
this.purposeAnswer,
this.currentPractise,
this.censusQ1,
this.censusQ2,
this.censusQ3,
this.censusQ4,
this.trafContacts,
this.usingSolelyOrSharedId,
this.usingSolelyOrSharedName,
this.isEffectedId,
this.isEffectedName,
this.effectedServices,
this.isCombinationId,
this.isCombinationName,
this.usedWithCombination,
this.comment,
this.attachments,
this.isBudgetId,
this.isBudgetName,
this.firstLineManagerId,
this.firstLineManagerName,
this.firstLineManagerApprovalId,
this.firstLineManagerApprovalName,
this.tlapiId,
this.tlapiName,
this.assessorEmployeeId,
this.assessorEmployeeName,
this.secondLineManagerId,
this.secondLineManagerName,
this.secondLineManagerApprovalId,
this.secondLineManagerApprovalName,
this.hospitalManagementId,
this.hospitalManagementName,
this.hospitalManagementApprovalId,
this.hospitalManagementApprovalName,
this.oracleCodes,
this.assessorTeamLeaderId,
this.assessorTeamLeaderName,
this.assessorTeamLeaderApprovalId,
this.assessorTeamLeaderApprovalName,
this.statusOfDRId,
this.statusOfDRName,
this.statusOfRequesterId,
this.statusOfRequesterName,
this.approved,
this.approvalUserId,
this.approvalUserName,
this.approvalDate,
this.docDate,
this.approvalDocDate,
this.isAssigned,
this.poNumber,
this.apiDirectorId,
this.apiDirectorName,
this.apiDirectorApprovalId,
this.apiDirectorApprovalName,
this.trafAssessIds,
this.trafPRIds,
this.trafOfferIds,
this.id,
this.createdBy,
this.createdDate,
this.modifiedBy,
this.modifiedDate});
TrafRequestDataModel.fromJson(Map<String, dynamic> json) {
reqNo = json['reqNo'];
reqCode = json['reqCode'];
employeeId = json['employeeId'];
employeeIdForDisplay = json['employeeIdForDisplay'];
employeeName = json['employeeName'];
employeeEmail = json['employeeEmail'];
positionId = json['positionId'];
positionName = json['positionName'];
if (json['departments'] != null) {
departments = <Departments>[];
json['departments'].forEach((v) {
departments!.add(new Departments.fromJson(v));
});
}
if (json['trafDepartments'] != null) {
trafDepartments = <Departments>[];
json['trafDepartments'].forEach((v) {
trafDepartments!.add(new Departments.fromJson(v));
});
}
siteId = json['siteId'];
siteName = json['siteName'];
requesterExtensionNumber = json['requesterExtensionNumber'];
requesterExtensionName = json['requesterExtensionName'];
requesterExtensionPositionId = json['requesterExtensionPositionId'];
requesterExtensionPositionName = json['requesterExtensionPositionName'];
requestTypeId = json['requestTypeId'];
requestTypeName = json['requestTypeName'];
assetNDId = json['assetNDId'];
modelId = json['modelId'];
modelName = json['modelName'];
manufacturerId = json['manufacturerId'];
manufacturerName = json['manufacturerName'];
assetId = json['assetId'];
assetSerialNo = json['assetSerialNo'];
assetNumber = json['assetNumber'];
assetName = json['assetName'];
assetAssetNDId = json['assetAssetNDId'];
qty = json['qty'];
purposeAnswer = json['purposeAnswer'];
currentPractise = json['currentPractise'];
censusQ1 = json['censusQ1'];
censusQ2 = json['censusQ2'];
censusQ3 = json['censusQ3'];
censusQ4 = json['censusQ4'];
if (json['trafContacts'] != null) {
trafContacts = <TrafContacts>[];
json['trafContacts'].forEach((v) {
trafContacts!.add(new TrafContacts.fromJson(v));
});
}
usingSolelyOrSharedId = json['usingSolelyOrSharedId'];
usingSolelyOrSharedName = json['usingSolelyOrSharedName'];
isEffectedId = json['isEffectedId'];
isEffectedName = json['isEffectedName'];
effectedServices = json['effectedServices'];
isCombinationId = json['isCombinationId'];
isCombinationName = json['isCombinationName'];
usedWithCombination = json['usedWithCombination'];
comment = json['comment'];
if (json['attachments'] != null) {
attachments = <Attachments>[];
json['attachments'].forEach((v) {
attachments!.add(new Attachments.fromJson(v));
});
}
isBudgetId = json['isBudgetId'];
isBudgetName = json['isBudgetName'];
firstLineManagerId = json['firstLineManagerId'];
firstLineManagerName = json['firstLineManagerName'];
firstLineManagerApprovalId = json['firstLineManagerApprovalId'];
firstLineManagerApprovalName = json['firstLineManagerApprovalName'];
tlapiId = json['tlapiId'];
tlapiName = json['tlapiName'];
assessorEmployeeId = json['assessorEmployeeId'];
assessorEmployeeName = json['assessorEmployeeName'];
secondLineManagerId = json['secondLineManagerId'];
secondLineManagerName = json['secondLineManagerName'];
secondLineManagerApprovalId = json['secondLineManagerApprovalId'];
secondLineManagerApprovalName = json['secondLineManagerApprovalName'];
hospitalManagementId = json['hospitalManagementId'];
hospitalManagementName = json['hospitalManagementName'];
hospitalManagementApprovalId = json['hospitalManagementApprovalId'];
hospitalManagementApprovalName = json['hospitalManagementApprovalName'];
if (json['oracleCodes'] != null) {
oracleCodes = <OracleCodes>[];
json['oracleCodes'].forEach((v) {
oracleCodes!.add(new OracleCodes.fromJson(v));
});
}
assessorTeamLeaderId = json['assessorTeamLeaderId'];
assessorTeamLeaderName = json['assessorTeamLeaderName'];
assessorTeamLeaderApprovalId = json['assessorTeamLeaderApprovalId'];
assessorTeamLeaderApprovalName = json['assessorTeamLeaderApprovalName'];
statusOfDRId = json['statusOfDRId'];
statusOfDRName = json['statusOfDRName'];
statusOfRequesterId = json['statusOfRequesterId'];
statusOfRequesterName = json['statusOfRequesterName'];
approved = json['approved'];
approvalUserId = json['approvalUserId'];
approvalUserName = json['approvalUserName'];
approvalDate = json['approvalDate'];
docDate = json['docDate'];
approvalDocDate = json['approvalDocDate'];
isAssigned = json['isAssigned'];
poNumber = json['poNumber'];
apiDirectorId = json['apiDirectorId'];
apiDirectorName = json['apiDirectorName'];
apiDirectorApprovalId = json['apiDirectorApprovalId'];
apiDirectorApprovalName = json['apiDirectorApprovalName'];
trafAssessIds = json['trafAssessIds'].cast<int>();
trafPRIds = json['trafPRIds'].cast<int>();
trafOfferIds = json['trafOfferIds'].cast<int>();
id = json['id'];
createdBy = json['createdBy'];
createdDate = json['createdDate'];
modifiedBy = json['modifiedBy'];
modifiedDate = json['modifiedDate'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['reqNo'] = this.reqNo;
data['reqCode'] = this.reqCode;
data['employeeId'] = this.employeeId;
data['employeeIdForDisplay'] = this.employeeIdForDisplay;
data['employeeName'] = this.employeeName;
data['employeeEmail'] = this.employeeEmail;
data['positionId'] = this.positionId;
data['positionName'] = this.positionName;
if (this.departments != null) {
data['departments'] = this.departments!.map((v) => v.toJson()).toList();
}
if (this.trafDepartments != null) {
data['trafDepartments'] = this.trafDepartments!.map((v) => v.toJson()).toList();
}
data['siteId'] = this.siteId;
data['siteName'] = this.siteName;
data['requesterExtensionNumber'] = this.requesterExtensionNumber;
data['requesterExtensionName'] = this.requesterExtensionName;
data['requesterExtensionPositionId'] = this.requesterExtensionPositionId;
data['requesterExtensionPositionName'] = this.requesterExtensionPositionName;
data['requestTypeId'] = this.requestTypeId;
data['requestTypeName'] = this.requestTypeName;
data['assetNDId'] = this.assetNDId;
data['modelId'] = this.modelId;
data['modelName'] = this.modelName;
data['manufacturerId'] = this.manufacturerId;
data['manufacturerName'] = this.manufacturerName;
data['assetId'] = this.assetId;
data['assetSerialNo'] = this.assetSerialNo;
data['assetNumber'] = this.assetNumber;
data['assetName'] = this.assetName;
data['assetAssetNDId'] = this.assetAssetNDId;
data['qty'] = this.qty;
data['purposeAnswer'] = this.purposeAnswer;
data['currentPractise'] = this.currentPractise;
data['censusQ1'] = this.censusQ1;
data['censusQ2'] = this.censusQ2;
data['censusQ3'] = this.censusQ3;
data['censusQ4'] = this.censusQ4;
if (this.trafContacts != null) {
data['trafContacts'] = this.trafContacts!.map((v) => v.toJson()).toList();
}
data['usingSolelyOrSharedId'] = this.usingSolelyOrSharedId;
data['usingSolelyOrSharedName'] = this.usingSolelyOrSharedName;
data['isEffectedId'] = this.isEffectedId;
data['isEffectedName'] = this.isEffectedName;
data['effectedServices'] = this.effectedServices;
data['isCombinationId'] = this.isCombinationId;
data['isCombinationName'] = this.isCombinationName;
data['usedWithCombination'] = this.usedWithCombination;
data['comment'] = this.comment;
if (this.attachments != null) {
data['attachments'] = this.attachments!.map((v) => v.toJson()).toList();
} else {
data['attachments'] = [];
}
data['isBudgetId'] = this.isBudgetId;
data['isBudgetName'] = this.isBudgetName;
data['firstLineManagerId'] = this.firstLineManagerId;
data['firstLineManagerName'] = this.firstLineManagerName;
data['firstLineManagerApprovalId'] = this.firstLineManagerApprovalId;
data['firstLineManagerApprovalName'] = this.firstLineManagerApprovalName;
data['tlapiId'] = this.tlapiId;
data['tlapiName'] = this.tlapiName;
data['assessorEmployeeId'] = this.assessorEmployeeId;
data['assessorEmployeeName'] = this.assessorEmployeeName;
data['secondLineManagerId'] = this.secondLineManagerId;
data['secondLineManagerName'] = this.secondLineManagerName;
data['secondLineManagerApprovalId'] = this.secondLineManagerApprovalId;
data['secondLineManagerApprovalName'] = this.secondLineManagerApprovalName;
data['hospitalManagementId'] = this.hospitalManagementId;
data['hospitalManagementName'] = this.hospitalManagementName;
data['hospitalManagementApprovalId'] = this.hospitalManagementApprovalId;
data['hospitalManagementApprovalName'] = this.hospitalManagementApprovalName;
if (this.oracleCodes != null) {
data['oracleCodes'] = this.oracleCodes!.map((v) => v.toJson()).toList();
}
data['assessorTeamLeaderId'] = this.assessorTeamLeaderId;
data['assessorTeamLeaderName'] = this.assessorTeamLeaderName;
data['assessorTeamLeaderApprovalId'] = this.assessorTeamLeaderApprovalId;
data['assessorTeamLeaderApprovalName'] = this.assessorTeamLeaderApprovalName;
data['statusOfDRId'] = this.statusOfDRId;
data['statusOfDRName'] = this.statusOfDRName;
data['statusOfRequesterId'] = this.statusOfRequesterId;
data['statusOfRequesterName'] = this.statusOfRequesterName;
data['approved'] = this.approved;
data['approvalUserId'] = this.approvalUserId;
data['approvalUserName'] = this.approvalUserName;
data['approvalDate'] = this.approvalDate;
data['docDate'] = this.docDate;
data['approvalDocDate'] = this.approvalDocDate;
data['isAssigned'] = this.isAssigned;
data['poNumber'] = this.poNumber;
data['apiDirectorId'] = this.apiDirectorId;
data['apiDirectorName'] = this.apiDirectorName;
data['apiDirectorApprovalId'] = this.apiDirectorApprovalId;
data['apiDirectorApprovalName'] = this.apiDirectorApprovalName;
data['trafAssessIds'] = this.trafAssessIds;
data['trafPRIds'] = this.trafPRIds;
data['trafOfferIds'] = this.trafOfferIds;
data['id'] = this.id;
data['createdBy'] = this.createdBy;
data['createdDate'] = this.createdDate;
data['modifiedBy'] = this.modifiedBy;
data['modifiedDate'] = this.modifiedDate;
return data;
}
}
class TrafContacts {
int? id;
int? trafId;
String? userId;
String? name;
String? telephone;
String? notes;
TrafContacts({this.id, this.trafId, this.userId, this.name, this.telephone, this.notes});
TrafContacts.fromJson(Map<String, dynamic> json) {
id = json['id'];
trafId = json['trafId'];
userId = json['userId'];
name = json['name'];
telephone = json['telephone'];
notes = json['notes'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['trafId'] = this.trafId;
data['userId'] = this.userId;
data['name'] = this.name;
data['telephone'] = this.telephone;
data['notes'] = this.notes;
return data;
}
}
class OracleCodes {
int? id;
int? assetNDId;
int? codeTypeId;
String? codeTypeName;
int? codeTypeValue;
String? codeValue;
OracleCodes({this.id, this.assetNDId, this.codeTypeId, this.codeTypeName, this.codeTypeValue, this.codeValue});
OracleCodes.fromJson(Map<String, dynamic> json) {
id = json['id'];
assetNDId = json['assetNDId'];
codeTypeId = json['codeTypeId'];
codeTypeName = json['codeTypeName'];
codeTypeValue = json['codeTypeValue'];
codeValue = json['codeValue'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['assetNDId'] = this.assetNDId;
data['codeTypeId'] = this.codeTypeId;
data['codeTypeName'] = this.codeTypeName;
data['codeTypeValue'] = this.codeTypeValue;
data['codeValue'] = this.codeValue;
return data;
}
}
class Departments {
int? id;
int? trafId;
int? departmentId;
String? departmentName;
Departments({this.id, this.trafId, this.departmentId, this.departmentName});
Departments.fromJson(Map<String, dynamic> json) {
id = json['id'];
trafId = json['trafId'];
departmentId = json['departmentId'];
departmentName = json['departmentName'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['trafId'] = this.trafId;
data['departmentId'] = this.departmentId;
data['departmentName'] = this.departmentName;
return data;
}
}
class Attachments {
int? id;
int? trafId;
String? attachmentName;
Attachments({this.id, this.trafId, this.attachmentName});
Attachments.fromJson(Map<String, dynamic> json) {
id = json['id'];
trafId = json['trafId'];
attachmentName = json['attachmentName'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['trafId'] = this.trafId;
data['attachmentName'] = this.attachmentName;
return data;
}
}

@ -0,0 +1,50 @@
import 'dart:convert';
import 'package:flutter/foundation.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 'traf_request_model.dart';
class TrafRequestProvider extends ChangeNotifier {
bool isLoading = false;
TrafRequestDataModel? trafRequestDataModel;
Future<int> addTraf(Map<String, dynamic> body) async {
try {
isLoading = true;
notifyListeners();
Response response = await ApiManager.instance.post(URLs.addTRAF, body: body);
if (response.statusCode >= 200 && response.statusCode < 300) {
// trafRequestDataModel = TrafRequestDataModel.fromJson(json.decode(response.body)["data"]);
}
isLoading = false;
notifyListeners();
return 0;
} catch (error) {
isLoading = false;
notifyListeners();
return -1;
}
}
Future<int> getTRAFById(int trafId) async {
try {
isLoading = true;
notifyListeners();
Response response = await ApiManager.instance.get("${URLs.getTRAFById}?tRAFId=$trafId");
if (response.statusCode >= 200 && response.statusCode < 300) {
trafRequestDataModel = TrafRequestDataModel.fromJson(json.decode(response.body)["data"]);
}
isLoading = false;
notifyListeners();
return 0;
} catch (error) {
isLoading = false;
notifyListeners();
return -1;
}
}
}

@ -0,0 +1,245 @@
import 'dart:convert';
import 'dart:io';
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/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/generic_attachment_model.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/modules/cm_module/utilities/service_request_utils.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/modules/traf_module/traf_request_model.dart';
import 'package:test_sa/modules/traf_module/traf_request_provider.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_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/new_views/common_widgets/multiple_item_drop_down_menu.dart';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
import 'package:test_sa/providers/lookups/classification_lookup_provider.dart';
import 'package:test_sa/providers/lookups/recommendation_lookup_provider.dart';
import 'package:test_sa/providers/lookups/request_type_lookup_provider.dart';
import 'package:test_sa/views/widgets/equipment/asset_picker.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
class UpdateTrafRequestPage extends StatefulWidget {
static const String id = "/update-TRAF";
UpdateTrafRequestPage({Key? key}) : super(key: key);
@override
_UpdateTrafRequestPageState createState() {
return _UpdateTrafRequestPageState();
}
}
class _UpdateTrafRequestPageState extends State<UpdateTrafRequestPage> {
Lookup? requestType;
Lookup? assessorRecommendation;
Lookup? classificationType;
late TrafRequestProvider trafRequestProvider;
late TrafRequestDataModel trafRequest;
List<Lookup> abc = [];
List<Asset> _deviceList = [];
Asset? asset;
List<GenericAttachmentModel> attachments = [];
@override
void initState() {
super.initState();
Provider.of<ClassificationLookupProvider>(context, listen: false).reset();
Provider.of<RecommendationLookupProvider>(context, listen: false).reset();
trafRequestProvider = Provider.of<TrafRequestProvider>(context, listen: false);
trafRequest = trafRequestProvider.trafRequestDataModel!;
attachments = trafRequest.attachments?.map((item) => GenericAttachmentModel(id: item.id, name: item.attachmentName)).toList() ?? [];
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const DefaultAppBar(title: "Update TRAF Request"),
body: Column(
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleItemDropDownMenu<Lookup, ClassificationLookupProvider>(
context: context,
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
title: "Classification",
initialValue: classificationType,
onSelect: (value) {
classificationType = value;
// trafRequest?.cla = value?.value;
// setState(() {});
},
),
12.height,
SingleItemDropDownMenu<Lookup, RequestTypeLookupProvider>(
context: context,
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
title: context.translation.requestType,
initialValue: requestType,
onSelect: (value) {
requestType = value;
setState(() {});
},
),
if (requestType?.id == 732) ...[
12.height,
AppTextFormField(
initialValue: "",
makeMultiLinesNull: true,
labelText: "Recommended Quantity",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
textInputType: TextInputType.number,
onChange: (value) {
trafRequest.qty = int.tryParse(value);
},
),
],
if (requestType?.id == 733) ...[
12.height,
AssetPicker(
device: asset,
editable: false,
showLoading: false,
// borderColor: AppColor.black20,
// backgroundColor: AppColor.white936,
onPick: (asset) async {
this.asset = asset;
setState(() {});
// pendingAssetServiceRequest = null;
// _serviceRequest.device = asset;
// await checkAssetForPendingServiceRequest(asset.id!.toInt());
// if (pendingAssetServiceRequest != null && pendingAssetServiceRequest!.details!.isNotEmpty) {
// showPendingRequestBottomSheet();
// }
},
),
],
// 12.height,
// MultipleItemDropDownMenu<Lookup, RequestTypeLookupProvider>(
// context: context,
// showAsBottomSheet: true,
// backgroundColor: AppColor.neutral100,
// showShadow: false,
// showCancel: true,
// title: "Please specify departments and relations",
// initialValue: abc,
// onSelect: (value) {
// abc = value ?? [];
// // setState(() {
// //
// // });
// },
// ),
12.height,
Text(
"Quantity to be Transfer",
style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, fontWeight: FontWeight.w500),
),
8.height,
AssetPicker(
deviceList: _deviceList,
showLoading: false,
borderColor: AppColor.black20,
buttonColor: AppColor.white936,
multiSelection: true,
onAssetRemove: (itemId) {
_deviceList.removeWhere((asset) => asset.id?.toInt() == itemId);
setState(() {});
},
onMultiAssetPick: (assetList) {
_deviceList.addAll(assetList);
final seenIds = <num?>{};
_deviceList = _deviceList.where((item) => seenIds.add(item.id)).toList();
setState(() {});
},
),
12.height,
SingleItemDropDownMenu<Lookup, RecommendationLookupProvider>(
context: context,
showAsBottomSheet: true,
backgroundColor: AppColor.neutral100,
showShadow: false,
title: "Assessor Recommendation",
initialValue: assessorRecommendation,
onSelect: (value) {
assessorRecommendation = value;
trafRequest?.requestTypeId = value?.value;
// trafRequest?.requestTypeId = value?.value;
// setState(() {});
},
),
12.height,
AppTextFormField(
initialValue: "",
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
labelText: "Assessor comment",
backgroundColor: AppColor.fieldBgColor(context),
labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)),
showShadow: false,
onChange: (value) {
trafRequest?.comment = value; // todo confirm parameter shaheer
},
),
12.height,
AttachmentPicker(
label: context.translation.attachFiles,
attachment: attachments,
buttonColor: AppColor.black10,
onlyImages: false,
buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.neutral120),
onChange: (attachment) {
attachments = attachment;
},
),
],
).toShadowContainer(context, borderRadius: 20, padding: 12),
).expanded,
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
buttonColor: AppColor.primary10,
label: "Update",
onPressed: () {
trafRequest.attachments = [];
for (var item in attachments) {
String fileName =
ServiceRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? '';
trafRequest.attachments!.add(
Attachments(id: item.id, trafId: item.id, attachmentName: fileName),
);
}
}
// buttonColor: AppColor.primary10,
),
),
],
));
}
}

@ -0,0 +1,134 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/oracle_code_provider.dart';
import 'package:test_sa/controllers/providers/api/parts_provider.dart';
import 'package:test_sa/controllers/providers/api/search_user_provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/setting_provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/asset_nd_auto_complete_by_dynamic_codes_model.dart';
import 'package:test_sa/models/new_models/users_based_on_search_model.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 '../../../models/service_request/spare_parts.dart';
import '../../../new_views/app_style/app_text_style.dart';
class SearchUserAutoCompleteField extends StatefulWidget {
final String initialValue;
final num? assetId;
final bool clearAfterPick, byName;
final Function(UsersBasedOnSearchModel) onPick;
const SearchUserAutoCompleteField({Key? key, required this.byName, required this.initialValue, this.assetId, required this.onPick, this.clearAfterPick = true}) : super(key: key);
@override
_UsersAutoCompleteFieldState createState() => _UsersAutoCompleteFieldState();
}
class _UsersAutoCompleteFieldState extends State<SearchUserAutoCompleteField> {
late UserSearchProvider _TechnologyUsersProvider;
late TextEditingController _controller;
bool loading = false;
@override
void initState() {
_controller = TextEditingController(text: widget.initialValue);
super.initState();
_TechnologyUsersProvider = Provider.of<UserSearchProvider>(context, listen: false);
}
@override
void didUpdateWidget(covariant SearchUserAutoCompleteField 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) {
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<UsersBasedOnSearchModel>(
optionsBuilder: (TextEditingValue textEditingValue) async {
if (textEditingValue.text.isEmpty) {
if (loading) {
setState(() {
loading = false;
});
}
return const Iterable<UsersBasedOnSearchModel>.empty();
}
if (!loading) {
setState(() {
loading = true;
});
}
List<UsersBasedOnSearchModel> workOrders = (await _TechnologyUsersProvider.getUsersBasedOnSearch(textEditingValue.text));
setState(() {
loading = false;
});
return workOrders;
},
displayStringForOption: (UsersBasedOnSearchModel option) => widget.byName ? option.userName ?? "" : option.employeeId ?? "",
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(maxHeight: 24, maxWidth: 24 + 8),
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: "Users going to use technology",
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
suffixIcon: loading ? const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3.0).paddingOnly(end: 8) : null,
),
textInputAction: TextInputAction.search,
onChanged: (text) {
fieldTextEditingController.text = text;
},
onSubmitted: (String value) {
onFieldSubmitted();
},
);
},
onSelected: (UsersBasedOnSearchModel selection) {
if (widget.clearAfterPick) {
_controller.clear();
} else {
_controller.text = widget.byName ? (selection.userName ?? "") : (selection.employeeId ?? "");
}
widget.onPick(selection);
},
),
);
}
}

@ -25,6 +25,7 @@ class AppTextFormField extends StatefulWidget {
final TextStyle? style;
final TextStyle? labelStyle;
final TextStyle? hintStyle;
final TextStyle? floatingLabelStyle;
final bool enable;
final TextAlign? textAlign;
final FocusNode? node;
@ -58,6 +59,7 @@ class AppTextFormField extends StatefulWidget {
this.hintText,
this.labelText,
this.hintStyle,
this.floatingLabelStyle,
this.textInputType = TextInputType.text,
this.initialValue, // Provide default value
this.enable = true,
@ -183,12 +185,16 @@ class _AppTextFormFieldState extends State<AppTextFormField> {
onChanged: widget.onChange,
obscureText: widget.obscureText ?? false,
keyboardType: widget.textInputType,
maxLines: widget.makeMultiLinesNull ? null:widget.textInputType == TextInputType.multiline ? 4 : 1,
maxLines: widget.makeMultiLinesNull
? null
: widget.textInputType == TextInputType.multiline
? 4
: 1,
obscuringCharacter: "*",
controller: widget.controller,
textInputAction: widget.textInputType == TextInputType.multiline ? null : widget.textInputAction ?? TextInputAction.next,
onEditingComplete: widget.onAction ?? () => FocusScope.of(context).nextFocus(),
style: widget.style ?? AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500,color:context.isDark?AppColor.white10: AppColor.black10),
style: widget.style ?? AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.white10 : AppColor.black10),
onTap: widget.onTap,
decoration: InputDecoration(
alignLabelWithHint: widget.alignLabelWithHint,
@ -208,9 +214,12 @@ class _AppTextFormFieldState extends State<AppTextFormField> {
? (widget.enableColor ?? AppColor.neutral40)
: AppColor.background(context)),
errorStyle: AppTextStyle.tiny.copyWith(color: context.isDark ? AppColor.red50 : AppColor.red60),
floatingLabelStyle: AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.white10 : AppColor.neutral20),
floatingLabelStyle: widget.floatingLabelStyle ?? AppTextStyle.body1.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.white10 : AppColor.neutral20),
hintText: widget.hintText ?? "",
labelText: (widget.showSpeechToText && _speechToText.isListening) ? "Listening..." : widget.labelText ?? "",
// labelText: (widget.showSpeechToText && _speechToText.isListening) ? "Listening..." : widget.labelText ?? "",
label: Text(
(widget.showSpeechToText && _speechToText.isListening) ? "Listening..." : widget.labelText ?? "",
),
labelStyle: widget.labelStyle,
hintStyle: widget.labelStyle,
prefixIcon: widget.prefixIcon ??

@ -0,0 +1,252 @@
import 'package:flutter/cupertino.dart';
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/widget_extensions.dart';
import 'package:test_sa/new_views/common_widgets/app_loading_manager.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/views/widgets/bottom_sheets/selection_bottom_sheet.dart';
import 'package:test_sa/views/widgets/fullscreen_dialogs/multiple_selection_fullscreen_dialog.dart';
import 'package:test_sa/views/widgets/fullscreen_dialogs/selection_fullscreen_dialog.dart';
import '../../models/base.dart';
import '../app_style/app_color.dart';
class MultipleItemDropDownMenu<T extends Base, X extends LoadingListNotifier> extends StatefulWidget {
final BuildContext context;
final Function(List<T>?)? onSelect; // Now accepts nullable values
final List<T> initialValue;
final T? disableValue;
final bool enabled;
final bool showAsBottomSheet;
final bool showAsFullScreenDialog;
final List<T>? staticData;
final String title;
final double? height;
final bool showShadow;
final bool showCancel;
final Color? backgroundColor; // Now nullable
final bool? loading; // Now nullable
final int? requestById; // Now nullable
/// To use a static data (without calling API)
/// just send [NullableLoadingProvider] as generic data type and fill the [staticData]
const MultipleItemDropDownMenu({
Key? key,
this.title = "",
required this.context,
this.onSelect,
this.initialValue = const [],
this.disableValue,
this.enabled = true,
this.height,
this.showAsBottomSheet = false,
this.showAsFullScreenDialog = true,
this.staticData, // Provide a default empty list
this.showShadow = true,
this.showCancel = false,
this.backgroundColor,
this.loading,
this.requestById,
}) : super(key: key);
@override
State<MultipleItemDropDownMenu<T, X>> createState() => _MultipleItemDropDownMenuState<T, X>();
}
class _MultipleItemDropDownMenuState<T extends Base, X extends LoadingListNotifier> extends State<MultipleItemDropDownMenu<T, X>> {
List<T> _selectedItem = [];
X? provider;
@override
void initState() {
if (X != NullableLoadingProvider) {
provider = Provider.of<X>(widget.context);
}
if (widget.initialValue.isNotEmpty) {
// Get the source list
final sourceList = (X == NullableLoadingProvider ? widget.staticData : provider?.items);
if (sourceList != null && sourceList.isNotEmpty) {
// Collect matches based on identifier
final results = sourceList.where((element) => widget.initialValue!.any((init) => init.name == element.name)).toList();
if (results.isNotEmpty) {
_selectedItem
..clear()
..addAll(results.cast<T>());
// Call onSelect if items changed
if (widget.onSelect != null) {
widget.onSelect!(_selectedItem);
}
}
}
}
// if (widget.initialValue != null) {
// final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier);
// if (result?.isNotEmpty ?? false) _selectedItem.add(result!.first as T);
// if (widget.onSelect != null && (widget.initialValue?.identifier ?? "") != (_selectedItem?.identifier ?? "")) {
// widget.onSelect!(_selectedItem); // Non-null assertion after null check
// }
// }
super.initState();
}
@override
void setState(VoidCallback fn) {
if (mounted) super.setState(fn);
}
@override
void didUpdateWidget(covariant MultipleItemDropDownMenu<T, X> oldWidget) {
if (widget.initialValue.isNotEmpty) {
// Get the source list
final sourceList = (X == NullableLoadingProvider ? widget.staticData : provider?.items);
if (sourceList != null && sourceList.isNotEmpty) {
// Collect matches based on identifier
final results = sourceList.where((element) => widget.initialValue!.any((init) => init.name == element.name)).toList();
if (results.isNotEmpty) {
_selectedItem
..clear()
..addAll(results.cast<T>());
// Call onSelect if items changed
if (widget.onSelect != null) {
widget.onSelect!(_selectedItem);
}
}
}
}
// if (widget.initialValue != null) {
// final result = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.where((element) => element.identifier == widget.initialValue?.identifier);
//
// if (result?.isNotEmpty ?? false) {
// _selectedItem.add(result!.first as T);
// } else {
// _selectedItem = [];
// }
// // if (widget.onSelect != null && (widget.initialValue?.identifier ?? "") != (_selectedItem?.identifier ?? "")) {
// // widget.onSelect!(_selectedItem); // Non-null assertion after null check
// // }
// } else {
// _selectedItem = [];
// }
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
final isEmpty = (X == NullableLoadingProvider ? widget.staticData : provider?.items)?.isEmpty ?? true;
return AppLoadingManager(
isLoading: widget.loading ?? ((X == NullableLoadingProvider) ? false : provider?.loading ?? false),
// Provide default value if null
isFailedLoading: (X == NullableLoadingProvider) ? false : provider?.items == null,
stateCode: (X == NullableLoadingProvider) ? 200 : provider?.stateCode,
onRefresh: () async {
if (X != NullableLoadingProvider) {
provider?.reset();
await provider?.getData(id: widget.requestById);
}
},
child: Container(
// height: widget.height ?? 60.toScreenHeight,
padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight),
decoration: BoxDecoration(
color: context.isDark && (widget.enabled == false || isEmpty)
? AppColor.neutral20
: (widget.enabled == false || isEmpty)
? AppColor.neutral40
: widget.backgroundColor ?? AppColor.background(context),
borderRadius: BorderRadius.circular(10),
boxShadow: widget.showShadow ? [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)] : null,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Text(
widget.title,
style: Theme.of(context).textTheme.bodySmall?.copyWith(color: context.isDark ? null : AppColor.neutral20, fontWeight: FontWeight.w500),
),
if (_selectedItem.isEmpty)
Text(
context.translation.select,
style: Theme.of(context).textTheme.bodyLarge,
)
else
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.only(top: 8),
separatorBuilder: (cxt, index) => const Divider(
thickness: 1,
color: Colors.white,
),
itemBuilder: (cxt, index) => Text(
_selectedItem[index].name ?? "", // Null-aware operator for value.name
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w500, color: context.isDark ? AppColor.white10 : AppColor.black10),
),
itemCount: _selectedItem.length,
),
],
)
.onPress(
widget.enabled && widget.showAsFullScreenDialog
? () {
openDialog();
}
: null,
)
.expanded,
if (widget.enabled) const PositionedDirectional(end: 0, child: Icon(Icons.keyboard_arrow_down_rounded)),
],
),
),
);
}
void openDialog() async {
Widget child = MultipleSelectionFullScreenDialog<T>(
// Specify generic type
items: ((X == NullableLoadingProvider) ? widget.staticData : provider?.items as List<T>) ?? [],
// Provide default empty list if null
selectedItem: _selectedItem,
disableItem: widget.disableValue,
title: widget.title,
showCancel: widget.showCancel,
onSelect: (selectedT) {
setState(() {
_selectedItem = selectedT;
});
widget.onSelect!(selectedT);
},
builderString: (emp) => emp?.name ?? "", // Null-aware operator for emp.name
);
pushRouter(child);
// final selectedT = await pushRouter(child);
// if (selectedT != null) {
// setState(() {
// _selectedItem = selectedT;
// });
// widget.onSelect!(selectedT); // Non-null assertion after null check
// }
}
Future<T?> pushRouter(Widget child) async {
// PageRoute<T> pRoute = !Platform.isIOS ? CupertinoPageRoute(fullscreenDialog: true, builder: (context) => child) : MaterialPageRoute(fullscreenDialog: true, builder: (context) => child);
return await Navigator.of(context).push(CupertinoPageRoute(fullscreenDialog: true, builder: (context) => child));
}
}

@ -27,6 +27,7 @@ class SingleItemDropDownMenu<T extends Base, X extends LoadingListNotifier> exte
final bool showCancel;
final Color? backgroundColor; // Now nullable
final bool? loading; // Now nullable
final int? requestById;
/// To use a static data (without calling API)
/// just send [NullableLoadingProvider] as generic data type and fill the [staticData]
@ -46,6 +47,7 @@ class SingleItemDropDownMenu<T extends Base, X extends LoadingListNotifier> exte
this.showCancel = false,
this.backgroundColor,
this.loading,
this.requestById,
}) : super(key: key);
@override
@ -106,7 +108,7 @@ class _SingleItemDropDownMenuState<T extends Base, X extends LoadingListNotifier
onRefresh: () async {
if (X != NullableLoadingProvider) {
provider?.reset();
await provider?.getData();
await provider?.getData(id: widget.requestById);
}
},
child: Container(
@ -168,50 +170,50 @@ class _SingleItemDropDownMenuState<T extends Base, X extends LoadingListNotifier
),
);
}).toList(),
).onPress(widget.enabled && widget.showAsFullScreenDialog
? () {
openDialog();
}
: widget.enabled
? (widget.showAsBottomSheet
? () async {
final selectedT = await showModalBottomSheet<T?>(
// Specify return type
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
builder: (BuildContext context) => SelectionBottomSheet<T>(
// Specify generic type
items: ((X == NullableLoadingProvider) ? widget.staticData : provider?.items as List<T>) ?? [],
// Provide default empty list if null
selectedItem: _selectedItem,
title: widget.title,
showCancel: widget.showCancel,
onSelect: (selectedT) {
setState(() {
_selectedItem = selectedT;
});
widget.onSelect!(selectedT);
},
builderString: (emp) => emp?.name ?? "", // Null-aware operator for emp.name
),
);
// if (selectedT != null) {
// setState(() {
// _selectedItem = selectedT;
// });
// widget.onSelect!(selectedT); // Non-null assertion after null check
// }
}
: null)
: null),
),
],
),
).onPress(widget.enabled && widget.showAsFullScreenDialog
? () {
openDialog();
}
: widget.enabled
? (widget.showAsBottomSheet
? () async {
final selectedT = await showModalBottomSheet<T?>(
// Specify return type
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
builder: (BuildContext context) => SelectionBottomSheet<T>(
// Specify generic type
items: ((X == NullableLoadingProvider) ? widget.staticData : provider?.items as List<T>) ?? [],
// Provide default empty list if null
selectedItem: _selectedItem,
title: widget.title,
showCancel: widget.showCancel,
onSelect: (selectedT) {
setState(() {
_selectedItem = selectedT;
});
widget.onSelect!(selectedT);
},
builderString: (emp) => emp?.name ?? "", // Null-aware operator for emp.name
),
);
// if (selectedT != null) {
// setState(() {
// _selectedItem = selectedT;
// });
// widget.onSelect!(selectedT); // Non-null assertion after null check
// }
}
: null)
: null),
],
),
),

@ -3,21 +3,22 @@ import 'package:provider/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/models/enums/user_types.dart';
import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart';
import 'package:test_sa/modules/traf_module/create_traf_request_page.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/pages/gas_refill_request_form.dart';
import 'package:test_sa/views/pages/device_transfer/create__device_transfer_request.dart';
class CreateRequestTypeBottomSheet extends StatelessWidget {
final bool isEngineer;
const CreateRequestTypeBottomSheet({super.key, required this.isEngineer});
const CreateRequestTypeBottomSheet({super.key});
@override
Widget build(BuildContext context) {
List<CreateRequestModel> requestList = CreateRequestModel.requestsList(context, isEngineer);
List<CreateRequestModel> requestList = CreateRequestModel.requestsList(context);
return SafeArea(
top: false,
@ -87,9 +88,12 @@ class CreateRequestModel {
CreateRequestModel(this.title, this.icon, this.routeName);
static List<CreateRequestModel> requestsList(BuildContext context, bool isEngineer) {
static List<CreateRequestModel> requestsList(BuildContext context) {
List<CreateRequestModel> list = [];
if (isEngineer) {
if (context.userProvider.isAssessor) {
list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id));
} else if (context.userProvider.isEngineer) {
if (Provider.of<SettingProvider>(context, listen: false).engineerCanCreateCM) {
list.add(CreateRequestModel(context.translation.correctiveMaintenance, "add_icon", CreateNewRequest.id));
}
@ -101,6 +105,7 @@ class CreateRequestModel {
list.add(CreateRequestModel(context.translation.transferAsset, "add_icon", CreateDeviceTransferRequest.id));
//TODO uncommit this to enable task.
list.add(CreateRequestModel(context.translation.task, "add_icon", CreateTaskView.id));
list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id));
}
return list;
}

@ -161,13 +161,12 @@ class _LandPageState extends State<LandPage> {
: AppBottomNavigationBar(
selectedIndex: currentPageIndex,
onPressed: (index) {
bool isEngineer = _userProvider!.user!.type == UsersTypes.engineer;
if (index == 2) {
showModalBottomSheet(
context: context,
useSafeArea: true,
backgroundColor: Colors.white,
builder: (context) => CreateRequestTypeBottomSheet(isEngineer: isEngineer),
builder: (context) => CreateRequestTypeBottomSheet(),
);
} else if (index == 4) {
showModalBottomSheet(

@ -61,7 +61,7 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
);
search!.searchBySelectedValue = search?.requestNumber;
}
final types = {
var types = {
context.translation.correctiveMaintenance: 1,
context.translation.gasRefill: 2,
context.translation.transferAsset: 3,
@ -76,6 +76,14 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
if (context.settingProvider.isUserFlowMedical && isEngineer) {
types['Recall and Alert'] = 7;
}
if (!isEngineer) {
types['TRAF'] = 9;
}
if (context.userProvider.isAssessor) {
types = {"TRAF": 9};
}
final statuses = {
"All WO": 0,
context.translation.open: 1,

@ -55,6 +55,16 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
if (Provider.of<UserProvider>(context, listen: false).user!.type != UsersTypes.normal_user) {
requestsList.add(Request(8, 'Inventory Session'.addTranslation));
}
if (context.userProvider.user!.type == UsersTypes.normal_user) {
requestsList.add(Request(9, 'TRAF'));
}
if (context.userProvider.isAssessor) {
requestsList = [
Request(null, context.translation.allWorkOrder),
Request(9, 'TRAF'),
];
}
_provider = Provider.of<AllRequestsProvider>(context, listen: false);
_provider!.reset();
WidgetsBinding.instance.addPostFrameCallback((_) {

@ -21,9 +21,7 @@ class GasRefillItemView extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (requestData != null) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -144,6 +142,6 @@ class GasRefillItemView extends StatelessWidget {
});
}
return const SizedBox();
return const SizedBox();
}
}

@ -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/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';
import 'package:test_sa/new_views/pages/land_page/requests/device_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart';
@ -63,6 +64,8 @@ class RequestPaginatedListview extends StatelessWidget {
return TaskRequestItemView(requestData: request);
case 8:
return InventorySessionItemView(requestData: request);
case 9:
return TrafRequestItemView(requestData: request);
default:
return Container(
height: 100,

@ -6,6 +6,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/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/pages/land_page/requests/device_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/gas_refill_item_view.dart';
import 'package:test_sa/new_views/pages/land_page/requests/ppm_item_view.dart';
@ -43,8 +44,10 @@ class RequestItemViewList extends StatelessWidget {
return TaskRequestItemView(requestDetails: list[index]);
case 7:
return TaskRequestItemView(requestDetails: list[index]);
case 8:
case 8:
return InventorySessionItemView(requestDetails: list[index]);
case 9:
return TrafRequestItemView(requestDetails: list[index]);
default:
Container(
height: 100,

@ -9,7 +9,7 @@ import '../loading_list_notifier.dart';
class AssetTransferStatusProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import 'loading_list_notifier.dart';
class DepartmentProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../loading_list_notifier.dart';
class CylinderSizeProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../loading_list_notifier.dart';
class CylinderTypesProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../loading_list_notifier.dart';
class GasStatusProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../../controllers/api_routes/urls.dart';
class GasTypesProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -10,7 +10,7 @@ import '../../controllers/api_routes/urls.dart';
class SiteProvider extends LoadingListNotifier<Site> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();
@ -35,7 +35,7 @@ class SiteProvider extends LoadingListNotifier<Site> {
class MappedSiteProvider extends LoadingListNotifier<MappedSite> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -3,7 +3,7 @@ import 'package:test_sa/models/base.dart';
class NullableLoadingProvider extends LoadingListNotifier<Base> {
@override
Future getData() {
Future getData({int? id}) {
return Future.value();
}
}
@ -28,5 +28,5 @@ abstract class LoadingListNotifier<T extends Base> extends ChangeNotifier {
stateCode = null;
}
Future getData();
Future getData({int? id});
}

@ -0,0 +1,33 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import '../../controllers/api_routes/api_manager.dart';
import '../../controllers/api_routes/urls.dart';
import '../../models/lookup.dart';
class ClassificationLookupProvider extends LoadingListNotifier<Lookup> {
@override
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();
try {
Response response = await ApiManager.instance.get(URLs.getClassificationTypeLookup);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
List categoriesListJson = json.decode(response.body)["data"];
items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
}
loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
loading = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -0,0 +1,34 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:test_sa/models/new_models/traf_department.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import '../../controllers/api_routes/api_manager.dart';
import '../../controllers/api_routes/urls.dart';
import '../../models/lookup.dart';
class DepartmentLookupProvider extends LoadingListNotifier<TrafDepartment> {
@override
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();
try {
Response response = await ApiManager.instance.get(URLs.getDepartmentBasedOnSite + "?customerId=$id");
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
List categoriesListJson = json.decode(response.body)["data"];
items = categoriesListJson.map((item) => TrafDepartment.fromJson(item)).toList();
}
loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
loading = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -0,0 +1,33 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import '../../controllers/api_routes/api_manager.dart';
import '../../controllers/api_routes/urls.dart';
import '../../models/lookup.dart';
class RecommendationLookupProvider extends LoadingListNotifier<Lookup> {
@override
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();
try {
Response response = await ApiManager.instance.get(URLs.getRecommendationTypeLookup);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
List categoriesListJson = json.decode(response.body)["data"];
items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
}
loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
loading = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -0,0 +1,33 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import '../../controllers/api_routes/api_manager.dart';
import '../../controllers/api_routes/urls.dart';
import '../../models/lookup.dart';
class RequestTypeLookupProvider extends LoadingListNotifier<Lookup> {
@override
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();
try {
Response response = await ApiManager.instance.get(URLs.getTrafRequestTypeLookup);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
List categoriesListJson = json.decode(response.body)["data"];
items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
}
loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
loading = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -0,0 +1,33 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:test_sa/providers/loading_list_notifier.dart';
import '../../controllers/api_routes/api_manager.dart';
import '../../controllers/api_routes/urls.dart';
import '../../models/lookup.dart';
class YesNoLookupProvider extends LoadingListNotifier<Lookup> {
@override
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();
try {
Response response = await ApiManager.instance.get(URLs.getYesNoRequestTypeLookup);
stateCode = response.statusCode;
if (response.statusCode >= 200 && response.statusCode < 300) {
List categoriesListJson = json.decode(response.body)["data"];
items = categoriesListJson.map((item) => Lookup.fromJson(item)).toList();
}
loading = false;
notifyListeners();
return response.statusCode;
} catch (error) {
loading = false;
stateCode = -1;
notifyListeners();
return -1;
}
}
}

@ -9,7 +9,7 @@ import 'loading_list_notifier.dart';
class PpmAssetAvailabilityProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import 'loading_list_notifier.dart';
class PpmChecklistStatusProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import 'loading_list_notifier.dart';
class PPMDeviceStatusProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import 'loading_list_notifier.dart';
class PpmElectricalSafetyProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import 'loading_list_notifier.dart';
class PpmServiceProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import 'loading_list_notifier.dart';
class PpmTaskStatusProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import 'loading_list_notifier.dart';
class PPMVisitStatusProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading ?? false) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../../models/lookup.dart';
class CommissioningStatusProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../../models/lookup.dart';
class EquipmentStatusProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../../models/lookup.dart';
class FirstActionStatusProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../../models/lookup.dart';
class LastSituationProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../../models/lookup.dart';
class LoanAvailabilityProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;

@ -9,7 +9,7 @@ import '../../models/lookup.dart';
class PriorityProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -10,7 +10,7 @@ import '../../models/lookup.dart';
class RejectReasonProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../../models/lookup.dart';
class RequestedThroughProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../../models/lookup.dart';
class TypeOfRequestProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;

@ -11,7 +11,7 @@ import '../../controllers/api_routes/urls.dart';
class TaskTypeProvider extends LoadingListNotifier<TaskType> {
@override
Future getData() async {
Future getData({int? id}) async {
print('get data called...');
if (loading == true) return -2;
loading = true;
@ -39,7 +39,7 @@ class TaskTypeProvider extends LoadingListNotifier<TaskType> {
}
class TaskEvaluatorUserProvider extends LoadingListNotifier<TaskEvaluatorUser> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();
@ -65,7 +65,7 @@ class TaskEvaluatorUserProvider extends LoadingListNotifier<TaskEvaluatorUser> {
class TaskJobTypeOfAlertProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();
@ -90,7 +90,7 @@ class TaskJobTypeOfAlertProvider extends LoadingListNotifier<Lookup> {
}
class TaskJobRiskLevelProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();
@ -115,7 +115,7 @@ class TaskJobRiskLevelProvider extends LoadingListNotifier<Lookup> {
}
class TaskJobResourceProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();
@ -140,7 +140,7 @@ class TaskJobResourceProvider extends LoadingListNotifier<Lookup> {
}
class TaskJobActionNeededProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();
@ -165,7 +165,7 @@ class TaskJobActionNeededProvider extends LoadingListNotifier<Lookup> {
}
class TaskJobImpactStatusProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -10,7 +10,7 @@ import '../../models/lookup.dart';
class ActivityStatusProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../../models/lookup.dart';
class NeedVisitReminderTimeProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -11,7 +11,7 @@ class ReasonProvider extends LoadingListNotifier<Lookup> {
String? serviceRequestId;
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -12,7 +12,7 @@ class RetirementTypeProvider extends LoadingListNotifier<Lookup> {
String? serviceRequestId;
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
print('get data called...');
loading = true;

@ -9,7 +9,7 @@ import '../../models/lookup.dart';
class ServiceTypeProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -8,7 +8,7 @@ import 'package:test_sa/providers/loading_list_notifier.dart';
class SupplierEngineerProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -8,7 +8,7 @@ import 'package:test_sa/providers/loading_list_notifier.dart';
class VendorProvider extends LoadingListNotifier<SupplierDetails> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -9,7 +9,7 @@ import '../../models/lookup.dart';
class WoFrameProvider extends LoadingListNotifier<Lookup> {
@override
Future getData() async {
Future getData({int? id}) async {
if (loading == true) return -2;
loading = true;
notifyListeners();

@ -0,0 +1,172 @@
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/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/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
typedef SelectionBuilderString = String Function(dynamic);
class MultipleSelectionBottomSheet<T> extends StatefulWidget {
final List<T>? items;
final List<T> selectedItem; // Now nullable
final String title;
final SelectionBuilderString builderString;
final bool showCancel;
final Function(List<T>) onSelect;
const MultipleSelectionBottomSheet({Key? key, this.items = const [], this.selectedItem = const [], this.title = "", required this.builderString, this.showCancel = false, required this.onSelect})
: super(key: key);
@override
_MultipleSelectionBottomSheetState createState() => _MultipleSelectionBottomSheetState<T>();
}
class _MultipleSelectionBottomSheetState<T> extends State<MultipleSelectionBottomSheet<T>> {
late List<T> _selectedValue; // Now nullable
String query = "";
List<T>? get filteredList => widget.items?.where((element) => widget.builderString(element).toLowerCase().contains(query.toLowerCase())).toList();
@override
void initState() {
_selectedValue = widget.selectedItem;
super.initState();
}
FocusNode searchFocusNode = FocusNode();
@override
void dispose() {
searchFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height * .7,
color: Theme.of(context).scaffoldBackgroundColor,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
widget.title.heading5(context).expanded,
if (widget.showCancel)
AnimatedOpacity(
opacity: _selectedValue != null ? 1 : 0,
duration: const Duration(milliseconds: 250),
child: Container(
height: 30,
decoration: BoxDecoration(color: const Color(0xffF63939).withOpacity(.75), borderRadius: BorderRadius.circular(30)),
padding: const EdgeInsets.only(left: 8, right: 12, top: 4, bottom: 4),
alignment: Alignment.center,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.clear, color: Colors.white, size: 16),
4.width,
const Text(
"Clear",
style: TextStyle(fontSize: 14, color: Colors.white),
)
],
),
).onPress(_selectedValue.isNotEmpty
? () {
Navigator.pop(context);
widget.onSelect([]);
}
: null),
),
],
).paddingOnly(top: 16, start: 16, end: 16, bottom: 0),
TextField(
onChanged: (queryString) {
query = queryString;
setState(() {});
},
style: const TextStyle(fontSize: 14),
focusNode: searchFocusNode,
decoration: InputDecoration(
hintText: 'Search by name',
labelText: 'Search',
labelStyle: TextStyle(color: AppColor.textColor(context)),
filled: true,
fillColor: AppColor.fieldBgColor(context),
hintStyle: const TextStyle(fontSize: 14),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: AppColor.blueStatus(context), width: 2.0),
borderRadius: const BorderRadius.all(Radius.circular(12.0)),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: AppColor.blueStatus(context), width: 1.0),
borderRadius: const BorderRadius.all(Radius.circular(12.0)),
),
contentPadding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
),
).paddingOnly(top: 16, start: 16, end: 16, bottom: 16),
Expanded(
// Wrap ListView with Expanded
child: ListView.builder(
itemCount: filteredList?.length,
padding: EdgeInsets.zero,
itemBuilder: (cxt, index) => Theme(
data: Theme.of(context).copyWith(
radioTheme: RadioThemeData(
fillColor: MaterialStateColor.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return AppColor.textColor(context); // Active color
}
return Colors.grey; // Inactive color
}),
),
),
child: CheckboxListTile(
value: checkItContains(filteredList![index]),
dense: true,
// groupValue: _selectedValue,
activeColor: AppColor.textColor(context),
contentPadding: const EdgeInsets.only(left: 16, right: 16),
onChanged: (value) {
if (value == true) {
_selectedValue.add(filteredList![index]);
} else if (value == false) {
_selectedValue.remove(filteredList![index]);
}
searchFocusNode.unfocus();
setState(() {});
},
title: Text(
widget.builderString(filteredList![index]).cleanupWhitespace.capitalizeFirstOfEach ?? "",
style: Theme.of(context).textTheme.bodyLarge,
),
),
),
),
),
8.height,
if (_selectedValue.isNotEmpty)
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
label: context.translation.select,
maxWidth: true,
onPressed: () {
Navigator.pop(context);
widget.onSelect(_selectedValue);
},
)),
],
),
);
}
bool? checkItContains(T) {
return widget.items?.contains(T);
}
}

@ -0,0 +1,193 @@
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/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/base.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';
typedef SelectionBuilderString = String Function(dynamic);
class MultipleSelectionFullScreenDialog<T extends Base> extends StatefulWidget {
final List<T>? items;
final List<T> selectedItem; // Now nullable
final T? disableItem; // Now nullable
final String title;
final bool showCancel;
final SelectionBuilderString builderString;
final Function(List<T>) onSelect;
const MultipleSelectionFullScreenDialog(
{Key? key, this.items, this.selectedItem = const [], this.disableItem, this.title = "", required this.builderString, this.showCancel = false, required this.onSelect})
: super(key: key);
@override
_SelectionBottomSheetState createState() => _SelectionBottomSheetState<T>();
}
class _SelectionBottomSheetState<T extends Base> extends State<MultipleSelectionFullScreenDialog<T>> {
late List<T> _selectedValue; // Now nullable
String query = "";
List<T>? get filteredList => widget.items?.where((element) => widget.builderString(element).toLowerCase().contains(query.toLowerCase())).toList();
@override
void initState() {
_selectedValue = widget.selectedItem;
super.initState();
}
FocusNode searchFocusNode = FocusNode();
@override
void dispose() {
searchFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: widget.title.heading5(context),
actions: [
if (widget.showCancel)
AnimatedContainer(
height: 24,
duration: const Duration(milliseconds: 250),
margin: const EdgeInsets.only(right: 16),
decoration: BoxDecoration(color: _selectedValue.isNotEmpty ? const Color(0xffF63939).withOpacity(.75) : Colors.grey.withOpacity(.75), borderRadius: BorderRadius.circular(30)),
padding: const EdgeInsets.only(left: 4, right: 8, top: 4, bottom: 4),
alignment: Alignment.center,
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(Icons.clear, color: Colors.white, size: 16),
4.width,
const Text(
"Clear",
style: TextStyle(fontSize: 14, color: Colors.white, height: 1),
)
],
).onPress(_selectedValue.isNotEmpty
? () {
Navigator.pop(context);
widget.onSelect([]);
}
: null),
),
],
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SearchBar(
focusNode: searchFocusNode,
elevation: WidgetStateProperty.all<double>(0),
backgroundColor: WidgetStateProperty.all<Color?>(context.isDark ? AppColor.neutral120 : null),
leading: Icon(Icons.search, color: AppColor.iconColor(context)),
textStyle: WidgetStateProperty.all<TextStyle>(
TextStyle(color: AppColor.textColor(context), fontSize: 16.0),
),
hintStyle: WidgetStateProperty.all<TextStyle>(
TextStyle(color: AppColor.textColor(context), fontSize: 14.0),
),
hintText: 'Search by name',
onChanged: (queryString) {
query = queryString;
setState(() {});
},
).paddingOnly(top: 16, start: 16, end: 16, bottom: 8),
// TextField(
// onChanged: (queryString) {
// query = queryString;
// setState(() {});
// },
// style: const TextStyle(fontSize: 14),
// focusNode: searchFocusNode,
// decoration: InputDecoration(
// hintText: 'Search by name',
// labelText: 'Search',
// hintStyle: const TextStyle(fontSize: 14),
// focusedBorder: OutlineInputBorder(
// borderSide: BorderSide(color: AppColor.blueStatus(context), width: 2.0),
// borderRadius: const BorderRadius.all(Radius.circular(12.0)),
// ),
// enabledBorder: OutlineInputBorder(
// borderSide: BorderSide(color: AppColor.blueStatus(context), width: 1.0),
// borderRadius: const BorderRadius.all(Radius.circular(12.0)),
// ),
// contentPadding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
// ),
// ),
8.height,
Expanded(
child: ListView.builder(
itemCount: filteredList?.length,
padding: EdgeInsets.zero,
itemBuilder: (cxt, index) {
bool isDisabledItem = widget.disableItem != null && widget.disableItem?.identifier == filteredList![index].identifier;
return Theme(
data: Theme.of(context).copyWith(
radioTheme: RadioThemeData(
fillColor: MaterialStateColor.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return AppColor.iconColor(context); // Active color
}
return Colors.grey; // Inactive color
}),
),
),
child: CheckboxListTile(
value: checkItContains(filteredList![index]),
dense: true,
controlAffinity: ListTileControlAffinity.leading,
activeColor: AppColor.textColor(context),
contentPadding: const EdgeInsets.only(left: 16, right: 16),
onChanged: (value) {
// if (checkItContains(filteredList![index]) ?? false) {
// _selectedValue.remove(filteredList![index]);
// } else {
// _selectedValue.add(filteredList![index]);
// }
if (value == true) {
_selectedValue.add(filteredList![index]);
} else if (value == false) {
_selectedValue.remove(filteredList![index]);
}
searchFocusNode.unfocus();
setState(() {});
},
title: Text(
widget.builderString(filteredList![index]).cleanupWhitespace.capitalizeFirstOfEach ?? "",
style: Theme.of(context).textTheme.bodyLarge,
),
),
);
}),
),
8.height,
if (_selectedValue.isNotEmpty)
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
label: context.translation.select,
maxWidth: true,
onPressed: () {
Navigator.pop(context);
widget.onSelect(_selectedValue);
},
)),
],
),
);
}
bool? checkItContains(T) {
return _selectedValue.contains(T);
}
}
Loading…
Cancel
Save