diff --git a/lib/controllers/providers/api/service_requests_provider.dart b/lib/controllers/providers/api/service_requests_provider.dart index 9bab49f5..b338d0ae 100644 --- a/lib/controllers/providers/api/service_requests_provider.dart +++ b/lib/controllers/providers/api/service_requests_provider.dart @@ -142,7 +142,7 @@ class ServiceRequestsProvider extends ChangeNotifier { "requestedDate": DateTime.now().toIso8601String(), "requestedTime": DateTime.now().toIso8601String(), "client": user.clientId, - "callComments": serviceRequest.maintenanceIssue, + "callComments": serviceRequest.callComments, if (serviceRequest.devicePhotos.isNotEmpty) "attachmentsCallRequest": serviceRequest.devicePhotos.map((e) => {"name": e}).toList(), "priority": serviceRequest.priority.toMap(), "defectType": serviceRequest.defectType.toMap(), @@ -248,13 +248,13 @@ class ServiceRequestsProvider extends ChangeNotifier { "contactUserId": user.id, }, ], - "callComments": request.maintenanceIssue, + "callComments": request.callComments, "noofFollowup": 0, // "status": null, "callLastSituation": null, "firstAction": request.firstAction?.toMap(), "loanAvailablity": request.loanAvailability?.toMap(), - "comments": request.comment, + "comments": request.reviewComment, "firstActionDate": serviceRequest['firstActionDate'], "visitDate": date?.toIso8601String() ?? "", "callReview": null, diff --git a/lib/models/service_report.dart b/lib/models/service_report.dart index 8f5b873a..7024bd49 100644 --- a/lib/models/service_report.dart +++ b/lib/models/service_report.dart @@ -23,6 +23,7 @@ class ServiceReport { Lookup reason; int faultDescriptionId; String workPreformed; + //String workHours; String travelingHours; String invoiceNumber; @@ -127,6 +128,7 @@ class ServiceReport { _map["travelingExpense"] = travelingExpense; _map["startofWorkTime"] = startDate; _map["endofWorkTime"] = endDate; + _map["workingHours"] = endDate?.difference(startDate)?.inHours ?? 0; return _map; } @@ -154,7 +156,7 @@ class ServiceReport { factory ServiceReport.fromJson(Map parsedJson, int id) { List _parts = []; if (parsedJson["sparePartsWorkOrders"] != null) { - if ((parsedJson["sparePartsWorkOrders"]as List ).isNotEmpty && parsedJson["sparePartsWorkOrders"][0]["id"] != null) { + if ((parsedJson["sparePartsWorkOrders"] as List).isNotEmpty && parsedJson["sparePartsWorkOrders"][0]["id"] != null) { List partsList = parsedJson["sparePartsWorkOrders"]; _parts = partsList.map((e) => Part.fromJson(e["sparePart"], reportJson: e)).toList(); } @@ -171,11 +173,11 @@ class ServiceReport { //invoiceCode: parsedJson["invoice_code"], //invoiceNumber: parsedJson["invoice_no"], //jobSheetNumber: parsedJson["job_sheet_no"], - //operatingHours: parsedJson["workingHours"], + operatingHours: parsedJson["workingHours"], engineer: Engineer.fromJson(parsedJson["assignedEmployee"]), parts: _parts, //quantity: parsedJson["nid"], - //travelingHours: parsedJson["traveling_hours"], + travelingHours: parsedJson["traveling_hours"], visitDate: DateTime.tryParse(parsedJson["visitDate"]), //workHours: parsedJson["working_hours"], timer: TimerModel( @@ -187,8 +189,8 @@ class ServiceReport { ); } - // static getDate(String date){ - // return date == null || date.isEmpty - // ? null : DateTime.fromMillisecondsSinceEpoch(int.tryParse(date) * 1000); - // } +// static getDate(String date){ +// return date == null || date.isEmpty +// ? null : DateTime.fromMillisecondsSinceEpoch(int.tryParse(date) * 1000); +// } } diff --git a/lib/models/service_request/service_request.dart b/lib/models/service_request/service_request.dart index 6ebc748b..a884da62 100644 --- a/lib/models/service_request/service_request.dart +++ b/lib/models/service_request/service_request.dart @@ -10,7 +10,7 @@ class ServiceRequest { String deviceArName; String deviceEnName; List devicePhotos; - String maintenanceIssue; + String callComments; String hospitalName; int hospitalId; String departmentName; @@ -19,7 +19,8 @@ class ServiceRequest { String audio; int statusValue; String statusLabel; - String comment; + String reviewComment; + String comments; bool viewReport; String engineerMobile; @@ -49,7 +50,7 @@ class ServiceRequest { this.devicePhotos, this.hospitalId, this.deviceSerialNumber, - this.maintenanceIssue, + this.callComments, this.statusLabel, this.statusValue, this.departmentName, @@ -71,7 +72,8 @@ class ServiceRequest { this.type, this.requestedThrough, this.device, - this.comment, + this.reviewComment, + this.comments, this.loanAvailability, this.firstAction, }); @@ -94,7 +96,8 @@ class ServiceRequest { devicePhotos: images, deviceSerialNumber: parsedJson["asset"]["assetSerialNo"], date: DateTime.tryParse(parsedJson["requestedDate"] ?? "").toString().split(" ").first, - maintenanceIssue: parsedJson["comments"], + callComments: parsedJson["callComments"], + comments: parsedJson["comments"], statusLabel: parsedJson["status"] == null ? null : parsedJson["status"]["name"], statusValue: parsedJson["status"] == null ? null : parsedJson["status"]["value"], departmentName: parsedJson["asset"]["department"] != null ? parsedJson["asset"]["department"]["name"] : "", @@ -110,7 +113,7 @@ class ServiceRequest { nextVisitDate: DateTime.tryParse(parsedJson["nextVisitDate"] ?? ""), workPerformed: parsedJson["workOrder"] != null ? parsedJson["workOrder"]["workPerformed"] : null, device: Device.fromJson(parsedJson["asset"]), - comment: parsedJson["reviewComment"], + reviewComment: parsedJson["reviewComment"], type: Lookup.fromJson(parsedJson['typeofRequest']), defectType: Lookup.fromJson(parsedJson['defectType']), loanAvailability: Lookup.fromJson(parsedJson['loanAvailability']), diff --git a/lib/views/pages/user/requests/create_request.dart b/lib/views/pages/user/requests/create_request.dart index fb676de4..3d2b6de8 100644 --- a/lib/views/pages/user/requests/create_request.dart +++ b/lib/views/pages/user/requests/create_request.dart @@ -39,6 +39,7 @@ import '../../../widgets/status/service_request/service_request_loan_availabilit class CreateRequestPage extends StatefulWidget { static const String id = "/create-request"; final ServiceRequest serviceRequest; + const CreateRequestPage({this.serviceRequest, Key key}) : super(key: key); @override @@ -199,7 +200,7 @@ class CreateRequestPageState extends State { height: 4, ), ServiceRequestedThroughMenu( - initialValue: const Lookup(name: "App", value: 375), + initialValue: _serviceRequest.requestedThrough, onSelect: (status) { _serviceRequest.requestedThrough = status; }, @@ -219,7 +220,7 @@ class CreateRequestPageState extends State { }, ), if (_serviceRequest.firstAction != null) 12.height, - if (_serviceRequest.firstAction != null) + if (_serviceRequest?.firstAction?.id == 405) ADatePicker( date: _dateTime, from: DateTime.now(), @@ -241,6 +242,22 @@ class CreateRequestPageState extends State { }, ), 12.height, + if (widget.serviceRequest != null) const ASubTitle("Comments"), + const SizedBox( + height: 4, + ), + if (widget.serviceRequest != null) + ATextFormField( + controller: _commentController, + initialValue: _serviceRequest.reviewComment, + hintText: _subtitle.comment, + style: Theme.of(context).textTheme.titleMedium, + textInputType: TextInputType.multiline, + onSaved: (value) { + _serviceRequest.reviewComment = value; + }, + ), + 12.height, MultiImagesPicker( label: _subtitle.deviceImages, images: _deviceImages, @@ -250,32 +267,20 @@ class CreateRequestPageState extends State { 12.height, ATextFormField( controller: _maintenanceController, - initialValue: _serviceRequest.maintenanceIssue, + initialValue: _serviceRequest.callComments, hintText: _subtitle.maintenanceIssue, prefixIconData: FontAwesomeIcons.triangleExclamation, style: Theme.of(context).textTheme.headline6, textInputType: TextInputType.multiline, validator: (value) => Validator.hasValue(value) ? null : _subtitle.maintenanceIssueRequired, onSaved: (value) { - _serviceRequest.maintenanceIssue = value; + _serviceRequest.callComments = value; }, ), 12.height, RecordSound(onRecord: (audio) { _serviceRequest.audio = audio; }), - 12.height, - if (widget.serviceRequest != null) - ATextFormField( - controller: _commentController, - initialValue: _serviceRequest.comment, - hintText: _subtitle.comment, - style: Theme.of(context).textTheme.titleMedium, - textInputType: TextInputType.multiline, - onSaved: (value) { - _serviceRequest.comment = value; - }, - ), ], ).paddingOnly(left: 20, right: 20), Padding( 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 f7ee46eb..477bba08 100644 --- a/lib/views/pages/user/requests/report/create_service_report.dart +++ b/lib/views/pages/user/requests/report/create_service_report.dart @@ -21,6 +21,7 @@ import 'package:test_sa/views/widgets/app_text_form_field.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/buttons/app_button.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/date_and_time/time_picker.dart'; import 'package:test_sa/views/widgets/e_signature/e_signature.dart'; import 'package:test_sa/views/widgets/equipment/auto_complete_devices_field.dart'; import 'package:test_sa/views/widgets/images/mini_one_image_picker.dart'; @@ -43,6 +44,7 @@ class CreateServiceReport extends StatefulWidget { final ServiceRequest request; const CreateServiceReport({Key key, this.request}) : super(key: key); + @override _CreateServiceReportState createState() => _CreateServiceReportState(); } @@ -337,15 +339,15 @@ class _CreateServiceReportState extends State with TickerPr child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - const ASubTitle("Start Date"), + const ASubTitle("Start of Work"), SizedBox( height: 8 * AppStyle.getScaleFactor(context), ), - ADatePicker( + ADateTimePicker( date: _serviceReport.startDate, from: DateTime.now().subtract(const Duration(days: 365)), to: DateTime.now().add(const Duration(days: 365)), - onDatePicker: (date) { + onDateTimePicker: (date) { _serviceReport.startDate = date; setState(() {}); }, @@ -358,15 +360,15 @@ class _CreateServiceReportState extends State with TickerPr child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - const ASubTitle("End Date"), + const ASubTitle("End of Work"), SizedBox( height: 8 * AppStyle.getScaleFactor(context), ), - ADatePicker( + ADateTimePicker( date: _serviceReport.endDate, from: DateTime.now().subtract(const Duration(days: 365)), to: DateTime.now().add(const Duration(days: 365)), - onDatePicker: (date) { + onDateTimePicker: (date) { _serviceReport.endDate = date; setState(() {}); }, @@ -376,31 +378,46 @@ class _CreateServiceReportState extends State with TickerPr ), ], ), - SizedBox( - height: 8 * AppStyle.getScaleFactor(context), - ), - const ASubTitle("Assigned Employee"), - const SizedBox( - height: 8, - ), - _validate && _serviceReport.engineer == null - ? ASubTitle( - _subtitle.requiredWord, - color: Colors.red, - ) - : const SizedBox.shrink(), - const SizedBox( - height: 4, - ), - EngineersMenu( - initialValue: _serviceReport.engineer, - onSelect: (engineer) { - _serviceReport.engineer = engineer; + ASubTitle(_subtitle.workingHours), + const SizedBox(height: 4), + ATextFormField( + initialValue: null, + textAlign: TextAlign.center, + hintText: _serviceReport.startDate == null ? "0" : _serviceReport?.endDate?.difference(_serviceReport?.startDate)?.inHours?.toString() ?? "0", + enable: false, + style: Theme.of(context).textTheme.subtitle1, + validator: (value) => Validator.isNumeric(value) ? null : _subtitle.requiredWord, + textInputType: TextInputType.number, + onSaved: (value) { + // _serviceReport.workHours = value; }, ), - const SizedBox( - height: 8, + + SizedBox( + height: 8 * AppStyle.getScaleFactor(context), ), + // const ASubTitle("Assigned Employee"), + // const SizedBox( + // height: 8, + // ), + // _validate && _serviceReport.engineer == null + // ? ASubTitle( + // _subtitle.requiredWord, + // color: Colors.red, + // ) + // : const SizedBox.shrink(), + // const SizedBox( + // height: 4, + // ), + // EngineersMenu( + // initialValue: _serviceReport.engineer, + // onSelect: (engineer) { + // _serviceReport.engineer = engineer; + // }, + // ), + // const SizedBox( + // height: 8, + // ), // invoice number & code _serviceReport.callLastSituation?.id != 12 ? const SizedBox.shrink() @@ -577,6 +594,10 @@ class _CreateServiceReportState extends State with TickerPr const SizedBox( height: 16, ), + ASubTitle(_subtitle.travelingExpense), + const SizedBox( + height: 4, + ), ATextFormField( initialValue: _serviceReport?.travelingExpense?.toString(), hintText: _subtitle.travelingExpense, @@ -587,19 +608,6 @@ class _CreateServiceReportState extends State with TickerPr _serviceReport.travelingExpense = int.tryParse(value) ?? 0; }, ), - const SizedBox( - height: 8, - ), - ATextFormField( - initialValue: _serviceReport?.comment, - hintText: _subtitle.comment, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleMedium, - textInputType: TextInputType.multiline, - onSaved: (value) { - _serviceReport.comment = value; - }, - ), const SizedBox( height: 8, @@ -607,66 +615,68 @@ class _CreateServiceReportState extends State with TickerPr // Traveling Hours & Working Hours Row( children: [ + // Expanded( + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // ASubTitle(_subtitle.workingHours), + // const SizedBox( + // height: 8, + // ), + // Row( + // children: [ + // Expanded( + // child: AppTimer( + // timer: _serviceReport.timer, + // onChange: (timer) async { + // _serviceReport.timer = timer; + // return true; + // }, + // ), + // ), + // ], + // ), + // // ATextFormField( + // // initialValue: _serviceReport?.workHours, + // // textAlign: TextAlign.center, + // // hintText: "i.e 3, 3.5, 4", + // // style: Theme.of(context).textTheme.subtitle1, + // // validator: (value) => + // // Validator.isNumeric(value) + // // ? null : _subtitle.requiredWord, + // // textInputType: TextInputType.number, + // // onSaved: (value){ + // // _serviceReport.workHours = value; + // // }, + // // ), + // ], + // ), + // ), + // const SizedBox(width: 8,), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ASubTitle(_subtitle.workingHours), + ASubTitle(_subtitle.travelingHours), const SizedBox( - height: 8, + height: 4, ), - Row( - children: [ - Expanded( - child: AppTimer( - timer: _serviceReport.timer, - onChange: (timer) async { - _serviceReport.timer = timer; - return true; - }, - ), - ), - ], + ATextFormField( + initialValue: _serviceReport?.travelingHours, + textAlign: TextAlign.center, + hintText: "i.e 3, 3.5, 4", + style: Theme.of(context).textTheme.subtitle1, + // validator: (value) => + // Validator.isNumeric(value) + // ? null : _subtitle.requiredWord, + textInputType: TextInputType.number, + onSaved: (value) { + _serviceReport.travelingHours = value; + }, ), - // ATextFormField( - // initialValue: _serviceReport?.workHours, - // textAlign: TextAlign.center, - // hintText: "i.e 3, 3.5, 4", - // style: Theme.of(context).textTheme.subtitle1, - // validator: (value) => - // Validator.isNumeric(value) - // ? null : _subtitle.requiredWord, - // textInputType: TextInputType.number, - // onSaved: (value){ - // _serviceReport.workHours = value; - // }, - // ), ], ), ), - // const SizedBox(width: 8,), - // Expanded( - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // ASubTitle(_subtitle.travelingHours), - // const SizedBox(height: 4,), - // ATextFormField( - // initialValue: _serviceReport?.travelingHours, - // textAlign: TextAlign.center, - // hintText: "i.e 3, 3.5, 4", - // style: Theme.of(context).textTheme.subtitle1, - // // validator: (value) => - // // Validator.isNumeric(value) - // // ? null : _subtitle.requiredWord, - // textInputType: TextInputType.number, - // onSaved: (value){ - // _serviceReport.travelingHours = value; - // }, - // ), - // ], - // ), - // ), ], ), const SizedBox( @@ -718,6 +728,24 @@ class _CreateServiceReportState extends State with TickerPr // ), // ], // ), + + const SizedBox( + height: 8, + ), + ASubTitle(_subtitle.comment), + const SizedBox( + height: 4, + ), + ATextFormField( + initialValue: _serviceReport?.comment, + hintText: "Technical Comment", + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.titleMedium, + textInputType: TextInputType.multiline, + onSaved: (value) { + _serviceReport.comment = value; + }, + ), const SizedBox(height: 8), const ASubTitle("Nurse Signature"), ESignature( diff --git a/lib/views/pages/user/requests/request_details.dart b/lib/views/pages/user/requests/request_details.dart index 0d17f864..36f3f948 100644 --- a/lib/views/pages/user/requests/request_details.dart +++ b/lib/views/pages/user/requests/request_details.dart @@ -254,7 +254,7 @@ class RequestDetailsPage extends StatelessWidget { ), RequestInfoRow( title: _subtitle.maintenanceIssue, - content: serviceRequest.maintenanceIssue, + content: serviceRequest.callComments, ), if (serviceRequest.audio?.isNotEmpty == true) ASoundPlayer( diff --git a/lib/views/widgets/date_and_time/time_picker.dart b/lib/views/widgets/date_and_time/time_picker.dart new file mode 100644 index 00000000..036766e4 --- /dev/null +++ b/lib/views/widgets/date_and_time/time_picker.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/views/app_style/sizing.dart'; + +class ADateTimePicker extends StatelessWidget { + final DateTime date; + final DateTime from; + final DateTime to; + final Function(DateTime) onDateTimePicker; + + const ADateTimePicker({Key key, this.date, this.onDateTimePicker, this.from, this.to}) : super(key: key); + + @override + Widget build(BuildContext context) { + return ElevatedButton( + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + textStyle: Theme.of(context).textTheme.subtitle2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12 * AppStyle.getScaleFactor(context)), + ), + ), + child: Text( + date == null ? "Pick Time" : date.toString().substring(0,date.toString().lastIndexOf(":")), + textScaleFactor: AppStyle.getScaleFactor(context), + ), + onPressed: () async { + // TimeOfDay picked = await showTimePicker(context: context, initialTime: TimeOfDay.now()); + onDateTimePicker(await showDateTimePicker(context: context, initialDate: date, firstDate: from, lastDate: to)); + }, + ); + } +} + +Future showDateTimePicker({ + BuildContext context, + DateTime initialDate, + DateTime firstDate, + DateTime lastDate, +}) async { + initialDate ??= DateTime.now(); + firstDate ??= initialDate.subtract(const Duration(days: 365 * 100)); + lastDate ??= firstDate.add(const Duration(days: 365 * 200)); + + final DateTime selectedDate = await showDatePicker( + context: context, + initialDate: initialDate, + firstDate: firstDate, + lastDate: lastDate, + ); + + if (selectedDate == null) return null; + + if (!context.mounted) return selectedDate; + + final TimeOfDay selectedTime = await showTimePicker( + context: context, + initialTime: TimeOfDay.fromDateTime(selectedDate), + ); + + return selectedTime == null + ? selectedDate + : DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); +} diff --git a/lib/views/widgets/requests/service_request_item.dart b/lib/views/widgets/requests/service_request_item.dart index 7977048d..2580deef 100644 --- a/lib/views/widgets/requests/service_request_item.dart +++ b/lib/views/widgets/requests/service_request_item.dart @@ -190,7 +190,7 @@ class ServiceRequestItem extends StatelessWidget { child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( - request.maintenanceIssue ?? "No maintenance issue found", + request.callComments ?? "No maintenance issue found", style: Theme.of(context).textTheme.subtitle1.copyWith(color: onItemColor), textAlign: TextAlign.center, ),