From 655f96049cb71fd230fd33093d59c42407543cf0 Mon Sep 17 00:00:00 2001 From: zaid_daoud Date: Tue, 6 Jun 2023 11:20:56 +0300 Subject: [PATCH] Fault Description Became a Dropdown Menu --- lib/controllers/api_routes/urls.dart | 1 + .../api/service_requests_provider.dart | 9 +- ...ice_report_fault_description_provider.dart | 70 +++++++++++ lib/main.dart | 2 + lib/models/fault_description.dart | 36 ++++++ lib/models/service_report.dart | 77 ++++++------ .../report/create_service_report.dart | 45 ++++--- .../status/report/fault_desc_menu.dart | 110 ++++++++++++++++++ .../service_report_fault_description.dart | 43 +++++++ 9 files changed, 324 insertions(+), 69 deletions(-) create mode 100644 lib/controllers/providers/api/status_drop_down/report/service_report_fault_description_provider.dart create mode 100644 lib/models/fault_description.dart create mode 100644 lib/views/widgets/status/report/fault_desc_menu.dart create mode 100644 lib/views/widgets/status/report/service_report_fault_description.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index be942bbc..df430e8e 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -59,6 +59,7 @@ class URLs { static get getPartNumber => "$_baseUrl/PartCatalog/GetPartAutoComplete"; // get static get getServiceReportPriority => "$_baseUrl/Lookups/GetLookup?lookupEnum=602"; // get static get getServiceReportDefectTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=601"; // get + static get getServiceReportFaultDescription => "$_baseUrl/CallRequest/GetCallRequestForWorkOrder"; // get //gas refill static get getGasTypes => "$_baseUrl/Lookups/GetLookup?lookupEnum=606"; // get diff --git a/lib/controllers/providers/api/service_requests_provider.dart b/lib/controllers/providers/api/service_requests_provider.dart index ee264d1d..8f947e45 100644 --- a/lib/controllers/providers/api/service_requests_provider.dart +++ b/lib/controllers/providers/api/service_requests_provider.dart @@ -294,7 +294,7 @@ class ServiceRequestsProvider extends ChangeNotifier { "id": request.id, }, "assetType": report.assetType?.toMap(), - // "assignedEmployee": {"id": report.engineer?.id, "name": report.engineer?.name ?? ""}, + "assignedEmployee": {"id": report.engineer?.id, "name": report.engineer?.name ?? ""}, "visitDate": report.visitDate?.toIso8601String() ?? "", // "assistantEmployees": [ // {"id": report.engineer.id, "name": report.engineer.name}, @@ -322,12 +322,7 @@ class ServiceRequestsProvider extends ChangeNotifier { "workingHours": report.timer?.durationInSecond, "travelingHours": report.travelingHours, "travelingExpenses": report.travelingExpense ?? 0, - "faultDescription": { - "id": report.faultDescriptionId, - "defectName": report.type?.name, - "workPerformed": report.workPreformed, - "estimatedTime": report.operatingHours, - }, + if (report.faultDescription != null) "faultDescription": report.faultDescription.toJson(), "sparePartsWorkOrders": report.parts ?.map( (p) => { diff --git a/lib/controllers/providers/api/status_drop_down/report/service_report_fault_description_provider.dart b/lib/controllers/providers/api/status_drop_down/report/service_report_fault_description_provider.dart new file mode 100644 index 00000000..f50a5b1e --- /dev/null +++ b/lib/controllers/providers/api/status_drop_down/report/service_report_fault_description_provider.dart @@ -0,0 +1,70 @@ +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/user.dart'; + +import '../../../../../models/fault_description.dart'; + +class ServiceRequestFaultDescriptionProvider extends ChangeNotifier { + //reset provider data + void reset() { + _items = 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; + + // contain user data + // when user not login or register _user = null + List _items; + List get items => _items; + + // when categories in-process _loading = true + // done _loading = true + // failed _loading = false + bool _loading; + 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 getData({String host, User user, String requestId}) async { + if (_loading == true) return -2; + _loading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get( + URLs.getServiceReportFaultDescription + "?callId=$requestId", + ); + _stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + // client's request was successfully received + List listJson = json.decode(response.body)["data"]['asset']['modelDefinition']['modelDefRelatedDefects']; + _items = listJson.map((type) => FaultDescription.fromJson(type)).toList(); + } + _loading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + _loading = false; + _stateCode = -1; + notifyListeners(); + return -1; + } + } +} diff --git a/lib/main.dart b/lib/main.dart index eef23138..56bcee8c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -49,6 +49,7 @@ import 'package:test_sa/views/widgets/equipment/single_device_picker.dart'; import 'controllers/providers/api/parts_provider.dart'; import 'controllers/providers/api/preventive_maintenance_visits_provider.dart'; import 'controllers/providers/api/status_drop_down/pentry/pentry_status_provider.dart'; +import 'controllers/providers/api/status_drop_down/report/service_report_fault_description_provider.dart'; import 'controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; import 'controllers/providers/api/status_drop_down/report/service_report_reasons_provider.dart'; import 'controllers/providers/api/status_drop_down/report/service_report_repair_location_provider.dart'; @@ -117,6 +118,7 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => ServiceLoanAvailabilityProvider()), ChangeNotifierProvider(create: (_) => ServiceFirstActionProvider()), ChangeNotifierProvider(create: (_) => ServiceReportRepairLocationProvider()), + ChangeNotifierProvider(create: (_) => ServiceRequestFaultDescriptionProvider()), ], child: GestureDetector( onTap: () { diff --git a/lib/models/fault_description.dart b/lib/models/fault_description.dart new file mode 100644 index 00000000..02e67e92 --- /dev/null +++ b/lib/models/fault_description.dart @@ -0,0 +1,36 @@ +class FaultDescription { + FaultDescription({ + this.id, + this.defectName, + this.workPerformed, + this.estimatedTime,}); + + FaultDescription.fromJson(dynamic json) { + id = json['id']; + defectName = json['defectName']; + workPerformed = json['workPerformed']; + estimatedTime = json['estimatedTime']; + } + num id; + dynamic defectName; + String workPerformed; + String estimatedTime; +FaultDescription copyWith({ num id, + dynamic defectName, + String workPerformed, + String estimatedTime, +}) => FaultDescription( id: id ?? this.id, + defectName: defectName ?? this.defectName, + workPerformed: workPerformed ?? this.workPerformed, + estimatedTime: estimatedTime ?? this.estimatedTime, +); + Map toJson() { + final map = {}; + map['id'] = id; + map['defectName'] = defectName; + map['workPerformed'] = workPerformed; + map['estimatedTime'] = estimatedTime; + return map; + } + +} \ No newline at end of file diff --git a/lib/models/service_report.dart b/lib/models/service_report.dart index 637de4e3..f8f65e75 100644 --- a/lib/models/service_report.dart +++ b/lib/models/service_report.dart @@ -3,6 +3,7 @@ import 'dart:typed_data'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/models/device/device.dart'; import 'package:test_sa/models/engineer.dart'; +import 'package:test_sa/models/fault_description.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/part.dart'; import 'package:test_sa/models/service_request/service_request.dart'; @@ -41,40 +42,41 @@ class ServiceReport { Uint8List localEngineerSignature; int travelingExpense; String reviewComment; + FaultDescription faultDescription; - ServiceReport({ - this.id, - this.visitDate, - this.endDate, - this.assetType, - this.status, - this.type, - this.faultDescriptionId, - //this.workHours, - this.travelingHours, - this.parts, - this.engineer, - this.workPreformed, - this.reason, - this.operatingHours, - this.callLastSituation, - this.jobSheetNumber, - this.image, - this.device, - this.invoiceCode, - this.invoiceNumber, - this.quantity = "1", - this.timer, - this.signatureNurse, - this.signatureEngineer, - this.localNurseSignature, - this.localEngineerSignature, - this.comment, - this.repairLocation, - this.travelingExpense, - this.startDate, - this.reviewComment, - }); + ServiceReport( + {this.id, + this.visitDate, + this.endDate, + this.assetType, + this.status, + this.type, + this.faultDescriptionId, + //this.workHours, + this.travelingHours, + this.parts, + this.engineer, + this.workPreformed, + this.reason, + this.operatingHours, + this.callLastSituation, + this.jobSheetNumber, + this.image, + this.device, + this.invoiceCode, + this.invoiceNumber, + this.quantity = "1", + this.timer, + this.signatureNurse, + this.signatureEngineer, + this.localNurseSignature, + this.localEngineerSignature, + this.comment, + this.repairLocation, + this.travelingExpense, + this.startDate, + this.reviewComment, + this.faultDescription}); Map toMap(ServiceRequest request) { Map _map = {}; @@ -92,12 +94,9 @@ class ServiceReport { _map["workingHours"] = (timer.durationInSecond / 60 / 60).toStringAsFixed(5); } if (travelingHours != null && travelingHours.isNotEmpty) _map["traveling_hours"] = travelingHours; - // if(workPreformed != null && workPreformed.isNotEmpty){ - // _map["faultDescription"] = { - // //"id":faultDescriptionId ?? 0, - // "workPerformed":workPreformed - // }; - // } + if (workPreformed != null && workPreformed.isNotEmpty) { + _map["faultDescription"] = faultDescription.toJson(); + } if (jobSheetNumber != null && jobSheetNumber.isNotEmpty) _map["job_sheet_no"] = jobSheetNumber; if (parts != null && parts.isNotEmpty) { _map["sparePartsWorkOrders"] = parts.map((e) => e.toJson()).toList(); diff --git a/lib/views/pages/user/requests/report/create_service_report.dart b/lib/views/pages/user/requests/report/create_service_report.dart index ffb92ece..e705d495 100644 --- a/lib/views/pages/user/requests/report/create_service_report.dart +++ b/lib/views/pages/user/requests/report/create_service_report.dart @@ -35,6 +35,7 @@ import 'package:test_sa/views/widgets/titles/app_sub_title.dart'; import '../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; import '../../../../widgets/speech_to_text/speech_to_text.dart'; +import '../../../../widgets/status/report/service_report_fault_description.dart'; import '../../../../widgets/status/report/service_report_repair_location.dart'; class CreateServiceReport extends StatefulWidget { @@ -513,34 +514,32 @@ class _CreateServiceReportState extends State with TickerPr ], ), const SizedBox(height: 8), - Row( - children: [ - ASubTitle(_subtitle.faultDescription), - Expanded( - child: SizedBox( - height: 32 * AppStyle.getScaleFactor(context), - child: SpeechToTextButton( - controller: _faultController, - mini: true, - ), - ), - ), - ], - ), + ASubTitle(_subtitle.faultDescription), const SizedBox( height: 4, ), - ATextFormField( - initialValue: _serviceReport?.faultDescriptionId?.toString(), - textAlign: TextAlign.center, - controller: _faultController, - style: Theme.of(context).textTheme.titleMedium, - validator: (value) => Validator.hasValue(value) ? null : _subtitle.requiredWord, - textInputType: TextInputType.multiline, - onSaved: (value) { - _serviceReport.faultDescriptionId = int.tryParse(value) ?? 0; + ServiceReportFaultDescription( + requestId: widget.request.id, + initialValue: _serviceReport.faultDescription, + onSelect: (status) { + _serviceReport.faultDescription = status; + setState(() {}); }, ), + const SizedBox( + height: 4, + ), + // ATextFormField( + // initialValue: _serviceReport?.faultDescriptionId?.toString(), + // textAlign: TextAlign.center, + // controller: _faultController, + // style: Theme.of(context).textTheme.titleMedium, + // validator: (value) => Validator.hasValue(value) ? null : _subtitle.requiredWord, + // textInputType: TextInputType.multiline, + // onSaved: (value) { + // _serviceReport.faultDescriptionId = int.tryParse(value) ?? 0; + // }, + // ), const SizedBox( height: 8, ), diff --git a/lib/views/widgets/status/report/fault_desc_menu.dart b/lib/views/widgets/status/report/fault_desc_menu.dart new file mode 100644 index 00000000..4d9e2aed --- /dev/null +++ b/lib/views/widgets/status/report/fault_desc_menu.dart @@ -0,0 +1,110 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/models/fault_description.dart'; +import 'package:test_sa/views/app_style/colors.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; + +class FaultDescriptionMenu extends StatefulWidget { + final List statuses; + final FaultDescription initialStatus; + final Function(FaultDescription) onSelect; + + const FaultDescriptionMenu({Key key, this.statuses, this.onSelect, this.initialStatus}) : super(key: key); + + @override + _SingleStatusMenuState createState() => _SingleStatusMenuState(); +} + +class _SingleStatusMenuState extends State { + FaultDescription _selectedStatus; + + @override + void setState(VoidCallback fn) { + if (mounted) super.setState(fn); + } + + @override + void didUpdateWidget(covariant FaultDescriptionMenu oldWidget) { + if (widget.initialStatus != null) { + final result = widget.statuses?.where((element) { + return element == widget.initialStatus; + }); + if (result.isNotEmpty) { + _selectedStatus = result.first; + } else { + _selectedStatus = null; + } + if ((widget.initialStatus?.id ?? "") != (_selectedStatus?.id ?? "")) { + widget.onSelect(_selectedStatus); + } + } else { + _selectedStatus = null; + } + super.didUpdateWidget(oldWidget); + } + + @override + void initState() { + if (widget.initialStatus != null) { + final result = widget.statuses?.where((element) { + return element == widget.initialStatus; + }); + if (result.isNotEmpty) _selectedStatus = result.first; + if (widget.initialStatus.id != _selectedStatus?.id) { + widget.onSelect(_selectedStatus); + } + } + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + color: AColors.inputFieldBackgroundColor, + border: Border.all( + color: Color(0xffefefef), + ), + borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)), + // boxShadow: const [ + // AppStyle.boxShadow + // ] + ), + child: DropdownButton( + value: _selectedStatus, + iconSize: 24, + icon: const Icon(Icons.keyboard_arrow_down_rounded), + elevation: 0, + isExpanded: true, + hint: Text( + "Select", + style: Theme.of(context).textTheme.subtitle1, + ), + style: TextStyle(color: Theme.of(context).primaryColor), + underline: SizedBox.shrink(), + onChanged: (FaultDescription newValue) { + setState(() { + _selectedStatus = newValue; + }); + widget.onSelect(newValue); + }, + items: widget.statuses.map>( + (FaultDescription value) { + return DropdownMenuItem( + value: value, + child: Text( + value.defectName, + style: Theme.of(context).textTheme.subtitle1.copyWith( + color: Theme.of(context).primaryColor, + fontSize: 11, + //fontWeight: FontWeight.bold + ), + ), + ); + }, + ).toList(), + ), + ); + } +} diff --git a/lib/views/widgets/status/report/service_report_fault_description.dart b/lib/views/widgets/status/report/service_report_fault_description.dart new file mode 100644 index 00000000..3e92f5f4 --- /dev/null +++ b/lib/views/widgets/status/report/service_report_fault_description.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_report_fault_description_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/models/fault_description.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import 'package:test_sa/views/widgets/status/report/fault_desc_menu.dart'; + +import '../../app_text_form_field.dart'; + +class ServiceReportFaultDescription extends StatelessWidget { + final String requestId; + final Function(FaultDescription) onSelect; + final FaultDescription initialValue; + + const ServiceReportFaultDescription({Key key, this.requestId, this.onSelect, this.initialValue}) : super(key: key); + @override + Widget build(BuildContext context) { + SettingProvider settingProvider = Provider.of(context); + UserProvider userProvider = Provider.of(context); + ServiceRequestFaultDescriptionProvider menuProvider = Provider.of(context); + return LoadingManager( + isLoading: menuProvider.isLoading, + isFailedLoading: menuProvider.items == null, + stateCode: menuProvider.stateCode, + onRefresh: () async { + menuProvider.reset(); + await menuProvider.getData(user: userProvider.user, host: settingProvider.host, requestId: requestId); + }, + child: menuProvider.items.isEmpty + ? const ATextFormField( + initialValue: "NULL", + enable: false, + ) + : FaultDescriptionMenu( + initialStatus: initialValue, + statuses: menuProvider.items, + onSelect: onSelect, + ), + ); + } +}