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.dartdesign_3.0_GlobalHealth
commit
facf80b07e
@ -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 [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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…
Reference in New Issue