diff --git a/assets/images/add_icon.svg b/assets/images/add_icon.svg new file mode 100644 index 00000000..833a5215 --- /dev/null +++ b/assets/images/add_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/arrived_icon.svg b/assets/images/arrived_icon.svg new file mode 100644 index 00000000..a5951d03 --- /dev/null +++ b/assets/images/arrived_icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/assets.svg b/assets/images/assets.svg index 905e96b3..f4fea28b 100644 --- a/assets/images/assets.svg +++ b/assets/images/assets.svg @@ -1,5 +1,3 @@ - - - - + + diff --git a/assets/images/clock.svg b/assets/images/clock.svg new file mode 100644 index 00000000..7c816867 --- /dev/null +++ b/assets/images/clock.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/contact.svg b/assets/images/contact.svg new file mode 100644 index 00000000..5e8a0385 --- /dev/null +++ b/assets/images/contact.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/drag_icon.svg b/assets/images/drag_icon.svg new file mode 100644 index 00000000..168ad9f8 --- /dev/null +++ b/assets/images/drag_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/image-plus.svg b/assets/images/image-plus.svg new file mode 100644 index 00000000..105b9c3e --- /dev/null +++ b/assets/images/image-plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/image_icon.svg b/assets/images/image_icon.svg new file mode 100644 index 00000000..9e54929a --- /dev/null +++ b/assets/images/image_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/overview.svg b/assets/images/overview.svg index 0abb97f3..d5e96156 100644 --- a/assets/images/overview.svg +++ b/assets/images/overview.svg @@ -1,5 +1,3 @@ - - - - + + diff --git a/assets/images/request.svg b/assets/images/request.svg new file mode 100644 index 00000000..a0e0d462 --- /dev/null +++ b/assets/images/request.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/request_icon.svg b/assets/images/request_icon.svg new file mode 100644 index 00000000..a0e0d462 --- /dev/null +++ b/assets/images/request_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/scan_asset.svg b/assets/images/scan_asset.svg new file mode 100644 index 00000000..b2dd1353 --- /dev/null +++ b/assets/images/scan_asset.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/lib/common_widgets/stapper_widget/components/base_step.dart b/lib/common_widgets/stapper_widget/components/base_step.dart new file mode 100644 index 00000000..7ecea1b3 --- /dev/null +++ b/lib/common_widgets/stapper_widget/components/base_step.dart @@ -0,0 +1,186 @@ + +import 'package:flutter/material.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'base_step_delegate.dart'; +typedef OnStepReached = void Function(int index); + +enum StepShape { circle, rRectangle } + +enum BorderType { normal, dotted } + +class BaseStep extends StatelessWidget { + const BaseStep({ + Key key, + @required this.step, + @required this.isActive, + @required this.isFinished, + @required this.isAlreadyReached, + @required this.radius, + @required this.isUnreached, + @required this.activeStepBackgroundColor, + @required this.unreachedBackgroundColor, + @required this.activeStepBorderColor, + @required this.unreachedBorderColor, + @required this.activeTextColor, + @required this.activeIconColor, + @required this.unreachedTextColor, + @required this.unreachedIconColor, + @required this.padding, + @required this.stepRadius, + @required this.showStepBorder, + @required this.lineLength, + @required this.enabled, + }) : super(key: key); + final StepModel step; + final bool isActive; + final bool isUnreached; + final bool isFinished; + final bool isAlreadyReached ; + final double radius; + final Color activeStepBackgroundColor; + final Color unreachedBackgroundColor; + final Color activeStepBorderColor; + final Color unreachedBorderColor; + final Color activeTextColor; + final Color activeIconColor; + final Color unreachedTextColor; + final Color unreachedIconColor; + final double padding; + final double stepRadius; + final bool showStepBorder; + final double lineLength; + final bool enabled; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: (radius * 2) + (padding ?? 0), + height: radius * 2.5 + 25, + child: CustomMultiChildLayout( + delegate: BaseStepDelegate( + stepRadius: radius, + topTitle: step.topTitle, + direction: Axis.horizontal), + children: [ + LayoutId( + id: BaseStepElem.step, + child: Material( + color: Colors.transparent, + clipBehavior: Clip.antiAlias, + borderRadius: BorderRadius.circular(stepRadius ?? 0), + child: Container( + width: radius * 2, + height: radius * 2, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: _handleColor(context, isFinished, isActive, + isAlreadyReached)), + alignment: Alignment.center, + child: _buildIcon(context), + ), + )), + LayoutId( + id: BaseStepElem.title, child: _buildStepTitle(context)) + ], + ), + ); + } + + Color _handleColor(BuildContext context, bool isFinished, bool isActive, + bool isAlreadyReached) { + if (isActive) { + return activeStepBackgroundColor ?? Colors.transparent; + } else { + if (isFinished) { + return AppColor.primary10; + } else if (isAlreadyReached) { + return AppColor.primary10; + } else { + return unreachedBackgroundColor ?? Colors.transparent; + } + } + } + + + Color _handleTitleColor(BuildContext context, bool isFinished, bool isActive, + bool isAlreadyReached) { + if (isActive) { + return activeTextColor ?? Theme.of(context).colorScheme.primary; + } else { + if (isFinished) { + return Colors.transparent; + } else if (isAlreadyReached) { + return Colors.transparent; + } else { + return unreachedTextColor ?? Colors.grey.shade400; + } + } + } + + + Widget _buildStepTitle(BuildContext context) { + return SizedBox( + width: (radius * 4.5) + + (padding ?? 0), + child: step.customTitle ?? + Text( + step.title ?? '', + maxLines: 3, + textAlign: TextAlign.center, + softWrap: false, + overflow: TextOverflow.visible, + style: Theme.of(context).textTheme.bodyMedium.copyWith( + color: _handleTitleColor( + context, isFinished, isActive, isAlreadyReached), + height: 1, + // fontSize: radius * 0.45, + ), + ), + ); + } + + SizedBox _buildIcon(BuildContext context) { + return SizedBox( + width: radius * 2, + height: radius * 2, + child: Center( + child: step.customStep ?? + Icon( + isActive && step.activeIcon != null + ? step.activeIcon.icon + : isFinished && step.finishIcon != null + ? step.finishIcon.icon + : step.icon.icon, + size: radius * 0.9, + color: Colors.white, + ), + ), + ); + } + +} +class StepModel { + final Icon icon; + final Icon finishIcon; + final Icon activeIcon; + final Widget customStep; + final String title; + final Widget customTitle; + final String lineText; + final Widget customLineWidget; + final bool topTitle; + final bool enabled; + const StepModel({ + this.icon, + this.finishIcon, + this.activeIcon, + this.title, + this.lineText, + this.customStep, + this.customTitle, + this.customLineWidget, + this.topTitle = false, + this.enabled = true, + }) : assert(icon != null || customStep != null); +} + diff --git a/lib/common_widgets/stapper_widget/components/base_step_delegate.dart b/lib/common_widgets/stapper_widget/components/base_step_delegate.dart new file mode 100644 index 00000000..43af00ee --- /dev/null +++ b/lib/common_widgets/stapper_widget/components/base_step_delegate.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +enum BaseStepElem { step, title } + +class BaseStepDelegate extends MultiChildLayoutDelegate { + final double stepRadius; + final Axis direction; + final bool topTitle; + + BaseStepDelegate({ + @required this.stepRadius, + @required this.direction, + this.topTitle = false, + }); + + @override + void performLayout(Size size) { + assert(hasChild(BaseStepElem.step)); + + layoutChild( + BaseStepElem.step, + BoxConstraints.loose( + size), // This just says that the child cannot be bigger than the whole layout. + ); + + positionChild( + BaseStepElem.step, + Offset( + (size.width - 2 * stepRadius) / 2, + direction == Axis.horizontal + ? 0 + : (size.height - 2 * stepRadius) / 2)); + + if (hasChild(BaseStepElem.title)) { + final Size titleSize = layoutChild( + BaseStepElem.title, + const BoxConstraints(), + ); + + Offset titleOffset = Offset(-titleSize.width / 2 + (size.width / 2), + topTitle ? -(stepRadius + titleSize.height) : (stepRadius * 2.35)); + + positionChild(BaseStepElem.title, titleOffset); + } + } + + @override + bool shouldRelayout(BaseStepDelegate oldDelegate) { + return false; + } +} diff --git a/lib/common_widgets/stapper_widget/components/custom_line.dart b/lib/common_widgets/stapper_widget/components/custom_line.dart new file mode 100644 index 00000000..2e29ac0d --- /dev/null +++ b/lib/common_widgets/stapper_widget/components/custom_line.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; + +class EasyLine extends StatelessWidget { + final double length; + final double width; + final Color color; + final double thickness; + final double spacing; + final LineType lineType; + final Axis axis; + + const EasyLine({ + key, + this.length = 50.0, + this.color = Colors.grey, + this.thickness = 3, + this.spacing = 3.0, + this.width = 2.0, + this.lineType = LineType.normal, + this.axis = Axis.horizontal, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + width: axis == Axis.horizontal + ? length + : thickness, + height: axis == Axis.vertical + ? length : thickness, + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(100), + ), + ); + } +} + + +enum LineType { + normal, + dotted, + dashed, +} +class LineStyle { + final Color defaultLineColor; + final Color unreachedLineColor; + final Color activeLineColor; + final Color finishedLineColor; + final double lineLength; + final double lineThickness; + final double lineWidth; + final double lineSpace; + final LineType lineType; + final LineType unreachedLineType; + final Color progressColor; + final double progress; + const LineStyle({ + Key key, + this.lineType = LineType.dotted, + this.defaultLineColor, + this.unreachedLineColor, + this.activeLineColor, + this.finishedLineColor, + this.lineLength = 40, + this.lineWidth = 4, + this.lineThickness = 1, + this.lineSpace = 5, + this.unreachedLineType, + this.progressColor, + this.progress, + }) : assert( + progressColor == null || progress != null, + 'progress should be defined to use progressColor', + ), + assert( + progress == null || (progress >= 0 && progress <= 1), + 'progress value should be between 0 and 1', + ); +} \ No newline at end of file diff --git a/lib/common_widgets/stapper_widget/custom_stepper.dart b/lib/common_widgets/stapper_widget/custom_stepper.dart new file mode 100644 index 00000000..068c505c --- /dev/null +++ b/lib/common_widgets/stapper_widget/custom_stepper.dart @@ -0,0 +1,289 @@ +library easy_stepper; +import 'dart:math'; +import 'package:flutter/material.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'components/base_step.dart'; +import 'components/custom_line.dart'; +class CustomStepper extends StatefulWidget { + final List steps; + final OnStepReached onStepReached; + final Color unreachedStepBackgroundColor; + final Color unreachedStepTextColor; + final Color unreachedStepIconColor; + final Color unreachedStepBorderColor; + final BorderType unreachedStepBorderType; + final Color activeStepBackgroundColor; + final Color activeStepTextColor; + final Color activeStepIconColor; + final Color activeStepBorderColor; + final BorderType activeStepBorderType; + final Color finishedStepBackgroundColor; + final Color finishedStepBorderColor; + final Color finishedStepTextColor; + final Color finishedStepIconColor; + final BorderType finishedStepBorderType; + final double stepRadius; + final int activeStep; + final int maxReachedStep; + final Set reachedSteps; + final AlignmentGeometry alignment; + final double internalPadding; + final EdgeInsetsGeometry padding; + final bool titlesAreLargerThanSteps; + final Curve stepAnimationCurve; + final Duration stepAnimationDuration; + final double borderThickness; + final StepShape stepShape; + final double stepBorderRadius; + final bool showStepBorder; + final bool showScrollbar; + final bool fitWidth; + final LineStyle lineStyle; + + const CustomStepper({ + Key key, + @required this.activeStep, + @required this.steps, + this.reachedSteps, + this.maxReachedStep, + this.onStepReached, + this.unreachedStepBackgroundColor, + this.unreachedStepTextColor, + this.unreachedStepIconColor, + this.unreachedStepBorderColor, + this.activeStepTextColor, + this.activeStepIconColor=AppColor.primary10, + this.activeStepBackgroundColor=AppColor.primary10, + this.activeStepBorderColor=AppColor.primary10, + this.finishedStepBackgroundColor=AppColor.primary10, + this.finishedStepBorderColor, + this.finishedStepIconColor, + this.stepRadius = 20, + this.alignment = Alignment.center, + this.fitWidth = true, + this.showScrollbar = false, + this.padding=EdgeInsetsDirectional.zero, + this.titlesAreLargerThanSteps = false, + this.internalPadding = 8, + this.stepAnimationCurve = Curves.linear, + this.stepAnimationDuration = const Duration(seconds: 1), + this.borderThickness = 1, + this.stepShape = StepShape.circle, + this.stepBorderRadius, + this.unreachedStepBorderType, + this.activeStepBorderType, + this.finishedStepBorderType, + this.showStepBorder = false, + this.lineStyle, this.finishedStepTextColor, + }) : assert(maxReachedStep == null || reachedSteps == null, + 'only "maxReachedStep" or "reachedSteps" allowed'), + super(key: key); + + @override + State createState() => _CustomStepperState(); +} + +class _CustomStepperState extends State { + ScrollController _scrollController; + int _selectedIndex; + LineStyle lineStyle; + EdgeInsetsGeometry _padding; + + @override + void initState() { + lineStyle = widget.lineStyle ?? const LineStyle(); + _selectedIndex = widget.activeStep; + _scrollController = ScrollController(); + + _padding = const EdgeInsetsDirectional.all(10); + if (widget.steps.any((element) => element.topTitle)) { + _padding = _padding.add(const EdgeInsetsDirectional.only(top: 45)); + } + if (widget.titlesAreLargerThanSteps) { + _padding = _padding.add(EdgeInsetsDirectional.symmetric( + horizontal: lineStyle.lineLength / 2)); + } + if (widget.padding != null) { + _padding.add(widget.padding); + } + + super.initState(); + } + + @override + void didUpdateWidget(CustomStepper oldWidget) { + super.didUpdateWidget(oldWidget); + + // Verify that the active step falls within a valid range. + if (widget.activeStep >= 0 && widget.activeStep < widget.steps.length) { + _selectedIndex = widget.activeStep; + } + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + /// Controls the step scrolling. + void _afterLayout(_) { + for (int i = 0; i < widget.steps.length; i++) { + _scrollController.animateTo( + i * + ((widget.stepRadius * 2) + + widget.internalPadding + + lineStyle.lineLength), + duration: widget.stepAnimationDuration, + curve: widget.stepAnimationCurve, + ); + + if (_selectedIndex == i) break; + } + } + + @override + Widget build(BuildContext context) { + lineStyle = widget.lineStyle ?? const LineStyle(); + + return Align( + alignment: widget.alignment, + child: NotificationListener( + onNotification: (OverscrollIndicatorNotification overscroll) { + overscroll.disallowIndicator(); + return false; + }, + child: FittedBox( + fit: widget.fitWidth ? BoxFit.fitWidth : BoxFit.none, + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: _buildEasySteps(), + ), + ) + ), + ); + } + + List _buildEasySteps() { + return List.generate(widget.steps.length, (index) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildStep(index), + _buildLine(index, Axis.horizontal), + ], + ); + }); + } + + BaseStep _buildStep(int index) { + final step = widget.steps[index]; + return BaseStep( + step: step, + radius: widget.stepRadius, + isActive: index == widget.activeStep, + isFinished: widget.reachedSteps != null + ? index < widget.activeStep && widget.reachedSteps.contains(index) + : index < widget.activeStep, + isUnreached: index > widget.activeStep, + isAlreadyReached: widget.reachedSteps != null + ? widget.reachedSteps.contains(index) + : widget.maxReachedStep != null + ? index <= widget.maxReachedStep + : false, + activeStepBackgroundColor: widget.activeStepBackgroundColor, + activeStepBorderColor: widget.activeStepBorderColor, + activeTextColor: widget.activeStepTextColor, + activeIconColor: widget.activeStepIconColor, + unreachedBackgroundColor: widget.unreachedStepBackgroundColor, + unreachedBorderColor: widget.unreachedStepBorderColor, + unreachedTextColor: widget.unreachedStepTextColor, + unreachedIconColor: widget.unreachedStepIconColor, + padding: max(widget.internalPadding, 0), + stepRadius: widget.stepBorderRadius, + showStepBorder: widget.showStepBorder, + lineLength: lineStyle.lineLength, + enabled: widget.steps[index].enabled, + ); + } + + // BorderType _handleBorderType(int index) { + // if (index == widget.activeStep) { + // //Active Step + // return widget.activeStepBorderType ?? widget.defaultStepBorderType; + // } else if (index > widget.activeStep) { + // //Unreached Step + // return widget.unreachedStepBorderType ?? widget.defaultStepBorderType; + // } else if (index < widget.activeStep) { + // //Finished Step + // return widget.finishedStepBorderType ?? widget.defaultStepBorderType; + // } else { + // return widget.defaultStepBorderType; + // } + // } + + Color _getLineColor(int index) { + Color preferredColor; + if (index == widget.activeStep) { + //Active Step + preferredColor = lineStyle.activeLineColor; + } else if (index > widget.activeStep) { + //Unreached Step + preferredColor = lineStyle.unreachedLineColor; + } else if (index < widget.activeStep) { + //Finished Step + preferredColor = lineStyle.finishedLineColor; + } + + return preferredColor ?? + lineStyle.defaultLineColor ?? + Theme.of(context).colorScheme.primary; + } + + Widget _buildLine(int index, Axis axis) { + return index < widget.steps.length - 1 + ? Column( + children: [ + Padding( + padding: EdgeInsets.only( + top: axis == Axis.horizontal + ? (widget.stepRadius - lineStyle.lineThickness) + : 0, + ), + child: _buildBaseLine(index, axis), + ), + if (axis == Axis.horizontal && + widget.steps[index].lineText != null) ...[ + const SizedBox(height: 5), + SizedBox( + width: lineStyle.lineLength, + child: widget.steps[index].customLineWidget ?? + Text( + widget.steps[index].lineText, + maxLines: 3, + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.labelSmall, + ), + ), + ], + ], + ) + : const Offstage(); + } + + EasyLine _buildBaseLine(int index, Axis axis) { + return EasyLine( + length: lineStyle.lineLength, + color: _getLineColor(index), + thickness: lineStyle.lineThickness, + spacing: lineStyle.lineSpace, + width: lineStyle.lineWidth, + axis: axis, + lineType: + index > widget.activeStep - 1 && lineStyle.unreachedLineType != null + ? lineStyle.unreachedLineType + : lineStyle.lineType, + ); + } +} diff --git a/lib/controllers/api_routes/api_manager.dart b/lib/controllers/api_routes/api_manager.dart index 1f53b45c..77a9dfd0 100644 --- a/lib/controllers/api_routes/api_manager.dart +++ b/lib/controllers/api_routes/api_manager.dart @@ -83,6 +83,41 @@ class ApiManager { return response; } + Future postWithOutBody( + String url, { + Map headers, + }) async { + headers ??= {}; + + headers.addAll(_headers); + + Uri _url = Uri.parse(url); + if (!kReleaseMode) { + print("URL:$_url"); + print("Headers:$headers"); + } + + var request = http.Request('POST', _url); + request.headers.addAll(headers); + + http.StreamedResponse _streamedResponse = await request.send(); + http.Response response = await http.Response.fromStream(_streamedResponse); + try { + if (response.statusCode == 401) { + showLoginDialog(); + } else { + if (jsonDecode(response.body) is Map) { + final message = jsonDecode(response.body)["message"]; + if (message != null && message.toString().isNotEmpty) { + Fluttertoast.showToast(msg: message ?? "", toastLength: Toast.LENGTH_LONG); + } + } + } + } catch (ex) {} + + return response; + } + Future put(String url, {Map? headers, required Map body}) async { headers ??= {}; diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index 12be61d2..2722f365 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -25,7 +25,22 @@ class URLs { static get getSites => "$_baseUrl/Customer/GetCustomers"; // get static get getSitesAutoComplete => "$_baseUrl/Customer/GetCustomersAutoComplete"; // get static get getSiteAutoCompleteWithoutConditionSites => "$_baseUrl/Customer/GetCustomersAutoCompleteWithoutConditionSites"; // get - + static get nurseDashboardCountUrl=> '$_baseUrl/ServiceRequest/GetDashboardNurseCount'; + static get nurseDashboardDetailsUrl=> '$_baseUrl/ServiceRequest/GetDashboardNurseDetails'; + static get nurseConfirmReopenUrl=> '$_baseUrl/ServiceRequest/NurseConfirmReopen'; + static get nurseConfirmCloseUrl=> '$_baseUrl/ServiceRequest/NurseConfirmClose'; + static get engineerDashboardCountUrl=> '$_baseUrl/ServiceRequest/GetDashboardEngineerCount'; + static get engineerDashboardDetailsUrl=> '$_baseUrl/ServiceRequest/GetDashboardEngineerDetails'; + static get engineerAcceptUrl=> '$_baseUrl/ServiceRequest/EngineerAccept'; + static get engineerRejectUrl=> '$_baseUrl/ServiceRequest/EngineerReject'; + static get engineerFixRemotlyUrl=> '$_baseUrl/ServiceRequest/EngineerFixRemotly'; + static get engineerNeedVisitUrl=> '$_baseUrl/ServiceRequest/EngineerNeedVisit'; + static get engineerMarkAsFixUrl=> '$_baseUrl/ServiceRequest/EngineerMarkAsFix'; + static get getWorkOrderByIdUrl=> '$_baseUrl/ServiceRequest/GetWorkOrderById'; + static get deleteActivitySparePartUrl=> '$_baseUrl/ServiceRequest/DeleteActivitySparePart'; + static get createActivitySparePartUrl=> '$_baseUrl/ServiceRequest/CreateActivitySparePart'; + static get updateActivitySparePartUrl=> '$_baseUrl/ServiceRequest/UpdateActivitySparePart'; + static get assignEngineerToWorkOrderUrl=> '$_baseUrl/ServiceRequest/AssignEngineerToWorkOrder'; static get getDepartments => "$_baseUrl/Customer/GetDepartmentLookup"; // get static get getAssets => "$_baseUrl/Asset/GetAssets"; // get static get getAssetById => "$_baseUrl/Asset/GetAssetById?assetId="; // get diff --git a/lib/controllers/providers/api/service_requests_provider.dart b/lib/controllers/providers/api/service_requests_provider.dart index d41f9e96..406eb304 100644 --- a/lib/controllers/providers/api/service_requests_provider.dart +++ b/lib/controllers/providers/api/service_requests_provider.dart @@ -1,12 +1,16 @@ import 'dart:convert'; +import 'dart:developer'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:http/http.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; +import 'package:test_sa/controllers/api_routes/http_status_manger.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/models/issue.dart'; import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/service_request/pending_service_request_model.dart'; import 'package:test_sa/models/service_request/service_report.dart'; @@ -26,6 +30,7 @@ class ServiceRequestsProvider extends ChangeNotifier { // number of items call in each request final pageItemNumber = 10; + //reset provider data void reset() { workOrders = []; @@ -37,8 +42,16 @@ class ServiceRequestsProvider extends ChangeNotifier { // state code of current request to defied error message // like 400 customer request failed // 500 service not available - int? stateCode; - bool _isDetialLoading = false; + int stateCode; + bool _isDetialLoading=false; + bool _ackhnowledge = false; + + bool get ackhnowledge => _ackhnowledge; + + set ackhnowledge(bool value) { + _ackhnowledge = value; + notifyListeners(); + } bool get isDetialLoading => _isDetialLoading; @@ -46,23 +59,32 @@ class ServiceRequestsProvider extends ChangeNotifier { _isDetialLoading = value; notifyListeners(); } // true if there is next page in product list and false if not - bool nextPage = true; - TimeOfDay? _selectedTime; + TimeOfDay _selectedTime ; - TimeOfDay? get selectedTime => _selectedTime; + TimeOfDay get selectedTime => _selectedTime; - set selectedTime(TimeOfDay? value) { + set selectedTime(TimeOfDay value) { _selectedTime = value; notifyListeners(); } // list of user requests - - List? serviceRequests; + List serviceRequests; List workOrders = []; + SearchWorkOrder _formWorkOrder=SearchWorkOrder(); + + SearchWorkOrder get formWorkOrder => _formWorkOrder; + + set formWorkOrder(SearchWorkOrder value) { + _formWorkOrder = value; + notifyListeners(); + } + List _sparePartList = []; + + SparePartsWorkOrders _initialSelectedSparePart = SparePartsWorkOrders(); - ServiceRequest? _currentSelectedRequest; + ServiceRequest _currentSelectedRequest; int _selectedListIndex = 0; int get selectedListIndex => _selectedListIndex; @@ -72,17 +94,19 @@ class ServiceRequestsProvider extends ChangeNotifier { notifyListeners(); } - ServiceRequest? get currentSelectedRequest => _currentSelectedRequest; + ServiceRequest get currentSelectedRequest => _currentSelectedRequest; - set currentSelectedRequest(ServiceRequest? value) { + set currentSelectedRequest(ServiceRequest value) { _currentSelectedRequest = value; + print('notify listner for current selected request Called...'); notifyListeners(); } + // when requests in-process _loading = true // done _loading = true // failed _loading = false - bool isLoading = false; + bool isLoading; ServiceRequestSearch search = ServiceRequestSearch(); @@ -91,7 +115,7 @@ class ServiceRequestsProvider extends ChangeNotifier { /// 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 getRequests({required int hospitalId}) async { + Future getRequests({@required int hospitalId}) async { if (isLoading == true) return -2; isLoading = true; if (serviceRequests?.isEmpty ?? false) notifyListeners(); @@ -113,7 +137,7 @@ class ServiceRequestsProvider extends ChangeNotifier { List requestsListJson = json.decode(response.body)["data"]; List serviceRequestsPage = requestsListJson.map((request) => ServiceRequest.fromJson(request)).toList(); serviceRequests ??= []; - serviceRequests!.addAll(serviceRequestsPage); + serviceRequests.addAll(serviceRequestsPage); notifyListeners(); if (serviceRequestsPage.length == pageItemNumber) { nextPage = true; @@ -132,46 +156,46 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - // Future getSingleServiceRequest({ - // required String requestId, - // required String host, - // required User user, - // required AppLocalizations subtitle, - // }) async { - // String userData = ''; - // if (user != null) { - // userData += "&uid=" + user!.id!; - // userData += "&token=" + user!.token!; - // } - // - // Response response; - // try { - // response = await get(Uri.parse( - // host + - // URLs.getSingleServiceRequest + - // '?call_nid=$requestId' - // '$userData', - // )); - // } catch (error) { - // throw (HttpStatusManger.getStatusMessage(status: -1, subtitle: subtitle)); - // } - // - // // If the call to the server was successful, parse the JSON. - // if (response.statusCode >= 200 && response.statusCode < 300) { - // // If the call to the server was successful, parse the JSON. - // List jsonList = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", "")); - // List _requests = jsonList.map((i) => ServiceRequest.fromJson(i)).toList(); - // return _requests[0]; - // } else { - // throw (HttpStatusManger.getStatusMessage(status: response.statusCode, subtitle: subtitle)); - // } - // } + Future getSingleServiceRequest({ + @required String requestId, + @required String host, + @required User user, + @required AppLocalizations subtitle, + }) async { + String userData = ''; + if (user != null) { + userData += "&uid=" + user.id; + userData += "&token=" + user.token; + } + + Response response; + try { + response = await get(Uri.parse( + host + + URLs.getSingleServiceRequest + + '?call_nid=$requestId' + '$userData', + )); + } catch (error) { + throw (HttpStatusManger.getStatusMessage(status: -1, subtitle: subtitle)); + } + + // If the call to the server was successful, parse the JSON. + if (response.statusCode >= 200 && response.statusCode < 300) { + // If the call to the server was successful, parse the JSON. + List jsonList = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", "")); + List _requests = jsonList.map((i) => ServiceRequest.fromJson(i)).toList(); + return _requests[0]; + } else { + throw (HttpStatusManger.getStatusMessage(status: response.statusCode, subtitle: subtitle)); + } + } Future createRequest({ - required BuildContext context, - required String host, - required User user, - required ServiceRequest serviceRequest, + @required BuildContext context, + @required String host, + @required User user, + @required ServiceRequest serviceRequest, }) async { var body = { "id": 0, @@ -182,7 +206,7 @@ class ServiceRequestsProvider extends ChangeNotifier { "requestedTime": DateTime.now().toIso8601String(), "client": user.clientId, "callComments": serviceRequest.callComments, - if (serviceRequest.devicePhotos?.isNotEmpty ?? false) "attachmentsCallRequest": serviceRequest.devicePhotos!.map((e) => {"name": e}).toList(), + if (serviceRequest.devicePhotos.isNotEmpty) "attachmentsCallRequest": serviceRequest.devicePhotos.map((e) => {"name": e}).toList(), "priority": serviceRequest.priority?.toJson(), "defectType": serviceRequest.defectType?.toJson(), "typeofRequest": serviceRequest.type?.toJson(), @@ -223,7 +247,7 @@ class ServiceRequestsProvider extends ChangeNotifier { if (serviceRequests != null) { var data = json.decode(utf8.decode(response.bodyBytes)); if (data is List) { - serviceRequests!.insert(0, ServiceRequest.fromJson(data[0])); + serviceRequests.insert(0, ServiceRequest.fromJson(data[0])); } else { if (data["data"] != null && data["data"] == true) { // serviceRequests.insert(0, ServiceRequest.fromJson(data[0])); @@ -243,33 +267,33 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - // Future createIssueReport({ - // required String host, - // required User user, - // required Issue issue, - // }) async { - // Response response; - // Map body = issue.toMap(); - // body["uid"] = user.id; - // body["token"] = user.token; - // try { - // response = await post( - // Uri.parse(host + URLs.createReport), - // body: body, - // ); - // - // stateCode = response.statusCode; - // if (response.statusCode >= 200 && response.statusCode < 300) {} - // return response.statusCode; - // } catch (error) { - // return -1; - // } - // } - - Future checkAssetPendingRequest(int assetId) async { + Future createIssueReport({ + @required String host, + @required User user, + @required Issue issue, + }) async { Response response; + Map body = issue.toMap(); + body["uid"] = user.id; + body["token"] = user.token; try { - response = await ApiManager.instance.get(URLs.CheckIfAssetHasAnotherServiceRequest + "?assetId=$assetId"); + response = await post( + Uri.parse(host + URLs.createReport), + body: body, + ); + + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) {} + return response.statusCode; + } catch (error) { + return -1; + } + } + + Future checkAssetPendingRequest(int assetId) async { + Response response; + try { + response = await await ApiManager.instance.get(URLs.CheckIfAssetHasAnotherServiceRequest + "?assetId=$assetId"); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) {} return PendingAssetServiceRequest.fromJson(json.decode(response.body)["data"]); @@ -279,16 +303,16 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - Future updateRequest({required User user, required ServiceRequest request}) async { + Future updateRequest({@required User user, @required ServiceRequest request}) async { isLoading = true; notifyListeners(); - Map serviceRequest = await getServiceRequestById(requestId: request.id!); + Map serviceRequest = await getServiceRequestById(requestId: request.id) ?? ""; final List callSiteContacts = (serviceRequest['callSiteContactPerson'] as List); final Map callSiteContactPerson = callSiteContacts.isEmpty ? {} : callSiteContacts[0]; Response response; try { if ((request.audio ?? "").isNotEmpty) { - request.audio = request.audio!.substring(request.audio!.indexOf("=") + 1, request.audio!.length); + request.audio = request.audio.substring(request.audio.indexOf("=") + 1, request.audio.length); } } catch (ex) {} @@ -304,7 +328,7 @@ class ServiceRequestsProvider extends ChangeNotifier { "requestedThrough": request.requestedThrough?.toJson(), "voiceNote": request.audio, "assets": request.deviceId == null ? [] : [request.deviceId], - "attachmentsCallRequest": (request.devicePhotos?.isNotEmpty ?? false) ? request.devicePhotos?.map((e) => {"name": e.getFileName}).toList() : [], + "attachmentsCallRequest": (request.devicePhotos?.isNotEmpty ?? false) ? request.devicePhotos?.map((e) => {"name": e.getFileName})?.toList() : [], "assignedEmployee": { "id": request.engineerId, "name": request.engineerName, @@ -363,12 +387,12 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - Future createServiceReport(BuildContext context, {required ServiceReport report, required User user, required ServiceRequest request}) async { + Future createServiceReport(BuildContext context, {@required ServiceReport report, @required User user, @required ServiceRequest request}) async { Response response; try { showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); final body = report.toJson(); - final callRequest = CallRequest(id: num.tryParse(request.id ?? "")).toJson(); + final callRequest = CallRequest(id: num.tryParse(request?.id ?? "")).toJson(); final contactPerson = [ { "id": 0, @@ -402,7 +426,7 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - Future createSubWorkOrder({required SearchWorkOrder workOrder, bool makeSuppPersonsEmpty = false}) async { + Future createSubWorkOrder({@required SearchWorkOrder workOrder, bool makeSuppPersonsEmpty = false}) async { Response response; try { if (makeSuppPersonsEmpty) workOrder.supplier?.suppPersons = []; @@ -420,17 +444,19 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - CallRequest? callRequestForWorkOrder; + CallRequest callRequestForWorkOrder; - Future getCallRequestForWorkOrder({required String callId}) async { + Future getCallRequestForWorkOrder({String callId}) async { Response response; try { - response = await ApiManager.instance.get(URLs.getCallRequestForWorkOrder + "?callId=$callId"); + response = await ApiManager.instance.get( + URLs.getCallRequestForWorkOrder + "?callId=$callId", + ); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received Map listJson = json.decode(response.body)["data"]; - // log(listJson?.toString()); + log(listJson?.toString()); callRequestForWorkOrder = CallRequest.fromJson(listJson); } @@ -442,13 +468,13 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - Future> searchWorkOrders({required String callId}) async { + Future> searchWorkOrders({@required String callId}) async { Response response; try { var body = { "pageSize": pageItemNumber, - "pageNumber": ((workOrders.length ?? 0) ~/ pageItemNumber) + 1, + "pageNumber": ((workOrders?.length ?? 0) ~/ pageItemNumber) + 1, "callId": callId, }; response = await ApiManager.instance.post(URLs.searchWorkOrders, body: body); @@ -469,7 +495,7 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - Future getSubWorkOrderDetails({required String parentId}) async { + Future getSubWorkOrderDetails({@required String parentId}) async { Response response; try { response = await ApiManager.instance.get(URLs.getSubWorkerInfoAccordingToPreviousStep + "?parentId=$parentId"); @@ -486,38 +512,38 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - // Future createDuplicatedReport({ - // required String host, - // required User user, - // required ServiceRequest request, - // }) async { - // Response response; - // String userData = ''; - // if (user != null) { - // userData += "&uid=" + user.id; - // userData += "&token=" + user.token; - // } - // - // try { - // response = await get( - // Uri.parse(host + URLs.createDuplicatedReport + "?nid=${request.id}" + userData), - // ); - // - // stateCode = response.statusCode; - // - // if (response.statusCode >= 200 && response.statusCode < 300) { - // reset(); - // notifyListeners(); - // } - // return response.statusCode; - // } catch (error) { - // return -1; - // } - // } - - Future updateServiceReport(BuildContext context, {required ServiceReport report}) async { + Future createDuplicatedReport({ + @required String host, + @required User user, + @required ServiceRequest request, + }) async { + Response response; + String userData = ''; + if (user != null) { + userData += "&uid=" + user.id; + userData += "&token=" + user.token; + } + + try { + response = await get( + Uri.parse(host + URLs.createDuplicatedReport + "?nid=${request.id}" + userData), + ); + + stateCode = response.statusCode; + + if (response.statusCode >= 200 && response.statusCode < 300) { + reset(); + notifyListeners(); + } + return response.statusCode; + } catch (error) { + return -1; + } + } + + Future updateServiceReport(BuildContext context, {@required ServiceReport report}) async { Response response; - report.callRequest = CallRequest(id: report.callRequest!.id!); + report.callRequest = CallRequest(id: report.callRequest.id); Map body = report.toJson(); try { showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); @@ -528,7 +554,7 @@ class ServiceRequestsProvider extends ChangeNotifier { Fluttertoast.showToast(msg: context.translation.successfulRequestMessage); Navigator.of(context).pop(); } else { - Fluttertoast.showToast(msg: context.translation.failedToCompleteRequest); + Fluttertoast.showToast(msg: "${context.translation.failedToCompleteRequest}"); } Navigator.of(context).pop(); return response.statusCode; @@ -539,7 +565,7 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - Future updateWorkOrderDetails({required SearchWorkOrder workOrder}) async { + Future updateWorkOrderDetails({@required SearchWorkOrder workOrder}) async { Response response; //Map body = report.toMap(request); // body["uid"] = user.id; @@ -568,15 +594,20 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - Future updateServiceReportTimer({required String host, required User user, required TimerModel timer, required ServiceRequest request}) async { + Future updateServiceReportTimer({ + @required String host, + @required User user, + @required TimerModel timer, + @required ServiceRequest request, + }) async { Response response; Map body = {}; body["uid"] = user.id; body["token"] = user.token; body["job_id"] = request.id; - body["start_time"] = (timer.startAt!.millisecondsSinceEpoch / 1000).toStringAsFixed(0); - body["end_time"] = (timer.endAt!.millisecondsSinceEpoch / 1000).toStringAsFixed(0); - body["working_hours"] = (timer.durationInSecond! / 60 / 60).toStringAsFixed(5); + body["start_time"] = (timer.startAt.millisecondsSinceEpoch / 1000).toStringAsFixed(0); + body["end_time"] = (timer.endAt.millisecondsSinceEpoch / 1000).toStringAsFixed(0); + body["working_hours"] = (timer.durationInSecond / 60 / 60).toStringAsFixed(5); body["report_id"] = request.reportID; try { response = await post( @@ -595,7 +626,7 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - Future getSingleServiceReport(BuildContext context, {required int reportId}) async { + Future getSingleServiceReport(BuildContext context, {@required int reportId}) async { Response response; try { response = await ApiManager.instance.get(URLs.getServiceReport + "?workOrderId=$reportId"); @@ -612,27 +643,29 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - Future getServiceRequestObjectById({required String requestId}) async { + Future getServiceRequestObjectById({@required String requestId}) async { try { isDetialLoading = true; Response response = await ApiManager.instance.get(URLs.getServiceRequestById + "?callRequestId=$requestId"); if (response.statusCode >= 200 && response.statusCode < 300) { - isDetialLoading = false; + isDetialLoading=false; return ServiceRequest.fromJson(json.decode(response.body)["data"]); } else { - isDetialLoading = false; + isDetialLoading=false; return null; } } catch (error) { - isDetialLoading = false; + isDetialLoading=false; return null; } } - Future> getServiceRequestById({required String requestId}) async { + Future> getServiceRequestById({@required String requestId}) async { Response response; try { - response = await ApiManager.instance.get(URLs.getServiceRequestById + "?callRequestId=$requestId"); + response = await ApiManager.instance.get( + URLs.getServiceRequestById + "?callRequestId=$requestId", + ); } catch (error) { print(error); return {}; @@ -662,17 +695,20 @@ class ServiceRequestsProvider extends ChangeNotifier { try { var body = { "pageSize": pageItemNumber, - "pageNumber": ((workOrders.length ?? 0) ~/ pageItemNumber) + 1, - if (callerId.isNotEmpty ?? false) "callId": callerId, + "pageNumber": ((workOrders?.length ?? 0) ~/ pageItemNumber) + 1, + if (callerId?.isNotEmpty ?? false) "callId": callerId, if (search.assetType != null) "assetSerialNo": search.assetType?.name, if (search.workOrderNo != null) "workOrderNo": search.workOrderNo, - if (search.id != null) "workOrderNo": search.id.toString(), - if (search.calllastSituation != null) "callslastSituationWO": search.calllastSituation!.toJson(), - if (search.assignedEmployee != null) "assignedEmployees": [search.assignedEmployee!.id], + if (search.id != null) "workOrderNo": search.id?.toString(), + if (search.calllastSituation != null) "callslastSituationWO": search.calllastSituation.toJson(), + if (search.assignedEmployee != null) + "assignedEmployees": [ + search.assignedEmployee.id, + ], // "statusWO": [], - if (site.isNotEmpty ?? false) "site": site, - if (search.visitDate != null) "visitDateSymbol": dateOperator.toJson(), - if (search.visitDate != null) "visitDateFrom": search.visitDate, + if (site?.isNotEmpty ?? false) "site": site, + if (search.visitDate != null && dateOperator != null) "visitDateSymbol": dateOperator?.toJson(), + if (search.visitDate != null && dateOperator != null) "visitDateFrom": search.visitDate, }; print(body); response = await ApiManager.instance.post(URLs.searchWorkOrders, body: body); @@ -695,11 +731,11 @@ class ServiceRequestsProvider extends ChangeNotifier { } } - Future addSupplierEngineer(SupplierEngineer supplierEngineer) async { + Future addSupplierEngineer(SupplierEngineer supplierEngineer) async { isLoading = true; notifyListeners(); Response response; - SuppEngineerWorkOrders? res; + SuppEngineerWorkOrders res; try { response = await ApiManager.instance.post(URLs.addSupplierEngineer, body: supplierEngineer.toJson()); stateCode = response.statusCode; @@ -722,7 +758,6 @@ class ServiceRequestsProvider extends ChangeNotifier { _initialSelectedSparePart = value; notifyListeners(); } - List get sparePartList => _sparePartList; set sparePartList(List value) { diff --git a/lib/dashboard_latest/dashboard_provider.dart b/lib/dashboard_latest/dashboard_provider.dart new file mode 100644 index 00000000..715ff72a --- /dev/null +++ b/lib/dashboard_latest/dashboard_provider.dart @@ -0,0 +1,142 @@ +import 'dart:convert'; +import 'package:flutter/widgets.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/enums/user_types.dart'; +import 'package:test_sa/models/new_models/dashboardCount.dart'; +import 'package:test_sa/models/new_models/dashboard_detail.dart'; + +class DashBoardProvider extends ChangeNotifier { + bool isAllCountLoading = false; + bool isLoading = false; + bool _isDetailLoading = false; + + int _status =0; + + + int get status => _status; + + set status(int value) { + _status = value; + notifyListeners(); + } + + int _currentListIndex = 0; + + int get currentListIndex => _currentListIndex; + + set currentListIndex(int value) { + _currentListIndex = value; + notifyListeners(); + } + + int stateCode; + + DashboardCount dashboardCount; + + DashboardDetail _requestDetailList; + + DashboardDetail get requestDetailList => _requestDetailList; + + set requestDetailList(DashboardDetail value) { + _requestDetailList = value; + notifyListeners(); + } + + final pageItemNumber = 10; + int pageNum = 1; + bool nextPage = true; + + void reset() { + pageNum = 1; + nextPage = true; + stateCode = null; + } + + + Future getDashBoardCount({@required UsersTypes usersType}) async { + isAllCountLoading = true; + String url=''; + if(usersType==UsersTypes.engineer){ + url = URLs.engineerDashboardCountUrl; + } + if(usersType==UsersTypes.nurse){ + url=URLs.nurseDashboardCountUrl; + } + Response response; + try { + response = await ApiManager.instance.postWithOutBody(url); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + dashboardCount = DashboardCount.fromJson(json.decode(response.body)); + } + notifyListeners(); + isAllCountLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isAllCountLoading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } + + + Future getRequestDetail({bool showLoader = true,UsersTypes usersType, int status}) async { + isDetailLoading =showLoader; + Response response; + String url=''; + if(usersType==UsersTypes.engineer){ + url = URLs.engineerDashboardDetailsUrl; + } + if(usersType==UsersTypes.nurse){ + url=URLs.nurseDashboardDetailsUrl; + } + try { + Map body = { + "statusValue": status, + "pageNumber": pageNum, + "pageSize" : pageItemNumber, + }; + response = await ApiManager.instance.post(url, body: body); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + if (requestDetailList == null) { + requestDetailList = DashboardDetail.fromJson(json.decode(response.body)); + isDetailLoading = false; + notifyListeners(); + } else { + requestDetailList.data.addAll(DashboardDetail.fromJson(json.decode(response.body)["data"][0]).data); + isDetailLoading = false; + notifyListeners(); + } + if (requestDetailList.data.length >= pageItemNumber) { + nextPage = true; + } else { + nextPage = false; + } + notifyListeners(); + } else { + requestDetailList = null; + } + isDetailLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isDetailLoading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } + + bool get isDetailLoading => _isDetailLoading; + + set isDetailLoading(bool value) { + _isDetailLoading = value; + notifyListeners(); + } + +} diff --git a/lib/dashboard_latest/dashboard_view.dart b/lib/dashboard_latest/dashboard_view.dart index c985f827..a9348703 100644 --- a/lib/dashboard_latest/dashboard_view.dart +++ b/lib/dashboard_latest/dashboard_view.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -9,37 +10,42 @@ import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/controllers/providers/api/notifications_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/dashboard_latest/dashboard_provider.dart'; import 'package:test_sa/dashboard_latest/widgets/app_bar_widget.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/user.dart'; -import 'package:test_sa/new_views/pages/land_page/dashboard_fragments/progress_fragment.dart'; -import 'package:test_sa/new_views/pages/land_page/dashboard_fragments/requests_fragment.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/dashboard_latest/widgets/progress_fragment.dart'; +import 'package:test_sa/dashboard_latest/widgets/requests_fragment.dart'; +import 'package:test_sa/service_request_latest/request_detail_provider.dart'; import 'package:test_sa/utilities/request_utils.dart'; -import '../new_views/pages/land_page/dashboard_fragments/request_category_fragment.dart'; +import 'widgets/request_category_fragment.dart'; class DashboardView extends StatefulWidget { final VoidCallback onDrawerPress; - const DashboardView({Key? key, required this.onDrawerPress}) : super(key: key); + const DashboardView({Key key, this.onDrawerPress}) : super(key: key); @override State createState() => _DashboardViewState(); } class _DashboardViewState extends State { - final int _currentPage = 0; + int _currentPage = 0; bool isFCM = true; - late User user; + User user; - late SettingProvider settingProvider; - late UserProvider userProvider; + SettingProvider settingProvider; + UserProvider userProvider; - late AllRequestsProvider allRequestsProvider; + AllRequestsProvider allRequestsProvider; - late NotificationsProvider notificationsProvider; - late ScrollController _scrollController; + NotificationsProvider notificationsProvider; + ScrollController _scrollController; @override void initState() { @@ -52,15 +58,19 @@ class _DashboardViewState extends State { scheduleMicrotask(() async { userProvider = Provider.of(context, listen: false); settingProvider = Provider.of(context, listen: false); + RequestDetailProvider requestDetailProvider = Provider.of(context, listen: false); allRequestsProvider = Provider.of(context, listen: false); notificationsProvider = Provider.of(context, listen: false); - user = userProvider.user!; + user = userProvider.user; + log('user token i got is ${user.token}'); + await getAllRequests(); + await requestDetailProvider.engineerRejectWorkOrder(id: '3',feedBack: 'Abcdef'); if (isFCM) { FirebaseNotificationManger.initialized(context); NotificationManger.initialisation((notificationDetails) { - FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!)); + FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload)); }, (id, title, body, payload) async {}); isFCM = false; @@ -73,27 +83,30 @@ class _DashboardViewState extends State { allRequestsProvider.isFilterRequestLoading = true; allRequestsProvider.currentListIndex = 0; allRequestsProvider.filterRequest = null; - var tabs = RequestUtils.getTabs(userType: userProvider.user!.type!, context: context); + var tabs = RequestUtils.getTabs(userType: userProvider.user.type, context: context); allRequestsProvider.status = tabs[0]['status']; - allRequestsProvider.getRequests(); - allRequestsProvider.pageNum = 1; - allRequestsProvider.getFilterRequests(showLoader: true, status: tabs[0]['status']).whenComplete(() { - allRequestsProvider.requestDetailList = allRequestsProvider.filterRequest; - }); - allRequestsProvider.isAllLoading = false; - notificationsProvider.getSystemNotifications(user: userProvider.user!, resetProvider: true); + allRequestsProvider.getRequests(); + allRequestsProvider.pageNum = 1; + allRequestsProvider.getFilterRequests(showLoader: true, status: tabs[0]['status']).whenComplete(() { + allRequestsProvider.requestDetailList = allRequestsProvider.filterRequest; + }); + allRequestsProvider.isAllLoading = false; + notificationsProvider.getSystemNotifications(user: userProvider.user, resetProvider: true); } - void handleScroll() async { + void handleScroll() async{ _scrollController = ScrollController(); _scrollController.addListener(() async { - if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent && !allRequestsProvider.isFilterRequestLoading) { + if (_scrollController?.position?.pixels == + _scrollController?.position?.maxScrollExtent && + !allRequestsProvider.isFilterRequestLoading) { allRequestsProvider.pageNum = allRequestsProvider.pageNum + 1; - await allRequestsProvider.getFilterRequests(showLoader: false, status: allRequestsProvider.status); + await allRequestsProvider.getFilterRequests(showLoader:false,status: allRequestsProvider.status); } }); } + @override void dispose() { _scrollController.dispose(); @@ -104,21 +117,33 @@ class _DashboardViewState extends State { Widget build(BuildContext context) { return Scaffold( // backgroundColor: AppColor.background(context), - appBar: PreferredSize(preferredSize: const Size.fromHeight(kToolbarHeight), child: AppBarWidget(onDrawerPress: widget.onDrawerPress)), + appBar: PreferredSize( + preferredSize: const Size.fromHeight(kToolbarHeight), + child: AppBarWidget( + onDrawerPress: widget.onDrawerPress, + )), body: RefreshIndicator( onRefresh: () async { - getInitialData(); + getInitialData(); return Future.delayed(const Duration(milliseconds: 250)); }, child: Scrollbar( controller: _scrollController, child: SingleChildScrollView( - // physics: AlwaysScrollableScrollPhysics(), - controller: _scrollController, + // physics: AlwaysScrollableScrollPhysics(), + controller: _scrollController, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, - children: [14.height, ProgressFragment(), 25.height, SizedBox(height: 110.toScreenHeight, child: const RequestsFragment()), 16.height, const RequestCategoryFragment()], + children: [ + 14.height, + ProgressFragment(), + 25.height, + SizedBox( + height: 110.toScreenHeight, child: const RequestsFragment()), + 16.height, + const RequestCategoryFragment() + ], ).paddingOnly(start: 16, end: 16, top: 0, bottom: 8), ), ), diff --git a/lib/new_views/pages/land_page/dashboard_fragments/progress_fragment.dart b/lib/dashboard_latest/widgets/progress_fragment.dart similarity index 95% rename from lib/new_views/pages/land_page/dashboard_fragments/progress_fragment.dart rename to lib/dashboard_latest/widgets/progress_fragment.dart index edf6ec95..6c316a10 100644 --- a/lib/new_views/pages/land_page/dashboard_fragments/progress_fragment.dart +++ b/lib/dashboard_latest/widgets/progress_fragment.dart @@ -14,7 +14,7 @@ // import '../../../../models/enums/user_types.dart'; // // class ProgressFragment extends StatelessWidget { -// ProgressFragment({Key? key}) : super(key: key); +// ProgressFragment({Key key}) : super(key: key); // // UserProvider _userProvider; // @@ -159,18 +159,20 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; -import '../../../../controllers/providers/api/user_provider.dart'; -import '../../../../models/enums/user_types.dart'; +import '../../controllers/providers/api/user_provider.dart'; +import '../../models/enums/user_types.dart'; class ProgressFragment extends StatelessWidget { - ProgressFragment({Key? key}) : super(key: key); + ProgressFragment({Key key}) : super(key: key); - late UserProvider _userProvider; + UserProvider _userProvider; + + AllRequestsProvider _provider; @override Widget build(BuildContext context) { _userProvider = Provider.of(context); - bool isCurrentUserNotEngineer = (_userProvider.user!.type != UsersTypes.engineer); + bool isCurrentUserNotEngineer = (_userProvider.user.type != UsersTypes.engineer); return Consumer( builder: (context, snapshot, _) { int total = (snapshot.completedRequests?.total?.count ?? 0) + (snapshot.inProgressRequests?.total?.count ?? 0) + (isCurrentUserNotEngineer ? (snapshot.openRequests?.total?.count ?? 0) : 0); @@ -184,9 +186,6 @@ class ProgressFragment extends StatelessWidget { if (isCurrentUserNotEngineer) { chartData.insert(1, ChartData('Open', snapshot.openRequests?.total?.count?.toDouble() ?? 0.0, AppColor.blueStatus(context))); } - print('conditon value is ${snapshot.isInProgressLoading}'); - print('conditon value is ${snapshot.isCompleteLoading}'); - print('conditon value is ${snapshot.isOpenLoading}'); return Column( children: [ diff --git a/lib/new_views/pages/land_page/dashboard_fragments/recent_activites_fragment.dart b/lib/dashboard_latest/widgets/recent_activites_fragment.dart similarity index 100% rename from lib/new_views/pages/land_page/dashboard_fragments/recent_activites_fragment.dart rename to lib/dashboard_latest/widgets/recent_activites_fragment.dart diff --git a/lib/new_views/pages/land_page/dashboard_fragments/request_category_fragment.dart b/lib/dashboard_latest/widgets/request_category_fragment.dart similarity index 99% rename from lib/new_views/pages/land_page/dashboard_fragments/request_category_fragment.dart rename to lib/dashboard_latest/widgets/request_category_fragment.dart index ea25ae5f..8576b8cb 100644 --- a/lib/new_views/pages/land_page/dashboard_fragments/request_category_fragment.dart +++ b/lib/dashboard_latest/widgets/request_category_fragment.dart @@ -80,7 +80,7 @@ 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/new_views/common_widgets/tab_button.dart'; -import 'package:test_sa/new_views/pages/land_page/dashboard_fragments/request_category_list.dart'; +import 'package:test_sa/dashboard_latest/widgets/request_category_list.dart'; import 'package:test_sa/utilities/request_utils.dart'; class RequestCategoryFragment extends StatelessWidget { diff --git a/lib/new_views/pages/land_page/dashboard_fragments/request_category_list.dart b/lib/dashboard_latest/widgets/request_category_list.dart similarity index 100% rename from lib/new_views/pages/land_page/dashboard_fragments/request_category_list.dart rename to lib/dashboard_latest/widgets/request_category_list.dart diff --git a/lib/new_views/pages/land_page/dashboard_fragments/requests_fragment.dart b/lib/dashboard_latest/widgets/requests_fragment.dart similarity index 100% rename from lib/new_views/pages/land_page/dashboard_fragments/requests_fragment.dart rename to lib/dashboard_latest/widgets/requests_fragment.dart diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index fef79a7d..bcab7808 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -10,6 +10,14 @@ extension StringExtensions on String { DateTime dateTime = DateTime.parse(this); return "${DateFormat('dd MMM, yyyy').format(dateTime)}\n${DateFormat('hh:mm a').format(dateTime)}"; } + String get toDragAbleTimerFormat { + DateTime dateTime = DateTime.tryParse(this); + return DateFormat('HH:mm:ss').format(dateTime); + } + String get toInitialVisitCardFormat { + DateTime dateTime = DateTime.tryParse(this); + return "${DateFormat('dd MMM, yyyy').format(dateTime)} at ${DateFormat('hh:mm a').format(dateTime)}"; + } String get toServiceRequestDetailsFormat { try { diff --git a/lib/extensions/text_extensions.dart b/lib/extensions/text_extensions.dart index 99aed3a7..581fd843 100644 --- a/lib/extensions/text_extensions.dart +++ b/lib/extensions/text_extensions.dart @@ -16,7 +16,7 @@ extension TextStyles on String { Text heading4(BuildContext context) => getTextWithStyle(this, AppTextStyles.heading4, context.isDark ? AppColor.neutral30 : AppColor.neutral50); Text heading5(BuildContext context) => getTextWithStyle(this, AppTextStyles.heading5, context.isDark ? AppColor.neutral30 : AppColor.neutral50); - + Text bottomSheetHeadingTextStyle(BuildContext context) => getTextWithStyle(this, AppTextStyles.bottomSheetHeadingTextStyle, context.isDark ? AppColor.neutral30 : AppColor.black20); Text customHeadingText(BuildContext context) => getTextWithStyle(this, AppTextStyles.customHeadingText, context.isDark ? AppColor.neutral30 : AppColor.neutral50); Text heading6(BuildContext context) => getTextWithStyle(this, AppTextStyles.heading6, context.isDark ? AppColor.neutral30 : AppColor.neutral50); @@ -33,18 +33,11 @@ extension TextStyles on String { } extension CustomText on Text { - Text custom({ - Color? color, - FontWeight? fontWeight, - TextAlign? align, - double? fontSize, - double? lineHeight, - double? letterSpacing, - }) { + Text custom({Color color, FontWeight fontWeight, TextAlign align,double fontSize,double lineHeight,double letterSpacing}) { return Text( - data!, + data, textAlign: align, - style: style?.copyWith( + style: style.copyWith( color: color, height: lineHeight, letterSpacing: letterSpacing, @@ -93,17 +86,19 @@ abstract class AppTextStyles { fontStyle: FontStyle.normal, decoration: TextDecoration.none, ); - static const TextStyle customHeadingText = TextStyle( - fontFamily: 'Poppins', - fontSize: 27, - // Font size in logical pixels + static final TextStyle bottomSheetHeadingTextStyle = TextStyle( + fontSize: 21.toScreenWidth, fontWeight: FontWeight.w500, - // Equivalent to font-weight: 500 - height: 31 / 27, - // Line height (in Flutter, it's a multiplier of font size) - letterSpacing: -0.04 * 27, - // Letter spacing, converted to logical pixels - color: Colors.black, // Set your desired text color + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ); + static const TextStyle customHeadingText = TextStyle( + fontFamily: 'Poppins', + fontSize: 27, // Font size in logical pixels + fontWeight: FontWeight.w500, // Equivalent to font-weight: 500 + height: 31 / 27, // Line height (in Flutter, it's a multiplier of font size) + letterSpacing: -0.04 * 27, // Letter spacing, converted to logical pixels + color: Colors.black, // Set your desired text color ); static final TextStyle heading6 = TextStyle( @@ -133,6 +128,12 @@ abstract class AppTextStyles { fontStyle: FontStyle.normal, decoration: TextDecoration.none, ); + static final TextStyle tinyFont2 = TextStyle( + fontSize: 10.toScreenWidth, + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + decoration: TextDecoration.none, + ); static final TextStyle overline = TextStyle( fontSize: 9.toScreenWidth, @@ -154,31 +155,31 @@ extension CapExtension on String { String get capitalizeFirstOfEach => trim().isNotEmpty ? trim().toLowerCase().split(" ").map((str) { - return str.trim().inCaps ?? ""; + return str.trim()?.inCaps ?? ""; }).join(" ") : ""; } extension FilesExtension on String { SvgPicture toSvgAsset({ - int? width, - int? height, - Color? color, + int width, + int height, + Color color, BoxFit fit = BoxFit.contain, }) => SvgPicture.asset("assets/images/$this.svg", width: width?.toScreenWidth, height: height?.toScreenHeight, color: color, fit: fit); Image toPngAsset({ - int? width, - int? height, - Color? color, + int width, + int height, + Color color, BoxFit fit = BoxFit.contain, }) => Image.asset("assets/images/$this.png", width: width?.toScreenWidth, height: height?.toScreenHeight, color: color, fit: fit); LottieBuilder toLottieAsset({ - int? width, - int? height, + int width, + int height, BoxFit fit = BoxFit.contain, bool repeat = true, }) => diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 4f01cf1c..a183c640 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -1,3 +1,4 @@ +import 'package:another_flushbar/flushbar.dart'; import 'package:flutter/material.dart'; import 'package:shimmer/shimmer.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -12,11 +13,35 @@ extension WidgetExtensions on Widget { Widget get center => Center(child: this); - BoxShadow get boxShadowR14 => BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 14, offset: const Offset(0, 0), spreadRadius: 0); + BoxShadow get boxShadowR14 => BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 5, offset: const Offset(0, 0), spreadRadius: 0); Widget circle(double value) => ClipRRect(borderRadius: BorderRadius.circular(value), child: this); Widget paddingAll(double value) => Padding(padding: EdgeInsets.all(value), child: this); + Widget indicatorWidget({double height,double width,Color color})=> Container( + width: height??40.toScreenWidth, + height: width??5.toScreenHeight, + decoration: BoxDecoration(color:color?? AppColor.white50, borderRadius: BorderRadius.circular(30)), + child: this, + ); + Widget flushBar({@required BuildContext context,String title,String message,double duration,Color backgroundColor})=>Flushbar( + flushbarPosition: FlushbarPosition.TOP, + backgroundColor:backgroundColor?? AppColor.green70, + title: title ?? "Hey Ninja", + message: message ?? "Lorem Ipsum is simply dummy text of the printing and typesetting industry", + duration: Duration(seconds: duration ?? 3), + flushbarStyle: FlushbarStyle.GROUNDED, + reverseAnimationCurve: Curves.easeInOut, + mainButton: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon( + Icons.close, + color: AppColor.white20, + ), + ), + )..show(context); Widget paddingOnly({int start = 0, int end = 0, int top = 0, int bottom = 0}) => Padding(padding: EdgeInsetsDirectional.only(start: start.toScreenWidth, end: end.toScreenWidth, top: top.toScreenHeight, bottom: bottom.toScreenHeight), child: this); @@ -62,6 +87,15 @@ extension WidgetExtensions on Widget { child: this, ) : this; + Widget bottomSheetContainer(BuildContext context, { EdgeInsets padding}) => Container( + clipBehavior: Clip.antiAlias, + margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + decoration: BoxDecoration( + color:AppColor.background(context), + borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), + ), + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), + child: this,); Widget toShadowCircleContainer(BuildContext context, {bool showShadow = true, double padding = 16}) => showShadow ? Container( diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index b97076ed..da5cb730 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -73,6 +73,21 @@ "brand": "ماركة", "clearSearch": "تنظيف البحث", "closed": "غلق", + "close": "يغلق", + "attachFiles": "إرفاق الملفات", + "hours": "ساعات", + "internal": "داخلي", + "external": "خارجي", + "addInternalActivity": "إضافة نشاط داخلي", + "addExternalActivity": "إضافة نشاط خارجي", + "remotely": "عن بُعد", + "workshop": "ورشة", + "activityStatus": "حالة النشاط", + "scanOrPickAsset": "امسح أو اختر الأصل", + "takeAction": "اتخذ إجراء", + "pleaseConfirmTheIssueHasBeenResolved": "يرجى تأكيد أن المشكلة قد تم حلها", + "nurseAcknowledge": "أقر بإكمال أمر العمل هذا", + "abroad": "خارج البلاد", "create": "انشاء", "createServiceRequest": "انشاء طلب خدمة", "delete": "مسح", @@ -269,9 +284,25 @@ "requiredField" : "الحقل مطلوب", "passwordLengthMessage" : "يجب أن تتكون كلمة السر من 6 خانات على الأقل", "overview" : "نظرة عامة", - "myRequests" : "طلباتي", - "myAssets" : "ممتلكاتي", - "contactUs": "اتصل بنا", + "request" : "طلب", + "assets" : "الأصول", + "contact": "اتصال", + "feedBack": "تعليقات", + "timeAndDuration": "الوقت والمدة", + "assetsCondition": "حالة الأصول", + "attachmentsAcknowledge": "إقرار & المرفقات", + "up_and_running": "قيد التشغيل", + "partially_down": "معطل جزئيًا", + "fully_down": "معطل تمامًا", + "verify_asset_details": "تحقق من تفاصيل الأصل", + "equipment_status": "حالة المعدات", + "failureReason": "سبب الفشل", + "visitDateAndTime": "تاريخ ووقت الزيارة", + "markAsFixed": "تحديد كإصلاح", + "iHaveArrived": "لقد وصلت", + "fixedRemotely": "تم الإصلاح عن بُعد", + "needAVisit": "بحاجة إلى زيارة", + "solutions": "الحلول", "welcome" : "مرحبا،", "openWhatsapp" : "الإنتقال الى الواتس اب", "callUs" : "إتصل بنا", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index af57bfe4..03163f06 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -69,6 +69,21 @@ "brand": "manufacture", "clearSearch": "Clear Search", "closed": "Closed", + "close": "Close", + "scanOrPickAsset": "Scan or Pick Asset", + "attachFiles": "Attach Files", + "activityStatus": "Activity Status", + "takeAction": "Take Action", + "pleaseConfirmTheIssueHasBeenResolved": "Please confirm the issue has been resolved", + "nurseAcknowledge": "I acknowledge the completion of this work order", + "hours": "Hours", + "internal": "Internal", + "external": "External", + "addInternalActivity": "Add Internal Activity", + "addExternalActivity": "Add External Activity", + "remotely": "Remotely", + "workshop": "Workshop", + "abroad": "Abroad", "create": "Create", "createServiceRequest": "Create Service Request", "delete": "Delete", @@ -240,13 +255,29 @@ "requiredField" : "Required Field", "passwordLengthMessage" : "Password must has at least 6 characters", "overview" : "Overview", - "myRequests" : "My Requests", - "myAssets" : "My Assets", - "contactUs": "Contact Us", + "request" : "Request", + "assets" : "Assets", + "contact": "Contact", "welcome" : "Welcome,", "openWhatsapp" : "Open WhatsApp", + "timeAndDuration": "Time and Duration", + "assetsCondition": "Asset’s Condition", + "attachmentsAcknowledge": "Attachments & Acknowledge", + "up_and_running": "Up & Running", + "partially_down": "Partially Down", + "needAVisit": "Need a Visit", + "fixedRemotely": "Fixed Remotely", + "iHaveArrived": "I have arrived", + "verify_asset_details": "Verify Asset Details", + "equipment_status": "Equipment Status", + "failureReason": "Failure Reason", + "visitDateAndTime": "Visit Date & Time", + "markAsFixed": "Mark as Fixed", + "fully_down": "Fully Down", + "solutions": "Solutions", "callUs" : "Call Us", "liveChat" : "Live Chat", + "feedBack" : "Feedback", "gasRefillRequest" : "Gas Refill Request", "transferRequest" : "Transfer Request", "serviceRequest" : "Service Request", diff --git a/lib/main.dart b/lib/main.dart index 130278e8..74498bc2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -55,6 +55,7 @@ import 'package:test_sa/providers/work_order/reason_provider.dart'; import 'package:test_sa/providers/work_order/service_type_provider.dart'; import 'package:test_sa/providers/work_order/supplier_engineer_provider.dart'; import 'package:test_sa/providers/work_order/vendor_provider.dart'; +import 'package:test_sa/service_request_latest/request_detail_provider.dart'; import 'package:test_sa/views/pages/device_transfer/asset_filter_screen.dart'; import 'package:test_sa/views/pages/device_transfer/asset_search_screen.dart'; import 'package:test_sa/views/pages/device_transfer/request_device_transfer.dart'; @@ -77,6 +78,7 @@ import 'package:test_sa/views/widgets/equipment/single_device_picker.dart'; import 'controllers/providers/api/gas_refill_comments.dart'; import 'controllers/providers/api/user_provider.dart'; import 'controllers/providers/settings/setting_provider.dart'; +import 'dashboard_latest/dashboard_provider.dart'; import 'new_views/pages/new_gas_refill_request_page.dart'; import 'providers/service_request_providers/loan_availability_provider.dart'; @@ -131,6 +133,9 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => ServiceRequestsProvider()), ChangeNotifierProvider(create: (_) => DepartmentsProvider()), ChangeNotifierProvider(create: (_) => NotificationsProvider()), + //new providers according to new Api's.. + ChangeNotifierProvider(create: (_) => DashBoardProvider()), + ChangeNotifierProvider(create: (_) => RequestDetailProvider()), // ChangeNotifierProvider(create: (_) => PreventiveMaintenanceVisitsProvider()), ChangeNotifierProvider(create: (_) => PpmProvider()), ChangeNotifierProvider(create: (_) => PartsProvider()), diff --git a/lib/models/enums/user_types.dart b/lib/models/enums/user_types.dart index 41df2134..e84e2493 100644 --- a/lib/models/enums/user_types.dart +++ b/lib/models/enums/user_types.dart @@ -1,4 +1,5 @@ enum UsersTypes { engineer, // 0 normal_user, // 1 + nurse, // 1 } diff --git a/lib/models/helper_data_models/spare_part/activity_spare_part_model.dart b/lib/models/helper_data_models/spare_part/activity_spare_part_model.dart new file mode 100644 index 00000000..6293805e --- /dev/null +++ b/lib/models/helper_data_models/spare_part/activity_spare_part_model.dart @@ -0,0 +1,64 @@ +class ActivitySparePartModel { + int id; + int workOrderId; + int partCatalogItemId; + int quantity; + String comment; + List sparePartAttachments; + + ActivitySparePartModel( + {this.id, + this.workOrderId, + this.partCatalogItemId, + this.quantity, + this.comment, + this.sparePartAttachments}); + + ActivitySparePartModel.fromJson(Map json) { + id = json['id']; + workOrderId = json['workOrderId']; + partCatalogItemId = json['partCatalogItemId']; + quantity = json['quantity']; + comment = json['comment']; + if (json['acitiySparePartAttachments'] != null) { + sparePartAttachments = []; + json['acitiySparePartAttachments'].forEach((v) { + sparePartAttachments + .add(SparePartAttachments.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['workOrderId'] = workOrderId; + data['partCatalogItemId'] = partCatalogItemId; + data['quantity'] = quantity; + data['comment'] = comment; + if (sparePartAttachments != null) { + data['acitiySparePartAttachments'] = + sparePartAttachments.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class SparePartAttachments { + int id; + String name; + + SparePartAttachments({this.id, this.name}); + + SparePartAttachments.fromJson(Map json) { + id = json['id']; + name = json['name']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + return data; + } +} diff --git a/lib/models/helper_data_models/workorder/fix_remotely_model.dart b/lib/models/helper_data_models/workorder/fix_remotely_model.dart new file mode 100644 index 00000000..75523cb5 --- /dev/null +++ b/lib/models/helper_data_models/workorder/fix_remotely_model.dart @@ -0,0 +1,35 @@ +class FixRemotely { + int workOrderId; + DateTime startDate; + DateTime endDate; + int workingHour; + String comment; + + FixRemotely({ + this.workOrderId, + this.startDate, + this.endDate, + this.workingHour, + this.comment, + }); + + factory FixRemotely.fromJson(Map json) { + return FixRemotely( + workOrderId: json['workOrderId'], + startDate: DateTime.parse(json['startDate']), + endDate: DateTime.parse(json['endDate']), + workingHour: json['workingHour'], + comment: json['comment'], + ); + } + + Map toJson() { + return { + 'workOrderId': workOrderId, + 'startDate': startDate.toIso8601String(), + 'endDate': endDate.toIso8601String(), + 'workingHour': workingHour, + 'comment': comment, + }; + } +} diff --git a/lib/models/helper_data_models/workorder/mark_as_fixed_model.dart b/lib/models/helper_data_models/workorder/mark_as_fixed_model.dart new file mode 100644 index 00000000..a44cb687 --- /dev/null +++ b/lib/models/helper_data_models/workorder/mark_as_fixed_model.dart @@ -0,0 +1,23 @@ +class MarkAsFixed { + int workOrderId; + String feedback; + + MarkAsFixed({ + this.workOrderId, + this.feedback, + }); + + factory MarkAsFixed.fromJson(Map json) { + return MarkAsFixed( + workOrderId: json['workOrderId'], + feedback: json['feedback'], + ); + } + + Map toJson() { + return { + 'workOrderId': workOrderId, + 'feedback': feedback, + }; + } +} diff --git a/lib/models/helper_data_models/workorder/need_visit_model.dart b/lib/models/helper_data_models/workorder/need_visit_model.dart new file mode 100644 index 00000000..d345af95 --- /dev/null +++ b/lib/models/helper_data_models/workorder/need_visit_model.dart @@ -0,0 +1,27 @@ +class NeedVisit { + int workOrderId; + DateTime visitDate; + String comment; + + NeedVisit({ + this.workOrderId, + this.visitDate, + this.comment, + }); + + factory NeedVisit.fromJson(Map json) { + return NeedVisit( + workOrderId: json['workOrderId'], + visitDate: DateTime.parse(json['visitDate']), + comment: json['comment'], + ); + } + + Map toJson() { + return { + 'workOrderId': workOrderId, + 'visitDate': visitDate.toIso8601String(), + 'comment': comment, + }; + } +} diff --git a/lib/models/helper_data_models/workorder/nurse_action_model.dart b/lib/models/helper_data_models/workorder/nurse_action_model.dart new file mode 100644 index 00000000..86647e7f --- /dev/null +++ b/lib/models/helper_data_models/workorder/nurse_action_model.dart @@ -0,0 +1,27 @@ +class NurseActionModel { + int workOrderId; + String feedback; + String signatureNurse; + + NurseActionModel({ + this.workOrderId, + this.feedback, + this.signatureNurse, + }); + + factory NurseActionModel.fromJson(Map json) { + return NurseActionModel( + workOrderId: json['workOrderId'], + feedback: json['feedback'], + signatureNurse: json['signatureNurse'], + ); + } + + Map toJson() { + return { + 'workOrderId': workOrderId, + 'feedback': feedback, + 'signatureNurse': signatureNurse, + }; + } +} diff --git a/lib/models/lookup.dart b/lib/models/lookup.dart index f176d1f6..8552e081 100644 --- a/lib/models/lookup.dart +++ b/lib/models/lookup.dart @@ -1,26 +1,21 @@ import 'base.dart'; class Lookup extends Base { - int? id; // Now nullable - int? value; // Now nullable - @override - String? name; // Now nullable + final int id, value; - Lookup({this.id, this.value, this.name}) : super(identifier: id?.toString(), name: name); + Lookup({this.id, this.value, String name}) : super(identifier: id?.toString(), name: name); @override bool operator ==(Object other) => identical(this, other) || other is Lookup && ((value != null && value == other.value) || (id != null && id == other.id)); @override - int get hashCode => id.hashCode ^ value.hashCode; // Use XOR for hash code combination + int get hashCode => id?.hashCode ?? value?.hashCode; - Map toJson() { - // Return a Map instead of calling a function + toJson() { return {"id": id, "name": name, "value": value}; } - static Lookup? fromStatus(Lookup? old) { - // Now accepts nullable Lookup and returns nullable Lookup + factory Lookup.fromStatus(Lookup old) { if (old == null) return null; return Lookup( name: old.name, @@ -29,13 +24,9 @@ class Lookup extends Base { ); } - // CreatedBy.fromJson(dynamic json) { - // userId = json['userId'] ?? ''; - // userName = json['userName'] ?? ''; - // } - factory Lookup.fromJson(Map parsedJson) { - // if (parsedJson == null) return null; + + if (parsedJson == null) return null; return Lookup( name: parsedJson["name"], id: parsedJson["id"], diff --git a/lib/models/new_models/dashboardCount.dart b/lib/models/new_models/dashboardCount.dart new file mode 100644 index 00000000..7fddba76 --- /dev/null +++ b/lib/models/new_models/dashboardCount.dart @@ -0,0 +1,75 @@ +class DashboardCount { + Data data; + String message; + String title; + String innerMessage; + int responseCode; + bool isSuccess; + + DashboardCount( + {this.data, + this.message, + this.title, + this.innerMessage, + this.responseCode, + this.isSuccess}); + + DashboardCount.fromJson(Map json) { + data = json['data'] != null ? Data.fromJson(json['data']) : null; + message = json['message']; + title = json['title']; + innerMessage = json['innerMessage']; + responseCode = json['responseCode']; + isSuccess = json['isSuccess']; + } + + Map toJson() { + final Map data = {}; + if (this.data != null) { + data['data'] = this.data.toJson(); + } + data['message'] = message; + data['title'] = title; + data['innerMessage'] = innerMessage; + data['responseCode'] = responseCode; + data['isSuccess'] = isSuccess; + return data; + } +} + +class Data { + int countOpen; + int countInprogress; + int countComplete; + int countAcknowledge; + int countHighPriority; + int countOverdue; + + Data( + {this.countOpen, + this.countInprogress, + this.countComplete, + this.countAcknowledge, + this.countHighPriority, + this.countOverdue}); + + Data.fromJson(Map json) { + countOpen = json['countOpen']??0; + countInprogress = json['countInprogress']??0; + countComplete = json['countComplete']??0; + countAcknowledge = json['countAcknowledge']??0; + countHighPriority = json['countHighPriority']??0; + countOverdue = json['countOverdue']??0; + } + + Map toJson() { + final Map data = {}; + data['countOpen'] = countOpen; + data['countInprogress'] = countInprogress; + data['countComplete'] = countComplete; + data['countAcknowledge'] = countAcknowledge; + data['countHighPriority'] = countHighPriority; + data['countOverdue'] = countOverdue; + return data; + } +} \ No newline at end of file diff --git a/lib/models/new_models/dashboard_detail.dart b/lib/models/new_models/dashboard_detail.dart new file mode 100644 index 00000000..110488b9 --- /dev/null +++ b/lib/models/new_models/dashboard_detail.dart @@ -0,0 +1,140 @@ +class DashboardDetail { + List data; + int totalRows; + String message; + String title; + String innerMessage; + int responseCode; + bool isSuccess; + + DashboardDetail( + {this.data, + this.totalRows, + this.message, + this.title, + this.innerMessage, + this.responseCode, + this.isSuccess}); + + DashboardDetail.fromJson(Map json) { + if (json['data'] != null) { + data = []; + json['data'].forEach((v) { + data.add(Data.fromJson(v)); + }); + } + totalRows = json['totalRows']; + message = json['message']; + title = json['title']; + innerMessage = json['innerMessage']; + responseCode = json['responseCode']; + isSuccess = json['isSuccess']; + } + + Map toJson() { + final Map data = {}; + if (this.data != null) { + data['data'] = this.data.map((v) => v.toJson()).toList(); + } + data['totalRows'] = totalRows; + data['message'] = message; + data['title'] = title; + data['innerMessage'] = innerMessage; + data['responseCode'] = responseCode; + data['isSuccess'] = isSuccess; + return data; + } +} + +class Data { + int id; + String typeTransaction; + String transactionDate; + String statusName; + String priorityName; + bool isHighPriority; + String assetName; + String assetNumber; + String requestTypeName; + String requestNo; + + Data( + {this.id, + this.typeTransaction, + this.transactionDate, + this.statusName, + this.priorityName, + this.isHighPriority, + this.assetName, + this.assetNumber, + this.requestTypeName, + this.requestNo}); + + Data.fromJson(Map json) { + id = json['id']; + typeTransaction = json['typeTransaction']; + transactionDate = json['transactionDate']; + statusName = json['statusName']; + priorityName = json['priorityName']; + isHighPriority = json['isHighPriority']; + assetName = json['assetName']; + assetNumber = json['assetNumber']; + requestTypeName = json['requestTypeName']; + requestNo = json['requestNo']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['typeTransaction'] = typeTransaction; + data['transactionDate'] = transactionDate; + data['statusName'] = statusName; + data['priorityName'] = priorityName; + data['isHighPriority'] = isHighPriority; + data['assetName'] = assetName; + data['assetNumber'] = assetNumber; + data['requestTypeName'] = requestTypeName; + data['requestNo'] = requestNo; + return data; + } +} +class CommonResponseModel{ + bool data; + String message; + String title; + String innerMessage; + int responseCode; + bool isSuccess; + + CommonResponseModel({ + this.data, + this.message, + this.title, + this.innerMessage, + this.responseCode, + this.isSuccess, + }); + + factory CommonResponseModel.fromJson(Map json) { + return CommonResponseModel( + data: json['data'], + message: json['message'] ?? '', + title: json['title'], + innerMessage: json['innerMessage'], + responseCode: json['responseCode'], + isSuccess: json['isSuccess'], + ); + } + + Map toJson() { + return { + 'data': data, + 'message': message, + 'title': title, + 'innerMessage': innerMessage, + 'responseCode': responseCode, + 'isSuccess': isSuccess, + }; + } +} + diff --git a/lib/models/new_models/workOrderDetail.dart b/lib/models/new_models/workOrderDetail.dart new file mode 100644 index 00000000..249570c8 --- /dev/null +++ b/lib/models/new_models/workOrderDetail.dart @@ -0,0 +1,842 @@ +import 'package:test_sa/models/lookup.dart'; + +class WorkOrderDetail { + WorkOrder data; + String message; + String title; + String innerMessage; + int responseCode; + bool isSuccess; + + WorkOrderDetail({ + this.data, + this.message, + this.title, + this.innerMessage, + this.responseCode, + this.isSuccess, + }); + + factory WorkOrderDetail.fromJson(Map json) { + return WorkOrderDetail( + data: WorkOrder.fromJson(json['data']), + message: json['message'], + title: json['title'], + innerMessage: json['innerMessage'], + responseCode: json['responseCode'], + isSuccess: json['isSuccess'], + ); + } + Map toJson() { + return { + 'data': data?.toJson(), + 'message': message, + 'title': title, + 'innerMessage': innerMessage, + 'responseCode': responseCode, + 'isSuccess': isSuccess, + }; + } +} + +class WorkOrder { + String workOrderNo; + WorkOrderCreatedBy workOrderCreatedBy; + DateTime requestedDate; + Asset asset; + Lookup assetGroup; + Lookup manufacturer; + Lookup model; + Lookup assetNDModel; + Site site; + Lookup building; + Lookup floor; + Lookup department; + dynamic room; + Lookup assetType; + AssignedEmployee assignedEmployee; + dynamic lastActivityStatus; + Lookup status; + Lookup nextStep; + dynamic assetVerificationType; + List workOrderContactPerson; + EquipmentStatus equipmentStatus; + Priority priority; + RequestedThrough requestedThrough; + TypeOfRequest typeofRequest; + dynamic loanAvailablity; + dynamic assetLoan; + dynamic safety; + ProblemDescription problemDescription; + String comments; + String voiceNote; + List workOrderAttachments; + dynamic returnToService; + dynamic serviceType; + dynamic failureReasone; + dynamic solution; + dynamic totalWorkingHours; + List workOrderHistory; + List activityMaintenances; + List activitySpareParts; + List activityAssetToBeRetireds; + + WorkOrder({ + this.workOrderNo, + this.workOrderCreatedBy, + this.requestedDate, + this.asset, + this.assetGroup, + this.manufacturer, + this.model, + this.assetNDModel, + this.site, + this.building, + this.floor, + this.department, + this.room, + this.assetType, + this.assignedEmployee, + this.lastActivityStatus, + this.status, + this.nextStep, + this.assetVerificationType, + this.workOrderContactPerson, + this.equipmentStatus, + this.priority, + this.requestedThrough, + this.typeofRequest, + this.loanAvailablity, + this.assetLoan, + this.safety, + this.problemDescription, + this.comments, + this.voiceNote, + this.workOrderAttachments, + this.returnToService, + this.serviceType, + this.failureReasone, + this.solution, + this.totalWorkingHours, + this.workOrderHistory, + this.activityMaintenances, + this.activitySpareParts, + this.activityAssetToBeRetireds, + }); + + factory WorkOrder.fromJson(Map json) { + return WorkOrder( + workOrderNo: json['workOrderNo'], + workOrderCreatedBy: WorkOrderCreatedBy.fromJson(json['workOrderCreatedBy']), + requestedDate: DateTime.parse(json['requestedDate']), + asset: Asset.fromJson(json['asset']), + assetGroup: json['assetGroup']??Lookup.fromJson(json['assetGroup']), + manufacturer:json['manufacturer']?? Lookup.fromJson(json['manufacturer']), + model: json['model']?? Lookup.fromJson(json['model']), + assetNDModel:json['assetNDModel']?? Lookup.fromJson(json['assetNDModel']), + site: Site.fromJson(json['site']), + building: json['building']??Lookup.fromJson(json['building']), + floor: json['floor']??Lookup.fromJson(json['floor']), + department:json['department']?? Lookup.fromJson(json['department']), + room: json['room'], + assetType: json['assetType']??Lookup.fromJson(json['assetType']), + assignedEmployee: AssignedEmployee.fromJson(json['assignedEmployee']), + lastActivityStatus: json['lastActivityStatus'], + status: json['status']??Lookup.fromJson(json['status']), + nextStep: json['nextStep']??Lookup.fromJson(json['nextStep']), + assetVerificationType: json['assetVerificationType'], + workOrderContactPerson: (json['workOrderContactPerson'] as List) + .map((i) => WorkOrderContactPerson.fromJson(i)) + .toList(), + equipmentStatus: EquipmentStatus.fromJson(json['equipmentStatus']), + priority: Priority.fromJson(json['priority']), + requestedThrough: RequestedThrough.fromJson(json['requestedThrough']), + typeofRequest: TypeOfRequest.fromJson(json['typeofRequest']), + loanAvailablity: json['loanAvailablity'], + assetLoan: json['assetLoan'], + safety: json['safety'], + problemDescription: ProblemDescription.fromJson(json['problemDescription']), + comments: json['comments'], + voiceNote: json['voiceNote'], + workOrderAttachments: json['workOrderAttachments'] as List, + returnToService: json['returnToService'], + serviceType: json['serviceType'], + failureReasone: json['failureReasone'], + solution: json['solution'], + totalWorkingHours: json['totalWorkingHours'], + workOrderHistory: (json['workOrderHistory'] as List) + .map((i) => WorkOrderHistory.fromJson(i)) + .toList(), + activityMaintenances: json['activityMaintenances'] as List, + activitySpareParts: json['activitySpareParts'] as List, + activityAssetToBeRetireds: json['activityAssetToBeRetireds'] as List, + ); + } + Map toJson() { + return { + 'workOrderNo': workOrderNo, + 'workOrderCreatedBy': workOrderCreatedBy.toJson(), + 'requestedDate': requestedDate.toIso8601String(), + 'asset': asset.toJson(), + 'assetGroup': assetGroup.toJson(), + 'manufacturer': manufacturer.toJson(), + 'model': model.toJson(), + 'assetNDModel': assetNDModel.toJson(), + 'site': site.toJson(), + 'building': building.toJson(), + 'floor': floor.toJson(), + 'department': department.toJson(), + 'room': room, + 'assetType': assetType.toJson(), + 'assignedEmployee': assignedEmployee.toJson(), + 'lastActivityStatus': lastActivityStatus, + 'status': status.toJson(), + 'nextStep': nextStep.toJson(), + 'assetVerificationType': assetVerificationType, + 'workOrderContactPerson': workOrderContactPerson.map((i) => i.toJson()).toList(), + 'equipmentStatus': equipmentStatus.toJson(), + 'priority': priority.toJson(), + 'requestedThrough': requestedThrough.toJson(), + 'typeofRequest': typeofRequest.toJson(), + 'loanAvailablity': loanAvailablity, + 'assetLoan': assetLoan, + 'safety': safety, + 'problemDescription': problemDescription.toJson(), + 'comments': comments, + 'voiceNote': voiceNote, + 'workOrderAttachments': workOrderAttachments, + 'returnToService': returnToService, + 'serviceType': serviceType, + 'failureReasone': failureReasone, + 'solution': solution, + 'totalWorkingHours': totalWorkingHours, + 'workOrderHistory': workOrderHistory.map((i) => i.toJson()).toList(), + 'activityMaintenances': activityMaintenances, + 'activitySpareParts': activitySpareParts, + 'activityAssetToBeRetireds': activityAssetToBeRetireds, + }; + } + +} + +class WorkOrderCreatedBy { + String id; + String userName; + + WorkOrderCreatedBy({this.id, this.userName}); + + factory WorkOrderCreatedBy.fromJson(Map json) { + return WorkOrderCreatedBy( + id: json['id'], + userName: json['userName'], + ); + } + Map toJson() { + return { + 'id': id, + 'userName': userName, + }; + } +} + +class Asset { + int id; + String assetNumber; + + Asset({this.id, this.assetNumber}); + + factory Asset.fromJson(Map json) { + return Asset( + id: json['id'], + assetNumber: json['assetNumber'], + ); + } + Map toJson() { + return { + 'id': id, + 'assetNumber': assetNumber, + }; + } +} + +class WorkOrderContactPerson { + int id; + String name; + String employeeId; + String position; + String extension; + String email; + String mobilePhone; + ContactUser contactUser; + + WorkOrderContactPerson({ + this.id, + this.name, + this.employeeId, + this.position, + this.extension, + this.email, + this.mobilePhone, + this.contactUser, + }); + + factory WorkOrderContactPerson.fromJson(Map json) { + return WorkOrderContactPerson( + id: json['id'], + name: json['name'], + employeeId: json['employeeId'], + position: json['position'], + extension: json['extension'], + email: json['email'], + mobilePhone: json['mobilePhone'], + contactUser: ContactUser.fromJson(json['contactUser']), + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'employeeId': employeeId, + 'position': position, + 'extension': extension, + 'email': email, + 'mobilePhone': mobilePhone, + 'contactUser': contactUser.toJson(), + }; + } +} + +class ContactUser { + String id; + String userName; + + ContactUser({ + this.id, + this.userName, + }); + + factory ContactUser.fromJson(Map json) { + return ContactUser( + id: json['id'], + userName: json['userName'], + ); + } + + Map toJson() { + return { + 'id': id, + 'userName': userName, + }; + } +} + +class AssignedEmployee { + String id; + String userName; + + AssignedEmployee({this.id, this.userName}); + + factory AssignedEmployee.fromJson(Map json) { + return AssignedEmployee( + id: json['id'], + userName: json['userName'], + ); + } + Map toJson() { + return { + 'id': id, + 'userName': userName, + }; + } +} + +class Site { + int id; + String siteName; + + Site({this.id, this.siteName}); + + factory Site.fromJson(Map json) { + return Site( + id: json['id'], + siteName: json['siteName'], + ); + } + Map toJson() { + return { + 'id': id, + 'siteName': siteName, + }; + } +} + +/// + +// class AssetGroup { +// int id; +// String name; +// +// AssetGroup({this.id, this.name}); +// +// factory AssetGroup.fromJson(Map json) { +// return AssetGroup( +// id: json['id'], +// name: json['name'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// }; +// } +// +// } +// +// class Manufacturer { +// int id; +// String name; +// +// Manufacturer({this.id, this.name}); +// +// factory Manufacturer.fromJson(Map json) { +// return Manufacturer( +// id: json['id'], +// name: json['name'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// }; +// } +// } +// +// class Model { +// int id; +// String name; +// +// Model({this.id, this.name}); +// +// factory Model.fromJson(Map json) { +// return Model( +// id: json['id'], +// name: json['name'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// }; +// } +// } +// +// class AssetNDModel { +// int id; +// String name; +// +// AssetNDModel({this.id, this.name}); +// +// factory AssetNDModel.fromJson(Map json) { +// return AssetNDModel( +// id: json['id'], +// name: json['name'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// }; +// } +// } +// +// class Building { +// int id; +// String name; +// int value; +// +// Building({this.id, this.name, this.value}); +// +// factory Building.fromJson(Map json) { +// return Building( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } +// +// class Floor { +// int id; +// String name; +// int value; +// +// Floor({this.id, this.name, this.value}); +// +// factory Floor.fromJson(Map json) { +// return Floor( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } +// +// class Department { +// int id; +// String name; +// +// Department({this.id, this.name}); +// +// factory Department.fromJson(Map json) { +// return Department( +// id: json['id'], +// name: json['name'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// }; +// } +// } +// +// class AssetType { +// int id; +// String name; +// int value; +// +// AssetType({this.id, this.name, this.value}); +// +// factory AssetType.fromJson(Map json) { +// return AssetType( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } +// +// class Status { +// int id; +// String name; +// int value; +// +// Status({this.id, this.name, this.value}); +// +// factory Status.fromJson(Map json) { +// return Status( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } +// +// class NextStep { +// int id; +// String name; +// int value; +// +// NextStep({this.id, this.name, this.value}); +// +// factory NextStep.fromJson(Map json) { +// return NextStep( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } + + + + +class EquipmentStatus { + int id; + String name; + int value; + + EquipmentStatus({this.id, this.name, this.value}); + + factory EquipmentStatus.fromJson(Map json) { + return EquipmentStatus( + id: json['id'], + name: json['name'], + value: json['value'], + ); + } + Map toJson() { + return { + 'id': id, + 'name': name, + 'value': value, + }; + } +} + +class Priority { + int id; + String name; + int value; + + Priority({this.id, this.name, this.value}); + + factory Priority.fromJson(Map json) { + return Priority( + id: json['id'], + name: json['name'], + value: json['value'], + ); + } + Map toJson() { + return { + 'id': id, + 'name': name, + 'value': value, + }; + } +} + +class RequestedThrough { + int id; + String name; + + RequestedThrough({this.id, this.name}); + + factory RequestedThrough.fromJson(Map json) { + return RequestedThrough( + id: json['id'], + name: json['name'], + ); + } + Map toJson() { + return { + 'id': id, + 'name': name, + }; + } +} + +class TypeOfRequest { + int id; + String name; + + TypeOfRequest({this.id, this.name}); + + factory TypeOfRequest.fromJson(Map json) { + return TypeOfRequest( + id: json['id'], + name: json['name'], + ); + } + Map toJson() { + return { + 'id': id, + 'name': name, + }; + } +} + +class ProblemDescription { + int id; + String name; + + ProblemDescription({this.id, this.name}); + + factory ProblemDescription.fromJson(Map json) { + return ProblemDescription( + id: json['id'], + name: json['name'], + ); + } + Map toJson() { + return { + 'id': id, + 'name': name, + }; + } +} + +class WorkOrderHistory { + int id; + Lookup workOrderStatus; + dynamic activityStatus; // Since activityStatus is null, it's dynamic + String date; + HistoryUser user; + Lookup step; + dynamic fixRemotelyStartTime; // Since it's null, it's dynamic + dynamic fixRemotelyEndTime; // Since it's null, it's dynamic + dynamic fixRemotelyWorkingHours; // Since it's null, it's dynamic + String comments; + dynamic needAVisitDateTime; // Since it's null, it's dynamic + + WorkOrderHistory({ + this.id, + this.workOrderStatus, + this.activityStatus, + this.date, + this.user, + this.step, + this.fixRemotelyStartTime, + this.fixRemotelyEndTime, + this.fixRemotelyWorkingHours, + this.comments, + this.needAVisitDateTime, + }); + + factory WorkOrderHistory.fromJson(Map json) { + return WorkOrderHistory( + id: json['id'], + //json['assetType'] != null ? Lookup.fromJson(json['assetType']) : null; + workOrderStatus:json['workorderStatus']??Lookup.fromJson(json['workorderStatus']), + activityStatus: json['activityStatus'], + date: json['date'], + user: HistoryUser.fromJson(json['user']), + step: json['step']??Lookup.fromJson(json['step']), + fixRemotelyStartTime: json['fixRemotlyStartTime'], + fixRemotelyEndTime: json['fixRemotlyEndTime'], + fixRemotelyWorkingHours: json['fixRemotlyWorkingHours'], + comments: json['comments'] ?? "", + needAVisitDateTime: json['needAVisitDateTime'], + ); + } + + Map toJson() { + return { + 'id': id, + // Lookup.fromJson(json['workorderStatus']) + 'workorderStatus': workOrderStatus.toJson(), + 'activityStatus': activityStatus, + 'date': date, + 'user': user.toJson(), + 'step': step.toJson(), + 'fixRemotelyStartTime': fixRemotelyStartTime, + 'fixRemotelyEndTime': fixRemotelyEndTime, + 'fixRemotelyWorkingHours': fixRemotelyWorkingHours, + 'comments': comments, + 'needAVisitDateTime': needAVisitDateTime, + }; + } +} + +// class WorkOrderStatus { +// int id; +// String name; +// int value; +// +// WorkOrderStatus({ +// this.id, +// this.name, +// this.value, +// }); +// +// factory WorkOrderStatus.fromJson(Map json) { +// return WorkOrderStatus( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } + +class HistoryUser { + String id; + String userName; + + HistoryUser({ + this.id, + this.userName, + }); + + factory HistoryUser.fromJson(Map json) { + return HistoryUser( + id: json['id'], + userName: json['userName'], + ); + } + + Map toJson() { + return { + 'id': id, + 'userName': userName, + }; + } +} + +// class Step { +// int id; +// String name; +// int value; +// +// Step({ +// this.id, +// this.name, +// this.value, +// }); +// +// factory Step.fromJson(Map json) { +// return Step( +// id: json['id'], +// name: json['name'], +// value: json['value'], +// ); +// } +// +// Map toJson() { +// return { +// 'id': id, +// 'name': name, +// 'value': value, +// }; +// } +// } + diff --git a/lib/new_views/app_style/app_color.dart b/lib/new_views/app_style/app_color.dart index e8e17a8e..54f74083 100644 --- a/lib/new_views/app_style/app_color.dart +++ b/lib/new_views/app_style/app_color.dart @@ -12,6 +12,7 @@ class AppColor { static const Color primary60 = Color(0xff3B7097); static const Color primary70 = Color(0xff163A51); static const Color primary80 = Color(0xff161D27); + static const Color primary90 = Color(0xff1E95DE); //texts static const Color neutral10 = Color(0xffBCBCBC); @@ -37,6 +38,8 @@ class AppColor { static const Color white20 = Color(0xffF7F9FB); static const Color white30 = Color(0xffE7EBF2); static const Color white40 = Color(0xffE4EBEE); + static const Color white50 = Color(0xffECECEC); + static const Color white60 = Color(0xffEFEFEF); //black static const Color black10 = Color(0xff3B3D4A); @@ -47,6 +50,7 @@ class AppColor { static const Color red40 = Color(0xffFFDBDC); static const Color red50 = Color(0xffD02127); static const Color red60 = Color(0xff8C050A); + static const Color red70 = Color(0xffF63939); //green static const Color green40 = Color(0xffBAFFE1); diff --git a/lib/new_views/app_style/app_themes.dart b/lib/new_views/app_style/app_themes.dart index 746ea308..587092f6 100644 --- a/lib/new_views/app_style/app_themes.dart +++ b/lib/new_views/app_style/app_themes.dart @@ -19,10 +19,10 @@ class AppThemes { ), bottomNavigationBarTheme: BottomNavigationBarThemeData( type: BottomNavigationBarType.fixed, - unselectedLabelStyle: ThemeData.light().textTheme.bodySmall?.copyWith(fontWeight: FontWeight.w500), - selectedLabelStyle: ThemeData.light().textTheme.bodySmall?.copyWith(fontWeight: FontWeight.w500), - selectedItemColor: AppColor.primary70, - unselectedItemColor: AppColor.neutral20, + unselectedLabelStyle: ThemeData.light().textTheme.bodySmall.copyWith(fontWeight: FontWeight.w500), + selectedLabelStyle: ThemeData.light().textTheme.bodySmall.copyWith(fontWeight: FontWeight.w500), + selectedItemColor: AppColor.primary90, + unselectedItemColor: AppColor.neutral120, backgroundColor: Colors.white, ), appBarTheme: AppBarTheme(elevation: 0, backgroundColor: Colors.white, iconTheme: ThemeData.light().iconTheme.copyWith(color: AppColor.neutral50)), @@ -47,8 +47,8 @@ class AppThemes { ), bottomNavigationBarTheme: BottomNavigationBarThemeData( type: BottomNavigationBarType.fixed, - unselectedLabelStyle: ThemeData.dark().textTheme.bodySmall?.copyWith(fontWeight: FontWeight.w500), - selectedLabelStyle: ThemeData.dark().textTheme.bodySmall?.copyWith(fontWeight: FontWeight.w500), + unselectedLabelStyle: ThemeData.dark().textTheme.bodySmall.copyWith(fontWeight: FontWeight.w500), + selectedLabelStyle: ThemeData.dark().textTheme.bodySmall.copyWith(fontWeight: FontWeight.w500), selectedItemColor: AppColor.primary40, unselectedItemColor: AppColor.neutral10, backgroundColor: AppColor.neutral60, diff --git a/lib/new_views/common_widgets/app_bottom_nav_bar.dart b/lib/new_views/common_widgets/app_bottom_nav_bar.dart index 520eff5b..13da57ae 100644 --- a/lib/new_views/common_widgets/app_bottom_nav_bar.dart +++ b/lib/new_views/common_widgets/app_bottom_nav_bar.dart @@ -12,47 +12,49 @@ class AppBottomNavigationBar extends StatelessWidget { final Function(int index) onPressed; final int selectedIndex; - const AppBottomNavigationBar({Key? key, required this.onPressed, required this.selectedIndex}) : super(key: key); + const AppBottomNavigationBar({Key key, @required this.onPressed, @required this.selectedIndex}) : super(key: key); @override Widget build(BuildContext context) { - bool isEngineer = (Provider.of(context, listen: false).user!.type) == UsersTypes.engineer; - return ClipRRect( - borderRadius: const BorderRadius.only(topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)), - child: Container( - height: 120.toScreenHeight, - decoration: BoxDecoration( - color: AppColor.background(context), - boxShadow: [boxShadowR14], - ), - child: BottomNavigationBar( - items: [ - navBarItem(context, index: 0, iconName: "overview", label: context.translation.overview), - navBarItem(context, index: 1, iconName: "requests", label: context.translation.myRequests), - navBarItem(context, index: 2, iconName: "assets", label: context.translation.myAssets), - if (isEngineer) navBarItem(context, index: 3, iconName: "calender_bottom", label: context.translation.calendar), - navBarItem(context, index: isEngineer ? 4 : 3, iconName: "message", label: context.translation.contactUs), - ], - currentIndex: selectedIndex, - onTap: onPressed, - selectedLabelStyle: AppTextStyles.tinyFont, - unselectedLabelStyle: AppTextStyles.tinyFont, - selectedItemColor: Theme.of(context).bottomNavigationBarTheme.selectedItemColor, - unselectedItemColor: Theme.of(context).bottomNavigationBarTheme.unselectedItemColor, - ), + bool isEngineer = (Provider.of(context, listen: false).user.type) == UsersTypes.engineer; + return Container( + // height: 86.toScreenHeight, + decoration: BoxDecoration( + color: AppColor.background(context), + boxShadow: [boxShadowR14], + ), + child: BottomNavigationBar( + items: [ + navBarItem(context, index: 0, iconName: "overview", label: context.translation.overview), + navBarItem(context, index: 1, iconName: "request_icon", label: context.translation.request), + if (!isEngineer) navBarItem(context, index: 2, iconName: "add_icon", label: context.translation.calendar, showLabel: false), + navBarItem(context, index: !isEngineer ? 3 : 2, iconName: "assets", label: context.translation.assets), + navBarItem(context, index: !isEngineer ? 4 : 3, iconName: "contact", label: context.translation.contact), + ], + currentIndex: selectedIndex, + onTap: onPressed, + selectedLabelStyle: AppTextStyles.tinyFont2, + unselectedLabelStyle: AppTextStyles.tinyFont2, + selectedItemColor: Theme.of(context).bottomNavigationBarTheme.selectedItemColor, + unselectedItemColor: Theme.of(context).bottomNavigationBarTheme.unselectedItemColor, ), ); } - BottomNavigationBarItem navBarItem(BuildContext context, {required int index, required String iconName, required String label}) { + BottomNavigationBarItem navBarItem(BuildContext context, {@required int index, @required String iconName, @required String label, bool showLabel = true}) { return BottomNavigationBarItem( icon: iconName - .toSvgAsset( - width: 24, - color: selectedIndex == index ? Theme.of(context).bottomNavigationBarTheme.selectedItemColor : Theme.of(context).bottomNavigationBarTheme.unselectedItemColor, + ?.toSvgAsset( + width: showLabel ? 28 : 38, + height: showLabel ? 26 : 40, + color: showLabel||(showLabel && selectedIndex != 2) + ? selectedIndex == index + ? Theme.of(context).bottomNavigationBarTheme.selectedItemColor + : Theme.of(context).bottomNavigationBarTheme.unselectedItemColor + : null, ) - .paddingOnly(top: 10, bottom: 10), - label: label, + ?.paddingOnly(top: 21, bottom: showLabel ? 4 : 0), + label: showLabel ? label : '', ); } } diff --git a/lib/new_views/common_widgets/app_dashed_button.dart b/lib/new_views/common_widgets/app_dashed_button.dart index 288e780a..9fc2f841 100644 --- a/lib/new_views/common_widgets/app_dashed_button.dart +++ b/lib/new_views/common_widgets/app_dashed_button.dart @@ -10,23 +10,36 @@ import '../app_style/app_color.dart'; class AppDashedButton extends StatelessWidget { final String title; final VoidCallback onPressed; + double height; + Color buttonColor; + Widget icon; - const AppDashedButton({required this.title, required this.onPressed, Key? key}) : super(key: key); + AppDashedButton({@required this.title, @required this.onPressed, Key key,this.height,this.icon,this.buttonColor}) : super(key: key); @override Widget build(BuildContext context) { return Container( width: double.infinity, + height: height, padding: EdgeInsets.symmetric(horizontal: 2.toScreenWidth), decoration: BoxDecoration(color: AppColor.background(context), borderRadius: BorderRadius.circular(10)), child: DottedBorder( - strokeWidth: 2, + strokeWidth: 1, padding: EdgeInsets.symmetric(vertical: 16.toScreenHeight, horizontal: 16.toScreenWidth), - color: context.isDark ? AppColor.primary40 : AppColor.primary10, + color: context.isDark ? AppColor.primary40 : buttonColor?? AppColor.black20, dashPattern: const [4, 3], radius: const Radius.circular(10), borderType: BorderType.RRect, - child: title.heading6(context).custom(color: context.isDark ? AppColor.primary40 : AppColor.primary10).center, + child:icon!=null? + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + icon, + 7.width, + title.heading6(context).custom(color: context.isDark ? AppColor.primary40 : buttonColor??AppColor.black10).center, + ], + ): + title.heading6(context).custom(color: context.isDark ? AppColor.primary40 : buttonColor?? AppColor.primary10).center, ), ).onPress(onPressed); } diff --git a/lib/new_views/common_widgets/app_filled_button.dart b/lib/new_views/common_widgets/app_filled_button.dart index 77045509..a1f8577f 100644 --- a/lib/new_views/common_widgets/app_filled_button.dart +++ b/lib/new_views/common_widgets/app_filled_button.dart @@ -5,15 +5,27 @@ import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; class AppFilledButton extends StatelessWidget { - final VoidCallback? onPressed; + final VoidCallback onPressed; final String label; final bool maxWidth, loading; - final Color? buttonColor; - final Color? textColor; + final Color buttonColor; + final Color textColor; final bool showBorder; + final bool showIcon; + final Widget icon; - const AppFilledButton({ this.onPressed, required this.label, this.maxWidth = false, this.loading = false, this.showBorder = false, this.buttonColor, this.textColor, Key? key}) - : super(key: key); + const AppFilledButton({ + @required this.onPressed, + @required this.label, + this.maxWidth = false, + this.icon, + this.loading = false, + this.showBorder = false, + this.showIcon = false, + this.buttonColor, + this.textColor, + Key key, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -35,7 +47,18 @@ class AppFilledButton extends StatelessWidget { strokeWidth: 2, ), ) - : label.heading6(context).custom(color: textColor ?? AppColor.background(context)), + : showIcon&&icon!=null? + Center( + child: Row( + mainAxisSize:MainAxisSize.min, + children: [ + icon, + 8.width, + label.heading6(context).custom(color: textColor ?? AppColor.background(context)) + ], + ), + ): + label.heading6(context).custom(color: textColor ?? AppColor.background(context)), ).onPress(onPressed); } } diff --git a/lib/new_views/pages/land_page/calender_fragments/monthly_fragment.dart b/lib/new_views/pages/land_page/calender_fragments/monthly_fragment.dart index 38deeb00..d30c90c1 100644 --- a/lib/new_views/pages/land_page/calender_fragments/monthly_fragment.dart +++ b/lib/new_views/pages/land_page/calender_fragments/monthly_fragment.dart @@ -104,7 +104,7 @@ class _MonthlyFragmentState extends State { children: [ const CircleAvatar(backgroundColor: AppColor.primary40, radius: 8), 8.width, - context.translation.myRequests.heading6(context), + context.translation.request.heading6(context), ], ), 16.height, diff --git a/lib/new_views/pages/land_page/contact_us_bottom_sheet.dart b/lib/new_views/pages/land_page/contact_us_bottom_sheet.dart index e3924e62..b5240379 100644 --- a/lib/new_views/pages/land_page/contact_us_bottom_sheet.dart +++ b/lib/new_views/pages/land_page/contact_us_bottom_sheet.dart @@ -37,7 +37,7 @@ class ContactUsBottomSheet extends StatelessWidget { Align( alignment: AlignmentDirectional.centerStart, child: Text( - context.translation.contactUs, + context.translation.contact, style: AppTextStyles.heading3.copyWith(fontWeight: FontWeight.w600, color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), ), diff --git a/lib/new_views/pages/land_page/dashboard_page.dart b/lib/new_views/pages/land_page/dashboard_page.dart index 7430ef3e..bfa92e7d 100644 --- a/lib/new_views/pages/land_page/dashboard_page.dart +++ b/lib/new_views/pages/land_page/dashboard_page.dart @@ -14,9 +14,9 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/models/user.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/new_views/pages/land_page/dashboard_fragments/progress_fragment.dart'; -import 'package:test_sa/new_views/pages/land_page/dashboard_fragments/recent_activites_fragment.dart'; -import 'package:test_sa/new_views/pages/land_page/dashboard_fragments/requests_fragment.dart'; +import 'package:test_sa/dashboard_latest/widgets/progress_fragment.dart'; +import 'package:test_sa/dashboard_latest/widgets/recent_activites_fragment.dart'; +import 'package:test_sa/dashboard_latest/widgets/requests_fragment.dart'; import 'package:test_sa/views/pages/user/notifications/notifications_page.dart'; class DashboardPage extends StatefulWidget { diff --git a/lib/new_views/pages/land_page/land_page.dart b/lib/new_views/pages/land_page/land_page.dart index 161ac389..2fb2ad43 100644 --- a/lib/new_views/pages/land_page/land_page.dart +++ b/lib/new_views/pages/land_page/land_page.dart @@ -1,3 +1,4 @@ +import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; @@ -23,11 +24,12 @@ import '../../../views/widgets/dialogs/dialog.dart'; import '../../common_widgets/app_bottom_nav_bar.dart'; import '../../common_widgets/app_drawer.dart'; import 'contact_us_bottom_sheet.dart'; +import 'dashboard_page.dart'; class LandPage extends StatefulWidget { static const String routeName = "/land-page"; - const LandPage({Key? key}) : super(key: key); + const LandPage({Key key}) : super(key: key); @override State createState() => _LandPageState(); @@ -37,8 +39,8 @@ class _LandPageState extends State { final GlobalKey _scaffoldKey = GlobalKey(); int currentPageIndex = 0; bool showAppbar = true; - late List _pages; - UserProvider? _userProvider; + List _pages; + UserProvider _userProvider; @override void initState() { @@ -50,7 +52,7 @@ class _LandPageState extends State { if (await Provider.of(context, listen: false).auth.isDeviceSupported()) { SharedPreferences prefs = await SharedPreferences.getInstance(); if (!prefs.containsKey(ASettings.localAuth)) { - (Provider.of(context, listen: false)).setAuth(false); + (await Provider.of(context, listen: false)).setAuth(false); showModalBottomSheet( context: context, useSafeArea: true, @@ -102,12 +104,12 @@ class _LandPageState extends State { _userProvider = Provider.of(context, listen: false); _pages = [ DashboardView(onDrawerPress: (() { - _scaffoldKey.currentState!.isDrawerOpen ? _scaffoldKey.currentState!.closeDrawer() : _scaffoldKey.currentState!.openDrawer(); + _scaffoldKey.currentState.isDrawerOpen ? _scaffoldKey.currentState.closeDrawer() : _scaffoldKey.currentState.openDrawer(); })), // const old_page.LandPage(), const MyRequestsPage(), + if (_userProvider.user.type != UsersTypes.engineer) const CalendarPage(), const MyAssetsPage(fromBottomBar: true), - if (_userProvider!.user!.type == UsersTypes.engineer) const CalendarPage(), ]; checkLocalAuth(); } @@ -133,9 +135,8 @@ class _LandPageState extends State { bottomNavigationBar: AppBottomNavigationBar( selectedIndex: currentPageIndex, onPressed: (index) { - bool isEngineer = _userProvider!.user!.type == UsersTypes.engineer; - - if (index == (isEngineer ? 4 : 3)) { + bool isEngineer = _userProvider.user.type == UsersTypes.engineer; + if (index == (!isEngineer ? 4 : 3)) { showModalBottomSheet( context: context, useSafeArea: true, diff --git a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart index 3a4b2db5..2ef2ea8d 100644 --- a/lib/new_views/pages/land_page/requests/request_paginated_listview.dart +++ b/lib/new_views/pages/land_page/requests/request_paginated_listview.dart @@ -21,6 +21,7 @@ class RequestPaginatedList extends StatelessWidget { itemCount: list.length < totalCount ? list.length + 1 : list.length, controller: scrollController, shrinkWrap: true, + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), itemBuilder: (context, index) { if (index == list.length) { return const ListTile( diff --git a/lib/new_views/pages/land_page/requests_list_page.dart b/lib/new_views/pages/land_page/requests_list_page.dart index 49d5d87b..292eb7dd 100644 --- a/lib/new_views/pages/land_page/requests_list_page.dart +++ b/lib/new_views/pages/land_page/requests_list_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; @@ -7,23 +8,27 @@ import 'package:test_sa/extensions/int_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/enums/user_types.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/dashboard_latest/widgets/request_category_list.dart'; import 'package:test_sa/new_views/pages/land_page/requests/request_paginated_listview.dart'; +import 'package:test_sa/new_views/pages/land_page/widgets/request_item_view_list.dart'; +import 'package:test_sa/views/widgets/loaders/lazy_loading.dart'; class RequestsListPage extends StatefulWidget { static const String routeName = "/requests-list-page"; final int index; final String title; - const RequestsListPage(this.index, this.title, {Key? key}) : super(key: key); + const RequestsListPage(this.index, this.title, {Key key}) : super(key: key); @override State createState() => _RequestsListPageState(); } class _RequestsListPageState extends State { - late AllRequestsProvider _provider; - late ScrollController _scrollController; + AllRequestsProvider _provider; + ScrollController _scrollController; @override void initState() { @@ -46,11 +51,12 @@ class _RequestsListPageState extends State { void handleScroll() async { _scrollController = ScrollController(); - int pageNo = 1; + int pageNo =1; _scrollController.addListener(() async { - if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent && !_provider.isRequestCategoryLoading) { + if (_scrollController?.position?.pixels == _scrollController?.position?.maxScrollExtent && !_provider.isRequestCategoryLoading) { + pageNo = pageNo + 1; - callRequestApis(showLoader: false, pageNo: pageNo); + callRequestApis(showLoader: false,pageNo: pageNo); } }); } @@ -71,28 +77,30 @@ class _RequestsListPageState extends State { }, ); } else { - snapshot.requestDetailList = snapshot.selectedRequestCategory; - return RequestPaginatedList(snapshot.selectedRequestCategory!.requestsDetails ?? [], snapshot.isRequestCategoryLoading, snapshot.selectedRequestCategory!.total!.count!, _scrollController); + WidgetsBinding.instance.addPostFrameCallback((_) { + snapshot.requestDetailList = snapshot.selectedRequestCategory; + }); + return RequestPaginatedList(snapshot.selectedRequestCategory.requestsDetails ?? [], snapshot.isRequestCategoryLoading, snapshot.selectedRequestCategory.total.count, _scrollController); } - // bool isLoading = widget.index == 0 - // ? snapshot.isHighPriorityLoading - // : widget.index == 1 - // ? snapshot.isOverdueLoading - // : widget.index == 2 - // ? snapshot.isOpenLoading - // : widget.index == 3 - // ? snapshot.isCompleteLoading - // : false; - // - // List list = widget.index == 0 - // ? snapshot.highPriorityRequests?.requestsDetails ?? [] - // : widget.index == 1 - // ? snapshot.overdueRequests?.requestsDetails ?? [] - // : widget.index == 2 - // ? snapshot.openRequests?.requestsDetails ?? [] - // : widget.index == 3 - // ? snapshot.completedRequests?.requestsDetails ?? [] - // : []; + bool isLoading = widget.index == 0 + ? snapshot.isHighPriorityLoading + : widget.index == 1 + ? snapshot.isOverdueLoading + : widget.index == 2 + ? snapshot.isOpenLoading + : widget.index == 3 + ? snapshot.isCompleteLoading + : false; + + List list = widget.index == 0 + ? snapshot.highPriorityRequests?.requestsDetails ?? [] + : widget.index == 1 + ? snapshot.overdueRequests?.requestsDetails ?? [] + : widget.index == 2 + ? snapshot.openRequests?.requestsDetails ?? [] + : widget.index == 3 + ? snapshot.completedRequests?.requestsDetails ?? [] + : []; })); } @@ -101,7 +109,7 @@ class _RequestsListPageState extends State { int pageNo = 1, int pageSize = 10, }) async { - UsersTypes usersTypes = Provider.of(context, listen: false).user!.type!; + UsersTypes usersTypes = Provider.of(context, listen: false).user.type; print('i am here at ${widget.index}'); if (widget.index == 0) { diff --git a/lib/providers/work_order/reason_provider.dart b/lib/providers/work_order/reason_provider.dart index 31bf2ba6..e99c91e6 100644 --- a/lib/providers/work_order/reason_provider.dart +++ b/lib/providers/work_order/reason_provider.dart @@ -8,8 +8,8 @@ import '../../controllers/api_routes/urls.dart'; import '../../models/lookup.dart'; class ReasonProvider extends LoadingListNotifier { - String? serviceRequestId; + String serviceRequestId; @override Future getDate() async { if (loading == true) return -2; @@ -18,7 +18,8 @@ class ReasonProvider extends LoadingListNotifier { loading = true; notifyListeners(); try { - Response response = await ApiManager.instance.get(URLs.getServiceReportReasons + "&serviceRequestId=$serviceRequestId"); + print('get reson data called...$serviceRequestId'); + Response response = await ApiManager.instance.get(URLs.getServiceReportReasons+"&serviceRequestId=$serviceRequestId"); stateCode = response.statusCode; if (response.statusCode >= 200 && response.statusCode < 300) { // client's request was successfully received diff --git a/lib/service_request_latest/request_detail_provider.dart b/lib/service_request_latest/request_detail_provider.dart new file mode 100644 index 00000000..efd32140 --- /dev/null +++ b/lib/service_request_latest/request_detail_provider.dart @@ -0,0 +1,424 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:developer'; +import 'package:flutter/material.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/helper_data_models/spare_part/activity_spare_part_model.dart'; +import 'package:test_sa/models/helper_data_models/workorder/fix_remotely_model.dart'; +import 'package:test_sa/models/helper_data_models/workorder/mark_as_fixed_model.dart'; +import 'package:test_sa/models/helper_data_models/workorder/need_visit_model.dart'; +import 'package:test_sa/models/helper_data_models/workorder/nurse_action_model.dart'; +import 'package:test_sa/models/new_models/dashboard_detail.dart'; +import 'package:test_sa/models/new_models/workOrderDetail.dart'; + +class RequestDetailProvider extends ChangeNotifier { + final pageItemNumber = 10; + void reset() { + nextPage = true; + stateCode = null; + } + + DateTime timerStartTime = DateTime(0, 0, 0, 0, 0, 0); // Start from 00:00:00 + Timer timer; + bool isTimerRunning = false; + + void startTimer() { + if (isTimerRunning) return; + timer = Timer.periodic(const Duration(seconds: 1), (Timer t) { + timerStartTime = timerStartTime.add(const Duration(seconds: 1)); + notifyListeners(); // Notify UI when time is updated + }); + isTimerRunning = true; + notifyListeners(); // Notify UI when timer starts + } + + void stopTimer() { + timer?.cancel(); + isTimerRunning = false; + notifyListeners(); // Notify UI when timer stops + } + + void resetTimer() { + timerStartTime = DateTime(0, 0, 0, 0, 0, 0); // Reset to 00:00:00 + notifyListeners(); + } + + // Getter to get the current time + DateTime get currentTime => timerStartTime; + + bool _isLoading = false; + + bool get isLoading => _isLoading; + + set isLoading(bool value) { + _isLoading = value; + notifyListeners(); + } + + WorkOrderDetail _currentWorkOrder; + FixRemotely _fixRemotelyModel; + NeedVisit _needVisitModel; + MarkAsFixed _markAsFixed; + ActivitySparePartModel _activitySparePartModel; + + ActivitySparePartModel get activitySparePartModel => _activitySparePartModel; + + set activitySparePartModel(ActivitySparePartModel value) { + _activitySparePartModel = value; + notifyListeners(); + } + + MarkAsFixed get markAsFixed => _markAsFixed; + + set markAsFixed(MarkAsFixed value) { + _markAsFixed = value; + notifyListeners(); + } + + NurseActionModel _nurseActionModel; + + + NurseActionModel get nurseActionModel => _nurseActionModel; + + set nurseActionModel(NurseActionModel value) { + _nurseActionModel = value; + notifyListeners(); + } + + NeedVisit get needVisitModel => _needVisitModel; + + set needVisitModel(NeedVisit value) { + _needVisitModel = value; + notifyListeners(); + } + + FixRemotely get fixRemotelyModel => _fixRemotelyModel; + + set fixRemotelyModel(FixRemotely value) { + _fixRemotelyModel = value; + notifyListeners(); + } + + WorkOrderDetail get currentWorkOrder => _currentWorkOrder; + + set currentWorkOrder(WorkOrderDetail value) { + _currentWorkOrder = value; + notifyListeners(); + } + + int stateCode; +// true if there is next page in product list and false if not + bool nextPage = true; + TimeOfDay _selectedTime ; + + TimeOfDay get selectedTime => _selectedTime; + + set selectedTime(TimeOfDay value) { + _selectedTime = value; + notifyListeners(); + } // list of user requests + int _selectedListIndex = 0; + + int get selectedListIndex => _selectedListIndex; + + set selectedListIndex(int value) { + _selectedListIndex = value; + notifyListeners(); + } + //getWorkOrderById...... + Future getWorkOrderById({@required String id}) async { + try { + isLoading = true; + final response = await ApiManager.instance.get(URLs.getWorkOrderByIdUrl+"?workOrderId=$id"); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + currentWorkOrder = WorkOrderDetail.fromJson(json.decode(response.body)); + notifyListeners(); + isLoading = false; + return currentWorkOrder; + } + isLoading= false; + notifyListeners(); + return null; + } + catch (e) { + log("getSubWorkOrderDetails [error] : $e"); + isLoading = false; + notifyListeners(); + return null; + } + } + //engineerAcceptWorkOrder...... + Future engineerAcceptWorkOrder({@required String id}) async { + try { + final body = { + "workOrderId": id, + }; + isLoading = true; + final response = await ApiManager.instance.post(URLs.engineerAcceptUrl,body: body); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + CommonResponseModel commonResponseModel = CommonResponseModel.fromJson(json.decode(response.body)); + print('response of Engineer accept workorder ${commonResponseModel.toJson()}'); + notifyListeners(); + isLoading = false; + return commonResponseModel; + } + isLoading= false; + notifyListeners(); + return CommonResponseModel(); + } + catch (e) { + log("engineer accept [error] : $e"); + isLoading = false; + notifyListeners(); + return CommonResponseModel(); + } + } + //engineerRejectWorkOrder...... + Future engineerRejectWorkOrder({@required String id,String feedBack}) async { + try { + final body = { + "workOrderId": id, + "feedback": feedBack, + }; + isLoading = true; + final response = await ApiManager.instance.post(URLs.engineerRejectUrl,body: body); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + CommonResponseModel commonResponseModel = CommonResponseModel.fromJson(json.decode(response.body)); + print('response of Engineer reject workorder ${commonResponseModel.toJson()}'); + notifyListeners(); + isLoading = false; + return commonResponseModel; + } + isLoading= false; + notifyListeners(); + return CommonResponseModel(); + } + catch (e) { + log("engineer accept [error] : $e"); + isLoading = false; + notifyListeners(); + return CommonResponseModel(); + } + } + //engineerFixRemotelyWorkOrder...... + Future engineerFixRemotely() async { + try { + isLoading = true; + final response = await ApiManager.instance.post(URLs.engineerFixRemotlyUrl,body: fixRemotelyModel.toJson()); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + CommonResponseModel commonResponseModel = CommonResponseModel.fromJson(json.decode(response.body)); + print('response of Engineer fixremotely workorder ${commonResponseModel.toJson()}'); + notifyListeners(); + isLoading = false; + return commonResponseModel; + } + isLoading= false; + notifyListeners(); + return CommonResponseModel(); + } + catch (e) { + log("engineer accept [error] : $e"); + isLoading = false; + notifyListeners(); + return CommonResponseModel(); + } + } + //engineerNeedAVisitWorkOrder...... + Future engineerNeedVisit() async { + try { + isLoading = true; + final response = await ApiManager.instance.post(URLs.engineerNeedVisitUrl,body: needVisitModel.toJson()); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + CommonResponseModel commonResponseModel = CommonResponseModel.fromJson(json.decode(response.body)); + print('response of Engineer fixremotely workorder ${commonResponseModel.toJson()}'); + notifyListeners(); + isLoading = false; + return commonResponseModel; + } + isLoading= false; + notifyListeners(); + return CommonResponseModel(); + } + catch (e) { + log("engineer accept [error] : $e"); + isLoading = false; + notifyListeners(); + return CommonResponseModel(); + } + } + //engineerMarkAsFixed...... + Future engineerMarkAsFixed() async { + try { + isLoading = true; + final response = await ApiManager.instance.post(URLs.engineerMarkAsFixUrl,body: markAsFixed.toJson()); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + CommonResponseModel commonResponseModel = CommonResponseModel.fromJson(json.decode(response.body)); + print('response of Engineer mark as fixed ${commonResponseModel.toJson()}'); + notifyListeners(); + isLoading = false; + return commonResponseModel; + } + isLoading= false; + notifyListeners(); + return CommonResponseModel(); + } + catch (e) { + log("engineer accept [error] : $e"); + isLoading = false; + notifyListeners(); + return CommonResponseModel(); + } + } + //assignEngineerToWorkOrder...... + Future assignEngineerWorkOrder({@required String workOrderId,@required String engineerId}) async { + try { + final body = { + "workOrderId": workOrderId, + "assignedEngineerId": engineerId, + }; + isLoading = true; + final response = await ApiManager.instance.post(URLs.assignEngineerToWorkOrderUrl,body: body); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + CommonResponseModel commonResponseModel = CommonResponseModel.fromJson(json.decode(response.body)); + print('response of Engineer assignEngineer workorder ${commonResponseModel.toJson()}'); + notifyListeners(); + isLoading = false; + return commonResponseModel; + } + isLoading= false; + notifyListeners(); + return CommonResponseModel(); + } + catch (e) { + log("engineer accept [error] : $e"); + isLoading = false; + notifyListeners(); + return CommonResponseModel(); + } + } + //Nurse confirm reopen + Future nurseReopen() async { + try { + isLoading = true; + final response = await ApiManager.instance.post(URLs.nurseConfirmReopenUrl,body: nurseActionModel.toJson()); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + CommonResponseModel commonResponseModel = CommonResponseModel.fromJson(json.decode(response.body)); + print('response of nurse confirmreopen workorder ${commonResponseModel.toJson()}'); + notifyListeners(); + isLoading = false; + return commonResponseModel; + } + isLoading= false; + notifyListeners(); + return CommonResponseModel(); + } + catch (e) { + log("engineer accept [error] : $e"); + isLoading = false; + notifyListeners(); + return CommonResponseModel(); + } + } + //Nurse confirm close + Future nurseClose() async { + try { + isLoading = true; + final response = await ApiManager.instance.post(URLs.nurseConfirmCloseUrl,body: nurseActionModel.toJson()); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + CommonResponseModel commonResponseModel = CommonResponseModel.fromJson(json.decode(response.body)); + print('response of nurse confirmreopen workorder ${commonResponseModel.toJson()}'); + notifyListeners(); + isLoading = false; + return commonResponseModel; + } + isLoading= false; + notifyListeners(); + return CommonResponseModel(); + } + catch (e) { + log("engineer accept [error] : $e"); + isLoading = false; + notifyListeners(); + return CommonResponseModel(); + } + } + + + Future updateActivitySparePart({@required ActivitySparePartModel activitySparePartModel}) async { + isLoading = true; + try { + final response = await ApiManager.instance.put( + URLs.updateActivitySparePartUrl, + body: activitySparePartModel.toJson(), + ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + // request.engineerName = employee.name; + notifyListeners(); + } + isLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isLoading = false; + notifyListeners(); + return -1; + } + } + Future deleteActivitySparePart({@required int id,@required int workOrderId}) async { + isLoading = true; + var body = { + 'id':id, + 'workOrderId':workOrderId, + }; + try { + final response = await ApiManager.instance.post( + URLs.deleteActivitySparePartUrl, + body: body, + ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + //map to the model... + notifyListeners(); + } + isLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isLoading = false; + notifyListeners(); + return -1; + } + } + Future createActivitySparePart({@required ActivitySparePartModel activitySparePartModel}) async { + isLoading = true; + try { + final response = await ApiManager.instance.put( + URLs.createActivitySparePartUrl, + body: activitySparePartModel.toJson(), + ); + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + // request.engineerName = employee.name; + notifyListeners(); + } + isLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + isLoading = false; + notifyListeners(); + return -1; + } + } +} diff --git a/lib/service_request_latest/views/components/action_button/footer_action_button.dart b/lib/service_request_latest/views/components/action_button/footer_action_button.dart new file mode 100644 index 00000000..09b6b349 --- /dev/null +++ b/lib/service_request_latest/views/components/action_button/footer_action_button.dart @@ -0,0 +1,165 @@ +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/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart'; + +class FooterActionButton { + + static Widget footerContainer({@required Widget child}){ + return Align( + alignment: Alignment.bottomCenter, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth,vertical: 16.toScreenHeight), + color: AppColor.white10, + child: child, + ), + ); + } + + static Widget footerWidget({@required int status,@required BuildContext context}){ + switch(status){ + //accept reject... + case 1: + return footerContainer( + child: + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + AppFilledButton( + label: context.translation.reject, + maxWidth: true, + buttonColor: Colors.white54, + textColor: AppColor.red30, + showBorder: true, + onPressed: () async { + ServiceRequestBottomSheet.rejectRequestBottomSheet(context: context); + }, + ).expanded, + const SizedBox( + width: 20, + ), + AppFilledButton( + label: context.translation.accept, + maxWidth: true, + buttonColor: AppColor.green70, + onPressed: () async { + }, + ).expanded, + ], + ) + ); + break; + //need visit fixed remotely + case 2: + return footerContainer( + child: + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + AppFilledButton( + label: context.translation.needAVisit, + maxWidth: true, + buttonColor: AppColor.neutral50, + onPressed: () async { + ServiceRequestBottomSheet.initialVisitBottomSheet(context: context); + }, + ).expanded, + const SizedBox( + width: 20, + ), + AppFilledButton( + label: context.translation.fixedRemotely, + maxWidth: true, + buttonColor: AppColor.green70, + onPressed: () async { + ServiceRequestBottomSheet.fixRemotelyBottomSheet(context: context); + }, + ).expanded, + ], + ) + ); + break; + //verify Asset Details + case 3: + return footerContainer( + child: + AppFilledButton( + label: context.translation.verify_asset_details, + // maxWidth: true, + buttonColor: AppColor.primary10, + onPressed: () async { + + }, + ) + ); + break; + //Activities + case 4: + return footerContainer( + child: + AppFilledButton( + label: context.translation.activities, + // maxWidth: true, + buttonColor: AppColor.neutral50, + onPressed: () async { + ServiceRequestBottomSheet.activityTypeBottomSheet(context: context); + }, + ) + ); + break; + //I have arrived... + case 5: + return footerContainer( + child: + AppFilledButton( + label: context.translation.iHaveArrived, + showIcon: true, + icon: 'arrived_icon'.toSvgAsset(), + buttonColor: AppColor.green70, + onPressed: () async { + + }, + ) + ); + break; + //Close.. + case 6: + return footerContainer( + child: + AppFilledButton( + label: context.translation.close, + // maxWidth: true, + buttonColor: AppColor.primary10, + onPressed: () async { + + }, + ) + ); + break; + //for nurse to take action... + case 7: + return footerContainer( + child: + AppFilledButton( + label: context.translation.takeAction, + // maxWidth: true, + buttonColor: AppColor.primary10, + onPressed: () async { + + }, + ) + ); + break; + + default: + return const SizedBox(); + } + + } +} diff --git a/lib/service_request_latest/views/components/bottom_sheets/action_bottomsheet.dart b/lib/service_request_latest/views/components/bottom_sheets/action_bottomsheet.dart deleted file mode 100644 index 4996ba70..00000000 --- a/lib/service_request_latest/views/components/bottom_sheets/action_bottomsheet.dart +++ /dev/null @@ -1,84 +0,0 @@ -// 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 '../../../../controllers/providers/api/service_requests_provider.dart'; -// import '../../../../new_views/app_style/app_color.dart'; -// import '../../../../new_views/common_widgets/app_filled_button.dart'; -// -// class ActionBottomSheet extends StatelessWidget { -// final String title; -// final String button1Text; -// final String button2Text; -// final VoidCallback button1Tap; -// final VoidCallback button2Tap; -// -// ActionBottomSheet({Key? key, required this.title, this.button1Text, this.button2Text, this.button1Tap, this.button2Tap}) : super(key: key); -// -// final GlobalKey _formKey = GlobalKey(); -// -// @override -// Widget build(BuildContext context) { -// return Consumer(builder: (context, serviceRequestProvider, child) { -// return Wrap( -// children: [ -// Container( -// clipBehavior: Clip.antiAlias, -// margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), -// decoration: BoxDecoration( -// color: Theme.of(context).scaffoldBackgroundColor, -// borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), -// ), -// padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), -// child: Column( -// mainAxisSize: MainAxisSize.min, -// children: [ -// Container( -// width: 40.toScreenWidth, -// height: 5.toScreenHeight, -// decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), -// ), -// Align( -// alignment: AlignmentDirectional.centerStart, -// child: title.heading4(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), -// ), -// Row( -// mainAxisAlignment: MainAxisAlignment.spaceBetween, -// children: [ -// SizedBox( -// width: 200.toScreenHeight, -// child: AppFilledButton( -// label: button1Text ?? context.translation.no, -// loading: false, -// buttonColor: AppColor.neutral40, -// textColor: AppColor.black10, -// onPressed: button1Tap ?? -// () async { -// Navigator.pop(context); -// // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); -// // Navigator.pop(context, true); -// }, -// ), -// ), -// SizedBox( -// width: 200.toScreenHeight, -// child: AppFilledButton( -// label: context.translation.yes, -// buttonColor: AppColor.primary10, -// loading: false, -// onPressed: button2Tap, -// ), -// ), -// ], -// ) -// ], -// ), -// ) -// ], -// ); -// }); -// } -// } diff --git a/lib/service_request_latest/views/components/bottom_sheets/activity_type_bottomsheet.dart b/lib/service_request_latest/views/components/bottom_sheets/activity_type_bottomsheet.dart deleted file mode 100644 index 2c72134c..00000000 --- a/lib/service_request_latest/views/components/bottom_sheets/activity_type_bottomsheet.dart +++ /dev/null @@ -1,120 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:provider/provider.dart'; -import 'package:test_sa/app_strings/app_asset.dart'; -import 'package:test_sa/controllers/providers/api/service_requests_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/service_request/service_request.dart'; -import 'package:test_sa/new_views/app_style/app_color.dart'; -import 'package:test_sa/service_request_latest/views/components/spare_part_request.dart'; - -class ActivityTypeBottomSheet extends StatelessWidget { - const ActivityTypeBottomSheet({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final List> items = [ - {'heading': context.translation.sparePartRequest, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.sparePartIcon}, - {'heading': context.translation.maintenanceRequest, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.maintenanceIcon}, - {'heading': context.translation.assetToBeRetired, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.retiredAssetIcon}, - ]; - return Wrap( - children: [ - Consumer(builder: (context, serviceRequestsProvider, child) { - return Container( - clipBehavior: Clip.antiAlias, - margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), - decoration: BoxDecoration( - color: AppColor.background(context), - borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), - ), - padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), - child: SafeArea( - child: Column( - children: [ - Align( - alignment: AlignmentDirectional.centerStart, - child: context.translation.selectActivityType.heading4(context).paddingOnly(top: 16, bottom: 16), - ), - ListView.builder( - shrinkWrap: true, - padding: EdgeInsets.zero, - itemCount: items.length, - itemBuilder: (context, index) { - final item = items[index]; - return listItem( - icon: item['icon']!, - heading: item['heading']!, - subHeading: item['subHeading']!, - context: context, - onTap: () { - onItemTap(serviceRequest: serviceRequestsProvider.currentSelectedRequest!, index: index, context: context); - }); - }, - ), - ], - ), - ), - ); - }), - ], - ); - } - - Widget listItem({required BuildContext context, required String icon, required String heading, required String subHeading, required VoidCallback onTap}) { - return Padding( - padding: EdgeInsets.only(bottom: 8.toScreenHeight), - child: Card( - color: AppColor.neutral80, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15), - // Circular border radius - ), - // color: Colors.white, - child: ListTile( - minVerticalPadding: 8, - horizontalTitleGap: 10, - onTap: onTap, - contentPadding: const EdgeInsets.all(8), - leading: SvgPicture.asset(icon), - title: Text( - heading, - style: AppTextStyles.heading5, - ), - subtitle: Text( - subHeading, - style: AppTextStyles.bodyText, - ), - ), - ), - ); - } - - void onItemTap({required int index, required ServiceRequest serviceRequest, required BuildContext context}) { - print('on item tap i got index is $index'); - switch (index) { - case 0: - Navigator.of(context).push(MaterialPageRoute(builder: (_) => const SparePartRequest())); - - break; - case 1: - //push to specific screen... - // Navigator.push( - // context, - // MaterialPageRoute(builder: (context) => ActivitiesListView()), - // ); - break; - case 2: - //push to specific screen... - // Navigator.push( - // context, - // MaterialPageRoute(builder: (context) => const ScanQrView()), - // ); - break; - } - // ScanQr - } -} diff --git a/lib/service_request_latest/views/components/bottom_sheets/initial_visit_bottomsheet.dart b/lib/service_request_latest/views/components/bottom_sheets/initial_visit_bottomsheet.dart deleted file mode 100644 index fffe34e0..00000000 --- a/lib/service_request_latest/views/components/bottom_sheets/initial_visit_bottomsheet.dart +++ /dev/null @@ -1,204 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:test_sa/controllers/providers/api/user_provider.dart'; -import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; -import 'package:test_sa/extensions/context_extension.dart'; -import 'package:test_sa/extensions/int_extensions.dart'; -import 'package:test_sa/extensions/string_extensions.dart'; -import 'package:test_sa/extensions/text_extensions.dart'; -import 'package:test_sa/extensions/widget_extensions.dart'; -import 'package:test_sa/service_request_latest/views/components/verify_arrival_view.dart'; -import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; -import '../../../../controllers/providers/api/service_requests_provider.dart'; -import '../../../../new_views/app_style/app_color.dart'; -import '../../../../new_views/common_widgets/app_filled_button.dart'; -import '../../../../new_views/common_widgets/app_text_form_field.dart'; - -class InitialVisitBottomSheet extends StatelessWidget { - - InitialVisitBottomSheet({Key? key,}) : super(key: key); - - final GlobalKey _formKey = GlobalKey(); - - @override - Widget build(BuildContext context) { - final userProvider = Provider.of(context, listen: false); - return Consumer( - builder: (context, serviceRequestProvider,child) { - return Wrap( - children: [ - Container( - clipBehavior: Clip.antiAlias, - margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), - ), - padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), - child: Form( - key: _formKey, - child: SingleChildScrollView( - child: Column( - children: [ - Container( - width: 40.toScreenWidth, - height: 5.toScreenHeight, - decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), - ), - Align( - alignment: AlignmentDirectional.centerStart, - child: context.translation.setVisitDate.heading5(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), - ), - - 8.height, - ADatePicker( - label: context.translation.visitDate, - date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest?.visitDate ?? ""), - formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ).then((selectedTime) { - // Handle the selected date and time here. - if (selectedTime != null) { - DateTime selectedDateTime = DateTime( - selectedDate.year, - selectedDate.month, - selectedDate.day, - selectedTime.hour, - selectedTime.minute, - ); - if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.currentSelectedRequest!.date!))) { - "Visit Date time must be greater then request date".showToast; - return; - } - serviceRequestProvider.currentSelectedRequest?.visitDate = selectedDateTime.toIso8601String(); - } - }); - }, - ), - // ], - - if (serviceRequestProvider.currentSelectedRequest?.firstAction?.id == 404 && Provider.of(context, listen: false).assetGroup!.id == 1) ...[ - 8.height, - Row( - children: [ - ADatePicker( - label: context.translation.startDate, - date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest?.startDate ?? ""), - formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ).then((selectedTime) { - // Handle the selected date and time here. - if (selectedTime != null) { - DateTime selectedDateTime = DateTime( - selectedDate.year, - selectedDate.month, - selectedDate.day, - selectedTime.hour, - selectedTime.minute, - ); - serviceRequestProvider.currentSelectedRequest?.startDate = selectedDateTime.toIso8601String(); - - } - }); - }, - ).expanded, - 8.width, - ADatePicker( - label: context.translation.endDate, - date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest?.endDate ?? ""), - formatDateWithTime: true, - onDatePicker: (selectedDate) { - showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ).then((selectedTime) { - // Handle the selected date and time here. - if (selectedTime != null) { - DateTime selectedDateTime = DateTime( - selectedDate.year, - selectedDate.month, - selectedDate.day, - selectedTime.hour, - selectedTime.minute, - ); - serviceRequestProvider.currentSelectedRequest?.endDate = selectedDateTime.toIso8601String(); - serviceRequestProvider.currentSelectedRequest?.workingHours = - (((DateTime.parse(serviceRequestProvider.currentSelectedRequest!.endDate!).difference(DateTime.parse(serviceRequestProvider.currentSelectedRequest!.startDate!)).inSeconds ?? 0) / 60) / 60).toStringAsFixed(2); - } - }); - }, - ).expanded, - ], - ) - ], - - /// Loan availability not required - // 8.height, - // SingleItemDropDownMenu( - // context: context, - // title: context.translation.loanAvailability, - // initialValue: _serviceRequest.loanAvailability, - // onSelect: (status) { - // setState(() { - // _serviceRequest.loanAvailability = status; - // if (_serviceRequest.loanAvailability.value != 1) { - // asset = null; - // } - // }); - // }, - // ), - // if (_serviceRequest?.loanAvailability?.value == 1) 8.height, - // if (_serviceRequest?.loanAvailability?.value == 1) - // PickAsset( - // device: asset ?? _serviceRequest.device, - // onPickAsset: (asset) { - // setState(() { - // this.asset = asset; - // }); - // }, - // ), - 8.height, - AppTextFormField( - labelText: context.translation.comments, - textInputType: TextInputType.multiline, - alignLabelWithHint: true, - onChange: (text) { - serviceRequestProvider.currentSelectedRequest?.comments = text; - }, - onSaved: (text) { - serviceRequestProvider.currentSelectedRequest?.comments = text; - }, - ), - 16.height, - Consumer( - builder: (context, snapshot, _) => AppFilledButton( - label: context.translation.save, - loading: snapshot.isLoading ?? false, - onPressed: () async { - _formKey.currentState!.save(); - - // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); - // Navigator.pop(context, true); - Navigator.of(context).push(MaterialPageRoute( - builder: (_) => const VerifyArrivalView())); - }, - ), - ), - 16.height, - ], - ), - ), - ), - ) - ], - ); - } - ); - } -} diff --git a/lib/service_request_latest/views/components/bottom_sheets/reject_request_bottomsheet.dart b/lib/service_request_latest/views/components/bottom_sheets/reject_request_bottomsheet.dart deleted file mode 100644 index 1a07e1f5..00000000 --- a/lib/service_request_latest/views/components/bottom_sheets/reject_request_bottomsheet.dart +++ /dev/null @@ -1,235 +0,0 @@ -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/device/asset.dart'; - -import '../../../../controllers/providers/api/service_requests_provider.dart'; -import '../../../../models/lookup.dart'; -import '../../../../new_views/app_style/app_color.dart'; -import '../../../../new_views/common_widgets/app_filled_button.dart'; -import '../../../../new_views/common_widgets/app_text_form_field.dart'; -import '../../../../new_views/common_widgets/single_item_drop_down_menu.dart'; -import '../../../../providers/service_request_providers/first_action_provider.dart'; - -class RejectRequestBottomSheet extends StatelessWidget { - RejectRequestBottomSheet({ - Key? key, - }) : super(key: key); - - final GlobalKey _formKey = GlobalKey(); - Asset? asset; - - @override - Widget build(BuildContext context) { - final userProvider = Provider.of(context, listen: false); - return Consumer(builder: (context, requestDetailProvider, child) { - return Wrap( - children: [ - Container( - clipBehavior: Clip.antiAlias, - margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), - ), - padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), - child: Form( - key: _formKey, - child: SingleChildScrollView( - child: Column( - children: [ - Container( - width: 40.toScreenWidth, - height: 5.toScreenHeight, - decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), - ), - Align( - alignment: AlignmentDirectional.centerStart, - child: context.translation.rejectionReason.heading3(context).custom(fontWeight: FontWeight.w600).paddingOnly(top: 16, bottom: 16), - ), - SingleItemDropDownMenu( - context: context, - title: context.translation.rejectionReason, - initialValue: requestDetailProvider.currentSelectedRequest?.firstAction, //_currentSelectedRequest.firstAction, - onSelect: (value) { - // setState(() { - //_currentSelectedRequest.firstAction = value; - requestDetailProvider.currentSelectedRequest?.firstAction = value; - if (requestDetailProvider.currentSelectedRequest?.firstAction!.value != 2) { - requestDetailProvider.currentSelectedRequest?.visitDate = null; - } - // }); - }, - ), - // if (requestDetailProvider.currentSelectedRequest.firstAction?.value == 2) ...[ - // 8.height, - // ADatePicker( - // label: context.translation.visitDate, - // date: DateTime.tryParse(requestDetailProvider.currentSelectedRequest.visitDate ?? ""), - // formatDateWithTime: true, - // onDatePicker: (selectedDate) { - // if (selectedDate != null) { - // showTimePicker( - // context: context, - // initialTime: TimeOfDay.now(), - // ).then((selectedTime) { - // // Handle the selected date and time here. - // if (selectedTime != null) { - // DateTime selectedDateTime = DateTime( - // selectedDate.year, - // selectedDate.month, - // selectedDate.day, - // selectedTime.hour, - // selectedTime.minute, - // ); - // if (selectedDateTime != null) { - // if (selectedDateTime.isBefore(DateTime.parse(requestDetailProvider.currentSelectedRequest.date))) { - // "Visit Date time must be greater then request date".showToast; - // return; - // } - // - // // setState(() { - // requestDetailProvider.currentSelectedRequest.visitDate = selectedDateTime?.toIso8601String(); - // // }); - // } - // } - // }); - // } - // }, - // ), - // ], - // - // if (requestDetailProvider.currentSelectedRequest.firstAction?.id == 404 && Provider.of(context, listen: false).assetGroup.id == 1) ...[ - // 8.height, - // Row( - // children: [ - // ADatePicker( - // label: context.translation.startDate, - // date: DateTime.tryParse(requestDetailProvider.currentSelectedRequest.startDate ?? ""), - // formatDateWithTime: true, - // onDatePicker: (selectedDate) { - // if (selectedDate != null) { - // showTimePicker( - // context: context, - // initialTime: TimeOfDay.now(), - // ).then((selectedTime) { - // // Handle the selected date and time here. - // if (selectedTime != null) { - // DateTime selectedDateTime = DateTime( - // selectedDate.year, - // selectedDate.month, - // selectedDate.day, - // selectedTime.hour, - // selectedTime.minute, - // ); - // if (selectedDateTime != null) { - // requestDetailProvider.currentSelectedRequest.startDate = selectedDateTime?.toIso8601String(); - // } - // } - // }); - // } - // }, - // ).expanded, - // 8.width, - // ADatePicker( - // label: context.translation.endDate, - // date: DateTime.tryParse(requestDetailProvider.currentSelectedRequest.endDate ?? ""), - // formatDateWithTime: true, - // onDatePicker: (selectedDate) { - // if (selectedDate != null) { - // showTimePicker( - // context: context, - // initialTime: TimeOfDay.now(), - // ).then((selectedTime) { - // // Handle the selected date and time here. - // if (selectedTime != null) { - // DateTime selectedDateTime = DateTime( - // selectedDate.year, - // selectedDate.month, - // selectedDate.day, - // selectedTime.hour, - // selectedTime.minute, - // ); - // if (selectedDateTime != null) { - // requestDetailProvider.currentSelectedRequest.endDate = selectedDateTime?.toIso8601String(); - // requestDetailProvider.currentSelectedRequest.workingHours = - // (((DateTime.parse(requestDetailProvider.currentSelectedRequest.endDate).difference(DateTime.parse(requestDetailProvider.currentSelectedRequest.startDate)).inSeconds ?? 0) / 60) / 60).toStringAsFixed(2); - // } - // } - // }); - // } - // }, - // ).expanded, - // ], - // ) - // ], - - /// Loan availability not required - // 8.height, - // SingleItemDropDownMenu( - // context: context, - // title: context.translation.loanAvailability, - // initialValue: _currentSelectedRequest.loanAvailability, - // onSelect: (status) { - // setState(() { - // _currentSelectedRequest.loanAvailability = status; - // if (_currentSelectedRequest.loanAvailability.value != 1) { - // asset = null; - // } - // }); - // }, - // ), - // if (_currentSelectedRequest?.loanAvailability?.value == 1) 8.height, - // if (_currentSelectedRequest?.loanAvailability?.value == 1) - // PickAsset( - // device: asset ?? _currentSelectedRequest.device, - // onPickAsset: (asset) { - // setState(() { - // this.asset = asset; - // }); - // }, - // ), - 8.height, - AppTextFormField( - labelText: context.translation.comments, - textInputType: TextInputType.multiline, - alignLabelWithHint: true, - onChange: (text) { - requestDetailProvider.currentSelectedRequest?.comments = text; - }, - onSaved: (text) { - requestDetailProvider.currentSelectedRequest?.comments = text; - }, - ), - 16.height, - Consumer( - builder: (context, snapshot, _) => AppFilledButton( - label: context.translation.reject, - maxWidth: true, - buttonColor: Colors.white54, - textColor: AppColor.red50, - showBorder: true, - loading: snapshot.isLoading ?? false, - onPressed: () async { - _formKey.currentState!.save(); - // requestDetailProvider.serviceRequest.device = asset; - await snapshot.updateRequest(user: userProvider.user!, request: requestDetailProvider.currentSelectedRequest!); - Navigator.pop(context, true); - }, - ), - ), - 16.height, - ], - ), - ), - ), - ) - ], - ); - }); - } -} diff --git a/lib/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart b/lib/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart index 6ec6c94f..3954fcf1 100644 --- a/lib/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart +++ b/lib/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/app_strings/app_asset.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'; @@ -14,221 +14,19 @@ import 'package:test_sa/models/service_request/service_request.dart'; import 'package:test_sa/models/timer_model.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; import 'package:test_sa/providers/service_request_providers/first_action_provider.dart'; -import 'package:test_sa/service_request_latest/views/components/spare_part_request.dart'; +import 'package:test_sa/service_request_latest/views/forms/spare_part/spare_part_request.dart'; import 'package:test_sa/service_request_latest/views/components/verify_arrival_view.dart'; import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/e_signature/e_signature.dart'; import 'package:test_sa/views/widgets/timer/app_timer.dart'; - import '../../../../controllers/providers/api/service_requests_provider.dart'; import '../../../../new_views/app_style/app_color.dart'; import '../../../../new_views/common_widgets/app_filled_button.dart'; import '../../../../new_views/common_widgets/app_text_form_field.dart'; -// class FixRemotlyBottomSheet extends StatelessWidget { -// -// FixRemotlyBottomSheet({Key? key,}) : super(key: key); -// -// final GlobalKey _formKey = GlobalKey(); -// -// @override -// Widget build(BuildContext context) { -// return Consumer( -// builder: (context, serviceRequestProvider,child) { -// return StatefulBuilder( -// builder: (BuildContext context, StateSetter setState) { -// return Container( -// clipBehavior: Clip.antiAlias, -// margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), -// decoration: BoxDecoration( -// color: AppColor.background(context), -// borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), -// ), -// padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), -// child: Form( -// key: _formKey, -// child: SingleChildScrollView( -// child: Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Center( -// child: Container( -// width: 40.toScreenWidth, -// height: 5.toScreenHeight, -// decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), -// ), -// ), -// Align( -// alignment: AlignmentDirectional.centerStart, -// child: context.translation.fillDetails.heading5(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), -// ), -// -// 8.height, -// ADatePicker( -// label: context.translation.date, -// height: 80.toScreenHeight, -// backgroundColor: AppColor.neutral90, -// date: DateTime.tryParse(serviceRequestProvider.serviceRequest.startDate ?? ""), -// formatDateWithTime: true, -// onDatePicker: (selectedDate) { -// if (selectedDate != null) { -// showTimePicker( -// context: context, -// initialTime: TimeOfDay.now(), -// ).then((selectedTime) { -// // Handle the selected date and time here. -// if (selectedTime != null) { -// DateTime selectedDateTime = DateTime( -// selectedDate.year, -// selectedDate.month, -// selectedDate.day, -// selectedTime.hour, -// selectedTime.minute, -// ); -// if (selectedDateTime != null) { -// if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.serviceRequest.date))) { -// "Visit Date time must be greater then request date".showToast; -// return; -// } -// -// setState(() { -// serviceRequestProvider.serviceRequest.startDate = selectedDateTime?.toIso8601String(); -// }); -// } -// } -// }); -// } -// }, -// ), -// 8.height, -// ATimePicker( -// label: context.translation.startTime, -// height: 80.toScreenHeight, -// backgroundColor: AppColor.neutral90, -// hint:context.translation.pickTime, -// time: serviceRequestProvider.selectedTime, -// onTimePicker: (selectedTime) { -// //TODO handle selected time here. -// if (selectedTime != null) { -// setState(() { -// serviceRequestProvider.selectedTime = selectedTime; -// }); -// // DateTime selectedDateTime = DateTime( -// // selectedDate.year, -// // selectedDate.month, -// // selectedDate.day, -// // selectedTime.hour, -// // selectedTime.minute, -// // ); -// // if (selectedDateTime != null) { -// // if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.serviceRequest.date))) { -// // "Visit Date time must be greater then request date".showToast; -// // return; -// // } -// // -// -// // } -// } -// }, -// ), -// 8.height, -// ATimePicker( -// label: context.translation.endTime, -// height: 80.toScreenHeight, -// backgroundColor: AppColor.neutral90, -// hint:context.translation.pickTime, -// time: serviceRequestProvider.selectedTime, -// onTimePicker: (selectedTime) { -// //TODO handle selected time here. -// if (selectedTime != null) { -// setState(() { -// serviceRequestProvider.selectedTime = selectedTime; -// }); -// } -// }, -// ), -// 8.height, -// Container( -// width: double.infinity, -// height: 80.toScreenHeight, -// decoration: BoxDecoration( -// borderRadius: BorderRadius.circular(10), -// color:AppColor.neutral90, -// boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], -// ), -// padding: EdgeInsets.symmetric(horizontal: 20.toScreenWidth,vertical: 10.toScreenHeight), -// child: Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// mainAxisAlignment: MainAxisAlignment.start, -// children: [ -// context.translation.workingHours.bodyText2(context), -// //TODo calculate the hours and write here. -// 'No of hours'.bodyText(context).custom(color:AppColor.balck10), -// ], -// ), -// -// ), -// 8.height, -// AppTextFormField( -// labelText: context.translation.comments, -// textInputType: TextInputType.multiline, -// alignLabelWithHint: true, -// backgroundColor: AppColor.neutral90, -// onChange: (text) { -// serviceRequestProvider.serviceRequest.comments = text; -// }, -// onSaved: (text) { -// serviceRequestProvider.serviceRequest.comments = text; -// }, -// ), -// 16.height, -// Row( -// mainAxisAlignment: MainAxisAlignment.spaceBetween, -// children: [ -// SizedBox( -// width: 200.toScreenHeight, -// child: AppFilledButton( -// label: context.translation.cancel, -// loading: false, -// buttonColor: Colors.transparent, -// showBorder: true, -// textColor: AppColor.balck10, -// onPressed: -// () async { -// Navigator.pop(context); -// // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); -// // Navigator.pop(context, true); -// }, -// ), -// ), -// SizedBox( -// width: 200.toScreenHeight, -// child: AppFilledButton( -// label: context.translation.fixed, -// buttonColor: AppColor.green70, -// loading: false, -// onPressed:(){ -// -// }, -// ), -// ), -// ], -// ), -// 16.height, -// ], -// ), -// ), -// ), -// ); -// } -// ); -// } -// ); -// } -// } - class ServiceRequestBottomSheet { - static Future fixRemotelyBottomSheet({required BuildContext context}) { - final GlobalKey formKey = GlobalKey(); + static Future fixRemotelyBottomSheet({@required BuildContext context}) { + final GlobalKey _formKey = GlobalKey(); return showModalBottomSheet( context: context, useSafeArea: true, @@ -244,105 +42,57 @@ class ServiceRequestBottomSheet { ), padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), child: Form( - key: formKey, + key: _formKey, child: SingleChildScrollView( child: StatefulBuilder(builder: (context, setState) { return Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Center( - child: Container( - width: 40.toScreenWidth, - height: 5.toScreenHeight, - decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), - ), - ), + const SizedBox().indicatorWidget(), + 16.height, Align( alignment: AlignmentDirectional.centerStart, - child: context.translation.fillDetails.heading5(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), + child: context.translation.fillDetails.bottomSheetHeadingTextStyle(context), ), - 8.height, + 16.height, ADatePicker( label: context.translation.date, hideShadow: true, height: 80.toScreenHeight, - backgroundColor: AppColor.neutral90, - date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest?.startDate ?? ""), + backgroundColor: AppColor.neutral100, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.startDate ?? ""), formatDateWithTime: true, onDatePicker: (selectedDate) { - showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ).then((selectedTime) { - // Handle the selected date and time here. - if (selectedTime != null) { - DateTime selectedDateTime = DateTime( - selectedDate.year, - selectedDate.month, - selectedDate.day, - selectedTime.hour, - selectedTime.minute, - ); - if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.currentSelectedRequest!.date!))) { - "Visit Date time must be greater then request date".showToast; - return; - } + if (selectedDate != null) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + // Handle the selected date and time here. + if (selectedTime != null) { + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.currentSelectedRequest.date))) { + "Visit Date time must be greater then request date".showToast; + return; + } - setState(() { - serviceRequestProvider.currentSelectedRequest?.startDate = selectedDateTime.toIso8601String(); - }); - print('start date i got is ${serviceRequestProvider.currentSelectedRequest?.startDate}'); - } - }); - }, + setState(() { + serviceRequestProvider.currentSelectedRequest.startDate = selectedDateTime?.toIso8601String(); + }); + print('start date i got is ${serviceRequestProvider.currentSelectedRequest.startDate}'); + } + } + }); + } + }, ), - - // ATimePicker( - // label: context.translation.startTime, - // height: 80.toScreenHeight, - // backgroundColor: AppColor.neutral90, - // hint: context.translation.pickTime, - // time: serviceRequestProvider.selectedTime, - // onTimePicker: (selectedTime) { - // //TODO handle selected time here. - // if (selectedTime != null) { - // // setState(() { - // serviceRequestProvider.selectedTime = selectedTime; - // // }); - // // DateTime selectedDateTime = DateTime( - // // selectedDate.year, - // // selectedDate.month, - // // selectedDate.day, - // // selectedTime.hour, - // // selectedTime.minute, - // // ); - // // if (selectedDateTime != null) { - // // if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.serviceRequest.date))) { - // // "Visit Date time must be greater then request date".showToast; - // // return; - // // } - // // - // - // // } - // } - // }, - // ), - // 8.height, - // ATimePicker( - // label: context.translation.endTime, - // height: 80.toScreenHeight, - // backgroundColor: AppColor.neutral90, - // hint: context.translation.pickTime, - // time: serviceRequestProvider.selectedTime, - // onTimePicker: (selectedTime) { - // //TODO handle selected time here. - // if (selectedTime != null) { - // // setState(() { - // serviceRequestProvider.selectedTime = selectedTime; - // // }); - // } - // }, - // ), 8.height, SizedBox( width: double.infinity, @@ -352,7 +102,7 @@ class ServiceRequestBottomSheet { label: context.translation.workingHours, timer: TimerModel(), decoration: BoxDecoration( - color: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + color: context.isDark ? AppColor.neutral20 : AppColor.neutral100, borderRadius: BorderRadius.circular(10), // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], ), @@ -363,28 +113,20 @@ class ServiceRequestBottomSheet { return true; }, ), - // Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.start, - // children: [ - // context.translation.workingHours.bodyText2(context), - // //TODo calculate the hours and write here. - // 'No of hours'.bodyText(context).custom(color: AppColor.balck10), - // ], - // ), + ), 8.height, AppTextFormField( labelText: context.translation.comments, textInputType: TextInputType.multiline, showWithoutDecoration: true, - backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100, alignLabelWithHint: true, onChange: (text) { - serviceRequestProvider.currentSelectedRequest?.comments = text; + serviceRequestProvider.currentSelectedRequest.comments = text; }, onSaved: (text) { - serviceRequestProvider.currentSelectedRequest?.comments = text; + serviceRequestProvider.currentSelectedRequest.comments = text; }, ), 16.height, @@ -398,7 +140,7 @@ class ServiceRequestBottomSheet { loading: false, buttonColor: Colors.transparent, showBorder: true, - textColor: AppColor.black10, + textColor: AppColor.black20, onPressed: () async { Navigator.pop(context); // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); @@ -427,70 +169,70 @@ class ServiceRequestBottomSheet { })); } - static Future initialVisitBottomSheet({required BuildContext context}) { - final GlobalKey formKey = GlobalKey(); + static Future initialVisitBottomSheet({@required BuildContext context}) { + final GlobalKey _formKey = GlobalKey(); return showModalBottomSheet( context: context, useSafeArea: true, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => Consumer(builder: (context, serviceRequestProvider, child) { - return Container( - clipBehavior: Clip.antiAlias, - margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), - ), - padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), - child: Form( - key: formKey, - child: SingleChildScrollView( - child: Column( - children: [ - Container( - width: 40.toScreenWidth, - height: 5.toScreenHeight, - decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), - ), - Align( - alignment: AlignmentDirectional.centerStart, - child: context.translation.setVisitDate.heading5(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), - ), - - 8.height, - ADatePicker( - label: context.translation.visitDate, - date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest?.visitDate ?? ""), - formatDateWithTime: true, - onDatePicker: (selectedDate) { + return Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + children: [ + const SizedBox().indicatorWidget(), + 8.height, + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.setVisitDate.bottomSheetHeadingTextStyle(context), + ), + 15.height, + ADatePicker( + label: context.translation.visitDate, + hideShadow: true, + backgroundColor: AppColor.neutral100, + height: 70.toScreenHeight, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.visitDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { showTimePicker( context: context, initialTime: TimeOfDay.now(), ).then((selectedTime) { // Handle the selected date and time here. if (selectedTime != null) { - DateTime selectedDateTime = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.currentSelectedRequest!.date!))) { - "Visit Date time must be greater then request date".showToast; - return; + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.currentSelectedRequest.date))) { + "Visit Date time must be greater then request date".showToast; + return; + } + serviceRequestProvider.currentSelectedRequest.visitDate = selectedDateTime?.toIso8601String(); } - serviceRequestProvider.currentSelectedRequest?.visitDate = selectedDateTime.toIso8601String(); - } + } }); - }, - ), - // ], - - if (serviceRequestProvider.currentSelectedRequest?.firstAction?.id == 404 && Provider.of(context, listen: false).assetGroup!.id == 1) ...[ - 8.height, - Row( - children: [ - ADatePicker( - label: context.translation.startDate, - date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest?.startDate ?? ""), - formatDateWithTime: true, - onDatePicker: (selectedDate) { + } + }, + ), + if (serviceRequestProvider.currentSelectedRequest.firstAction?.id == 404 && Provider.of(context, listen: false).assetGroup.id == 1) ...[ + 8.height, + Row( + children: [ + ADatePicker( + label: context.translation.startDate, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.startDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { showTimePicker( context: context, initialTime: TimeOfDay.now(), @@ -504,197 +246,198 @@ class ServiceRequestBottomSheet { selectedTime.hour, selectedTime.minute, ); - serviceRequestProvider.currentSelectedRequest?.startDate = selectedDateTime.toIso8601String(); - } + if (selectedDateTime != null) { + serviceRequestProvider.currentSelectedRequest.startDate = selectedDateTime?.toIso8601String(); + } + } }); - }, - ).expanded, - 8.width, - ADatePicker( - label: context.translation.endDate, - date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest?.endDate ?? ""), - formatDateWithTime: true, - onDatePicker: (selectedDate) { + } + }, + ).expanded, + 8.width, + ADatePicker( + label: context.translation.endDate, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.endDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { showTimePicker( context: context, initialTime: TimeOfDay.now(), ).then((selectedTime) { // Handle the selected date and time here. if (selectedTime != null) { - DateTime selectedDateTime = DateTime(selectedDate.year, selectedDate.month, selectedDate.day, selectedTime.hour, selectedTime.minute); - serviceRequestProvider.currentSelectedRequest?.endDate = selectedDateTime.toIso8601String(); - serviceRequestProvider.currentSelectedRequest?.workingHours = (((DateTime.parse(serviceRequestProvider.currentSelectedRequest!.endDate!) - .difference(DateTime.parse(serviceRequestProvider.currentSelectedRequest!.startDate!)) - .inSeconds ?? - 0) / - 60) / - 60) - .toStringAsFixed(2); - } + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + serviceRequestProvider.currentSelectedRequest.endDate = selectedDateTime?.toIso8601String(); + serviceRequestProvider.currentSelectedRequest.workingHours = (((DateTime.parse(serviceRequestProvider.currentSelectedRequest.endDate) + .difference(DateTime.parse(serviceRequestProvider.currentSelectedRequest.startDate)) + .inSeconds ?? + 0) / + 60) / + 60) + .toStringAsFixed(2); + } + } }); - }, - ).expanded, - ], - ) - ], - 8.height, - AppTextFormField( - labelText: context.translation.comments, - textInputType: TextInputType.multiline, - alignLabelWithHint: true, - onChange: (text) { - serviceRequestProvider.currentSelectedRequest?.comments = text; - }, - onSaved: (text) { - serviceRequestProvider.currentSelectedRequest?.comments = text; - }, - ), - 16.height, - Consumer( - builder: (context, snapshot, _) => AppFilledButton( - label: context.translation.save, - loading: snapshot.isLoading ?? false, - onPressed: () async { - formKey.currentState!.save(); - - // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); - // Navigator.pop(context, true); - Navigator.of(context).push(MaterialPageRoute(builder: (_) => const VerifyArrivalView())); - }, - ), - ), - 16.height, + } + }, + ).expanded, + ], + ) ], - ), + 8.height, + AppTextFormField( + labelText: context.translation.comments, + backgroundColor: AppColor.neutral100, + showShadow: false, + textInputType: TextInputType.multiline, + alignLabelWithHint: true, + onChange: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + onSaved: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + ), + 12.height, + AppFilledButton( + label: context.translation.save, + buttonColor: AppColor.primary10, + + loading: serviceRequestProvider.isLoading ?? false, + onPressed: () async { + _formKey.currentState.save(); + + // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); + // Navigator.pop(context, true); + Navigator.of(context).push(MaterialPageRoute(builder: (_) => VerifyArrivalView())); + }, + ), + 16.height, + ], ), ), - ); + ).bottomSheetContainer(context); })); } - static Future rejectRequestBottomSheet({required BuildContext context}) { - final GlobalKey formKey = GlobalKey(); - final userProvider = Provider.of(context, listen: false); + static Future rejectRequestBottomSheet({@required BuildContext context}) { + final GlobalKey _formKey = GlobalKey(); return showModalBottomSheet( context: context, useSafeArea: true, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => Consumer(builder: (context, serviceRequestProvider, child) { - return Container( - clipBehavior: Clip.antiAlias, - margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), - ), - padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), - child: Form( - key: formKey, - child: SingleChildScrollView( - child: Column( - children: [ - Container( - width: 40.toScreenWidth, - height: 5.toScreenHeight, - decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), - ), - Align( - alignment: AlignmentDirectional.centerStart, - child: context.translation.rejectionReason.heading3(context).custom(fontWeight: FontWeight.w600).paddingOnly(top: 16, bottom: 16), - ), - SingleItemDropDownMenu( - context: context, - title: context.translation.rejectionReason, - initialValue: serviceRequestProvider.currentSelectedRequest?.firstAction, //_serviceRequest.firstAction, - onSelect: (value) { - serviceRequestProvider.currentSelectedRequest?.firstAction = value; - if (serviceRequestProvider.currentSelectedRequest?.firstAction!.value != 2) { - serviceRequestProvider.currentSelectedRequest?.visitDate = null; - } - }, - ), - 8.height, - AppTextFormField( - labelText: context.translation.comments, - textInputType: TextInputType.multiline, - alignLabelWithHint: true, - onChange: (text) { - serviceRequestProvider.currentSelectedRequest?.comments = text; - }, - onSaved: (text) { - serviceRequestProvider.currentSelectedRequest?.comments = text; + return Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + children: [ + const SizedBox().indicatorWidget(), + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.rejectionReason.heading4(context).paddingOnly(top: 21), + ), + 15.height, + SingleItemDropDownMenu( + context: context, + backgroundColor: AppColor.neutral100, + height: 70.toScreenHeight, + title: context.translation.rejectionReason, + initialValue: serviceRequestProvider.currentSelectedRequest.firstAction, //_serviceRequest.firstAction, + onSelect: (value) { + serviceRequestProvider.currentSelectedRequest.firstAction = value; + if (serviceRequestProvider.currentSelectedRequest.firstAction.value != 2) { + serviceRequestProvider.currentSelectedRequest.visitDate = null; + } + }, + ), + 12.height, + AppTextFormField( + backgroundColor: AppColor.neutral100, + labelText: context.translation.comments, + textInputType: TextInputType.multiline, + alignLabelWithHint: true, + onChange: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + onSaved: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + ), + 16.height, + Consumer( + builder: (context, snapshot, _) => AppFilledButton( + label: context.translation.reject, + maxWidth: true, + buttonColor: Colors.white54, + textColor: AppColor.red30, + showBorder: true, + loading: snapshot.isLoading ?? false, + onPressed: () async { + _formKey.currentState.save(); + //Todo implement backend logic.. + // serviceRequestProvider.serviceRequest.device = asset; + // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.currentSelectedRequest); + Navigator.pop(context, true); }, ), - 16.height, - Consumer( - builder: (context, snapshot, _) => AppFilledButton( - label: context.translation.reject, - maxWidth: true, - buttonColor: Colors.white54, - textColor: AppColor.red50, - showBorder: true, - loading: snapshot.isLoading ?? false, - onPressed: () async { - formKey.currentState!.save(); - // serviceRequestProvider.serviceRequest.device = asset; - await snapshot.updateRequest(user: userProvider.user!, request: serviceRequestProvider.currentSelectedRequest!); - Navigator.pop(context, true); - }, - ), - ), - 16.height, - ], - ), + ), + 16.height, + ], ), ), - ); + ).bottomSheetContainer(context); })); } - static Future activityTypeBottomSheet({required BuildContext context}) { + static Future activityTypeBottomSheet({@required BuildContext context}) { final List> items = [ {'heading': context.translation.sparePartRequest, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.sparePartIcon}, {'heading': context.translation.maintenanceRequest, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.maintenanceIcon}, - {'heading': context.translation.assetToBeRetired, 'subHeading': context.translation.sparePartRequestDetail, 'icon': AppAsset.retiredAssetIcon}, ]; - Widget listItem({required BuildContext context, required String icon, required String heading, required String subHeading, required VoidCallback onTap}) { - return Padding( - padding: EdgeInsets.only(bottom: 8.toScreenHeight), - child: Card( - color: AppColor.neutral80, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15), - // Circular border radius + Widget listItem({@required BuildContext context, @required String icon, @required String heading, @required String subHeading, @required VoidCallback onTap}) { + return Card( + color: AppColor.neutral80, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(14), + // Circular border radius + ), + // color: Colors.white, + child: ListTile( + minVerticalPadding:12.toScreenWidth, + horizontalTitleGap: 2.toScreenHeight, + onTap: onTap, + contentPadding: const EdgeInsets.all(8), + leading: SvgPicture.asset(icon), + title: Text( + heading, + style: AppTextStyles.heading6, ), - // color: Colors.white, - child: ListTile( - minVerticalPadding: 8, - horizontalTitleGap: 10, - onTap: onTap, - contentPadding: const EdgeInsets.all(8), - leading: SvgPicture.asset(icon), - title: Text( - heading, - style: AppTextStyles.heading5, - ), - subtitle: Text( - subHeading, - style: AppTextStyles.bodyText, - ), + subtitle: Text( + subHeading, + style: AppTextStyles.bodyText2, ), ), ); } - void onItemTap({required int index, required ServiceRequest serviceRequest, required BuildContext context}) { - print('on item tap i got index is $index'); + void onItemTap({@required int index, @required ServiceRequest serviceRequest, @required BuildContext context}) { switch (index) { case 0: Navigator.of(context).push(MaterialPageRoute(builder: (_) => const SparePartRequest())); break; case 1: + //push to specific screen... // Navigator.push( // context, @@ -708,6 +451,13 @@ class ServiceRequestBottomSheet { // MaterialPageRoute(builder: (context) => const ScanQrView()), // ); break; + case 2: + //push to specific screen... + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => const ScanQrView()), + // ); + break; } // ScanQr } @@ -715,7 +465,7 @@ class ServiceRequestBottomSheet { return showModalBottomSheet( context: context, useSafeArea: true, - isScrollControlled: false, + isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => Consumer(builder: (context, serviceRequestProvider, child) { return Container( @@ -726,39 +476,39 @@ class ServiceRequestBottomSheet { borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), ), padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), - child: SafeArea( - child: Column( - children: [ - Align( - alignment: AlignmentDirectional.centerStart, - child: context.translation.selectActivityType.heading4(context).paddingOnly(top: 16, bottom: 16), - ), - ListView.builder( - shrinkWrap: true, - padding: EdgeInsets.zero, - itemCount: items.length, - itemBuilder: (context, index) { - final item = items[index]; - return listItem( - icon: item['icon']!, - heading: item['heading']!, - subHeading: item['subHeading']!, - context: context, - onTap: () { - onItemTap(serviceRequest: serviceRequestProvider.currentSelectedRequest!, index: index, context: context); - }); - }, - ), - ], - ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox().indicatorWidget(), + 8.height, + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.selectActivityType.bottomSheetHeadingTextStyle(context), + ), + 16.height, + ListView.builder( + shrinkWrap: true, + padding: EdgeInsets.zero, + itemCount: items.length, + itemBuilder: (context, index) { + final item = items[index]; + return listItem( + icon: item['icon'], + heading: item['heading'], + subHeading: item['subHeading'], + context: context, + onTap: () { + onItemTap(serviceRequest: serviceRequestProvider.currentSelectedRequest, index: index, context: context); + }); + }, + ), + ], ), ); })); } - static Future actionBottomSheet({required BuildContext context, required String title, String? noButtonText, String? yesButtonText, VoidCallback? onNoPressed, VoidCallback? onYesPressed}) { - final GlobalKey formKey = GlobalKey(); - final userProvider = Provider.of(context, listen: false); + static Future actionBottomSheet({@required BuildContext context, @required String title, String button1Text, String button2Text, VoidCallback button1Tap, VoidCallback button2Tap}) { return showModalBottomSheet( context: context, useSafeArea: true, @@ -772,46 +522,39 @@ class ServiceRequestBottomSheet { color: Theme.of(context).scaffoldBackgroundColor, borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), ), - padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 12.toScreenHeight), child: Column( mainAxisSize: MainAxisSize.min, children: [ - Container( - width: 40.toScreenWidth, - height: 5.toScreenHeight, - decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), - ), + const SizedBox().indicatorWidget(), + 8.height, Align( alignment: AlignmentDirectional.centerStart, - child: title.heading4(context).custom(fontWeight: FontWeight.w500).paddingOnly(top: 16, bottom: 16), + child: title.bottomSheetHeadingTextStyle(context), ), + 41.height, Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - SizedBox( - width: 200.toScreenHeight, - child: AppFilledButton( - label: noButtonText ?? context.translation.no, - loading: false, - buttonColor: AppColor.neutral40, - textColor: AppColor.black10, - onPressed: onNoPressed ?? - () async { - Navigator.pop(context); - // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); - // Navigator.pop(context, true); - }, - ), - ), - SizedBox( - width: 200.toScreenHeight, - child: AppFilledButton( - label: context.translation.yes, - buttonColor: AppColor.primary10, - loading: false, - onPressed: onYesPressed, - ), - ), + AppFilledButton( + label: button1Text ?? context.translation.no, + loading: false, + buttonColor: AppColor.white60, + textColor: AppColor.black10, + onPressed: button1Tap ?? + () async { + Navigator.pop(context); + // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); + // Navigator.pop(context, true); + }, + ).expanded, + 12.width, + AppFilledButton( + label: context.translation.yes, + buttonColor: AppColor.primary10, + loading: false, + onPressed: button2Tap, + ).expanded, ], ) ], @@ -819,4 +562,153 @@ class ServiceRequestBottomSheet { ); })); } + static Future feedBackBottomSheet({@required BuildContext context}) { + final GlobalKey _formKey = GlobalKey(); + return showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) => Consumer(builder: (context, serviceRequestProvider, child) { + return Container( + clipBehavior: Clip.antiAlias, + margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), + decoration: BoxDecoration( + color: AppColor.background(context), + borderRadius: const BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)), + ), + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 16.toScreenHeight), + child: Form( + key: _formKey, + child: SingleChildScrollView( + child: StatefulBuilder(builder: (context, setState) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox().indicatorWidget(), + 8.height, + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.feedBack.bottomSheetHeadingTextStyle(context), + ), + 21.height, + AppTextFormField( + labelText: context.translation.comments, + textInputType: TextInputType.multiline, + showWithoutDecoration: true, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100, + alignLabelWithHint: true, + onChange: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + onSaved: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + ), + 16.height, + AppFilledButton( + label: context.translation.fixed, + buttonColor: AppColor.green70, + loading: false, + onPressed: () {}, + ), + ], + ); + }), + ), + ), + ); + })); + } + static Future nurseTakeActionBottomSheet({@required BuildContext context}) { + final GlobalKey _formKey = GlobalKey(); + return showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (context) => Consumer(builder: (context, serviceRequestProvider, child) { + return Form( + key: _formKey, + child: SingleChildScrollView( + child: StatefulBuilder(builder: (context, setState) { + bool acknowledge = false; + Uint8List newSignature; + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox().indicatorWidget(), + 8.height, + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.pleaseConfirmTheIssueHasBeenResolved.bottomSheetHeadingTextStyle(context), + ), + 10.height, + Row( + children: [ + Checkbox( + value: serviceRequestProvider.ackhnowledge, + activeColor: AppColor.blueStatus(context), + onChanged: (value) { + setState(() { + acknowledge = !value; + }); + print('acknowledge value is $acknowledge'); + + }), + context.translation.nurseAcknowledge.bodyText(context).custom(color: context.isDark ? AppColor.primary50 : AppColor.neutral120), + ], + ), + 17.height, + ESignature( + title: '', + oldSignature: '', + newSignature: newSignature, + backgroundColor: AppColor.neutral100, + showShadow: false, + onSaved: (signature) { + // if (signature == null || signature.isEmpty) { + // setState(() {}); + // return; + // } + if (signature == null || signature.isEmpty) return; + newSignature = signature; + // _subWorkOrders.nurseSignature = signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature)}" : null; + }, + ), + 16.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + AppFilledButton( + label: context.translation.reject, + maxWidth: true, + buttonColor: Colors.white54, + textColor: AppColor.red30, + showBorder: true, + onPressed: () async { + ServiceRequestBottomSheet.rejectRequestBottomSheet(context: context); + }, + ).expanded, + const SizedBox( + width: 20, + ), + AppFilledButton( + label: context.translation.confirm, + maxWidth: true, + buttonColor: AppColor.green70, + onPressed: () async { + }, + ).expanded, + ], + ) + + ], + ); + }), + ), + ).bottomSheetContainer(context); + })); + } } diff --git a/lib/service_request_latest/views/components/initial_visit_card.dart b/lib/service_request_latest/views/components/initial_visit_card.dart new file mode 100644 index 00000000..4da5616c --- /dev/null +++ b/lib/service_request_latest/views/components/initial_visit_card.dart @@ -0,0 +1,42 @@ +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/new_views/app_style/app_color.dart'; + +class InitialVisitCard extends StatelessWidget { + const InitialVisitCard({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(14), + color: AppColor.white10, + ), + padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth, vertical: 14.toScreenHeight), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Text( + DateTime.now().toString().toInitialVisitCardFormat, + textAlign: TextAlign.end, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.black10), + ), + "edit_icon".toSvgAsset(height: 21, width: 21).onPress(() { + //open bottom sheet again with the informations added... + }), + ]), + 2.height, + context.translation.visitDateAndTime.heading6(context).custom(color: AppColor.neutral120), + 8.height, + 'Comments for the visit will be visible here for reference'.heading6(context).custom(color: AppColor.neutral120), + + ], + ), + ); + } +} diff --git a/lib/service_request_latest/views/components/request_detail_view.dart b/lib/service_request_latest/views/components/request_detail_view.dart index 7dff9894..0e6cac3b 100644 --- a/lib/service_request_latest/views/components/request_detail_view.dart +++ b/lib/service_request_latest/views/components/request_detail_view.dart @@ -14,8 +14,12 @@ import 'package:test_sa/models/service_request/service_request.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/service_request_latest/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart'; -import 'package:test_sa/service_request_latest/views/components/verify_otp_view.dart'; +import 'package:test_sa/service_request_latest/views/components/initial_visit_card.dart'; +import 'package:test_sa/service_request_latest/views/components/timer_widget.dart'; +import 'package:test_sa/service_request_latest/views/forms/asset_retired/asset_retired.dart'; +import 'package:test_sa/service_request_latest/views/nurse/create_new_request_view.dart'; import 'package:test_sa/views/pages/user/requests/comments_bottom_sheet.dart'; import 'package:test_sa/views/pages/user/requests/update_service_request_page.dart'; import 'package:test_sa/views/pages/user/requests/work_order/work_orders_list_page.dart'; @@ -24,12 +28,15 @@ import 'package:test_sa/views/widgets/loaders/app_loading.dart'; import 'package:test_sa/views/widgets/requests/request_status.dart'; import 'package:test_sa/views/widgets/sound/sound_player.dart'; +import '../../../models/lookup.dart'; +import '../forms/maintenance_request/maintenance_request_main.dart'; + class RequestDetailView extends StatefulWidget { static const String id = "/call-details"; ServiceRequest serviceRequest; bool fromTabView = false; - RequestDetailView({Key? key, required this.serviceRequest, this.fromTabView = false}) : super(key: key); + RequestDetailView({Key key, this.serviceRequest, this.fromTabView = false}) : super(key: key); @override State createState() => _RequestDetailViewState(); @@ -42,7 +49,7 @@ class _RequestDetailViewState extends State { getServiceRequest(requestId: widget.serviceRequest.id); } - void getServiceRequest({required dynamic requestId}) { + void getServiceRequest({@required dynamic requestId}) { // setState(() {}); WidgetsFlutterBinding.ensureInitialized().addPostFrameCallback((timeStamp) async { Provider.of(context, listen: false).reset(); @@ -51,27 +58,41 @@ class _RequestDetailViewState extends State { // setState(() {}); }); } + final GlobalKey _detailsCardKey = GlobalKey(); + + void createBreakPoint(){ + + final RenderBox detailContainerBox = + _detailsCardKey.currentContext?.findRenderObject() as RenderBox; + final detailContainerHeight = detailContainerBox?.size?.height; + + } @override Widget build(BuildContext context) { - UserProvider userProvider = Provider.of(context, listen: false); + UserProvider _userProvider = Provider.of(context, listen: false); + return !widget.fromTabView ? Scaffold( appBar: DefaultAppBar(title: context.translation.serviceDetails), body: Padding( padding: EdgeInsets.only(top: 12.toScreenHeight), child: Consumer(builder: (context, serviceRequestsProvider, child) { - return requestDetailCard(serviceRequestsProvider: serviceRequestsProvider, userProvider: userProvider); + return requestDetailCard(serviceRequestsProvider: serviceRequestsProvider, userProvider: _userProvider); }), ), ) : Consumer(builder: (context, serviceRequestsProvider, child) { - return requestDetailCard(serviceRequestsProvider: serviceRequestsProvider, userProvider: userProvider); + return requestDetailCard(serviceRequestsProvider: serviceRequestsProvider, userProvider: _userProvider); }); } - Widget requestDetailCard({required ServiceRequestsProvider serviceRequestsProvider, required UserProvider userProvider}) { + Widget requestDetailCard({ServiceRequestsProvider serviceRequestsProvider, UserProvider userProvider}) { + if(!serviceRequestsProvider.isDetialLoading){ + createBreakPoint(); + } return SafeArea( + key: _detailsCardKey, child: serviceRequestsProvider.isDetialLoading ? const ALoading().center : serviceRequestsProvider.currentSelectedRequest == null @@ -79,115 +100,26 @@ class _RequestDetailViewState extends State { context.translation.noDataFound, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), ).center - : Column( - crossAxisAlignment: CrossAxisAlignment.start, + : Stack( children: [ SingleChildScrollView( padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), - child: informationCard(serviceRequestsProvider.currentSelectedRequest!, userProvider), - ).expanded, - Center( - child: InkWell( - onTap: () async { - try { - //use a common list - AllRequestsProvider allRequestProvider = Provider.of(context, listen: false); - int index = allRequestProvider.requestDetailList!.requestsDetails!.indexWhere((element) => element.id.toString() == serviceRequestsProvider.currentSelectedRequest?.id); - if (index != -1 && index != allRequestProvider.requestDetailList!.requestsDetails!.length) { - getServiceRequest(requestId: allRequestProvider.requestDetailList!.requestsDetails![index + 1].id.toString()); - } - } catch (e) { - print(e); - } - }, - child: Text( - context.translation.skipForLater, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, decoration: TextDecoration.underline, fontSize: 16), - ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + informationCard(serviceRequestsProvider.currentSelectedRequest, userProvider), + + 40.height, + // skipForLater(serviceRequestsProvider.currentSelectedRequest), + // 20.height, + const InitialVisitCard(), + 20.height, + ], ), ), - 20.height, - if (userProvider.user!.type == UsersTypes.engineer || - (serviceRequestsProvider.currentSelectedRequest?.statusValue == 5 || serviceRequestsProvider.currentSelectedRequest?.statusValue == 3)) - (serviceRequestsProvider.currentSelectedRequest?.firstAction == null - ? Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: [ - AppFilledButton( - label: context.translation.reject, - maxWidth: true, - buttonColor: Colors.white54, - textColor: AppColor.red50, - showBorder: true, - onPressed: () async { - ServiceRequestBottomSheet.rejectRequestBottomSheet(context: context); - // bool shouldReloadData = (await showModalBottomSheet( - // context: context, - // useSafeArea: true, - // isScrollControlled: true, - // backgroundColor: Colors.transparent, - // builder: (context) => RejectRequestBottomSheet(), - // )) as bool; - // if (shouldReloadData ?? false) { - // getServiceRequest(); - // } - }, - ).expanded, - const SizedBox( - width: 20, - ), - AppFilledButton( - label: context.translation.accept, - maxWidth: true, - buttonColor: AppColor.green70, - onPressed: () async { - // GeneralUtils.showFlushBar(context: context); - Navigator.of(context).push(MaterialPageRoute(builder: (_) => const VerifyOtpView())); - - // ServiceRequestBottomSheet.fixRemotelyBottomSheet(context: context); - // bool shouldReloadData = (await showModalBottomSheet( - // context: context, - // useSafeArea: true, - // isScrollControlled: true, - // backgroundColor: Colors.transparent, - // builder: (context) => InitialVisitBottomSheet(), - // )) as bool; - // if (shouldReloadData ?? false) { - // getServiceRequest(); - // } - }, - ).expanded, - ], - ) - // ? AppFilledButton( - // label: context.translation.firstAction, - // maxWidth: true, - // onPressed: () async { - // bool shouldReloadData = (await showModalBottomSheet( - // context: context, - // useSafeArea: true, - // isScrollControlled: true, - // backgroundColor: Colors.transparent, - // builder: (context) => FirstActionBottomSheet(request: serviceRequestsProvider.serviceRequest), - // )) as bool; - // if (shouldReloadData ?? false) { - // getServiceRequest(); - // } - // }, - // ) - : AppFilledButton( - label: context.translation.viewWorkOrder, - maxWidth: true, - onPressed: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => WorkOrderListPage(serviceRequest: serviceRequestsProvider.currentSelectedRequest!)), - ); - // Navigator.of(context).pushNamed(WorkOrderListPage.id, arguments: serviceRequest); - }, - )) - .paddingOnly(start: 16, end: 16, bottom: 24), + FooterActionButton.footerWidget(status: 1, context: context), + const TimerWidget(), ], ), ); @@ -211,30 +143,30 @@ class _RequestDetailViewState extends State { mainAxisSize: MainAxisSize.min, children: [ StatusLabel( - label: serviceRequest.priority?.name, - id: serviceRequest.priority!.id!, + label: serviceRequest.priority.name, + id: serviceRequest.priority.id, radius: 4, - textColor: AppColor.getPriorityStatusTextColor(context, serviceRequest.priority!.id!), - backgroundColor: AppColor.getPriorityStatusColor(context, serviceRequest.priority!.id!), + textColor: AppColor.getPriorityStatusTextColor(context, serviceRequest.priority.id), + backgroundColor: AppColor.getPriorityStatusColor(context, serviceRequest.priority.id), ), 8.width, StatusLabel( radius: 4, - label: serviceRequest.statusLabel!, - textColor: AppColor.getRequestStatusTextColor(context, serviceRequest.statusValue!), - backgroundColor: AppColor.getRequestStatusColor(context, serviceRequest.statusValue!), + label: serviceRequest.statusLabel, + textColor: AppColor.getRequestStatusTextColor(context, serviceRequest.statusValue), + backgroundColor: AppColor.getRequestStatusColor(context, serviceRequest.statusValue), ), 1.width.expanded, Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ - if (userProvider.user!.type == UsersTypes.normal_user) + if (userProvider.user.type == UsersTypes.normal_user) context.translation.code.toSvgAsset(width: 48).onPress(() { Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateServiceRequestPage(serviceRequest: serviceRequest))); }), - if (userProvider.user!.type == UsersTypes.engineer) 16.height, + if (userProvider.user.type == UsersTypes.engineer) 16.height, Text( - serviceRequest.date!.toServiceRequestCardFormat, + serviceRequest.date.toServiceRequestCardFormat, textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), @@ -247,7 +179,7 @@ class _RequestDetailViewState extends State { style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), 8.height, - '${context.translation.assetName}: ${serviceRequest.deviceEnName?.cleanupWhitespace.capitalizeFirstOfEach}'.bodyText(context), + '${context.translation.assetName}: ${serviceRequest.deviceEnName?.cleanupWhitespace?.capitalizeFirstOfEach}'.bodyText(context), // 8.height, Text( '${context.translation.assetNumber}: ${serviceRequest.device?.assetNumber}', @@ -259,31 +191,31 @@ class _RequestDetailViewState extends State { style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), ), Text( - '${context.translation.manufacture}: ${serviceRequest.device!.modelDefinition?.manufacturerName?.cleanupWhitespace.capitalizeFirstOfEach}', + '${context.translation.manufacture}: ${serviceRequest.device.modelDefinition.manufacturerName?.cleanupWhitespace?.capitalizeFirstOfEach}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), ), Text( - '${context.translation.model}: ${serviceRequest.device!.modelDefinition?.modelName?.cleanupWhitespace.capitalizeFirstOfEach}', + '${context.translation.model}: ${serviceRequest.device.modelDefinition.modelName?.cleanupWhitespace?.capitalizeFirstOfEach}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), ), Text( - '${context.translation.site}: ${serviceRequest.device!.site?.custName?.cleanupWhitespace.capitalizeFirstOfEach}', + '${context.translation.site}: ${serviceRequest.device.site?.custName?.cleanupWhitespace?.capitalizeFirstOfEach}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), ), Text( - '${context.translation.building}: ${serviceRequest.device!.building?.name?.cleanupWhitespace.capitalizeFirstOfEach}', + '${context.translation.building}: ${serviceRequest.device.building?.name?.cleanupWhitespace?.capitalizeFirstOfEach}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), ), Text( - '${context.translation.floor}: ${serviceRequest.device!.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? ""}', + '${context.translation.floor}: ${serviceRequest.device.floor?.name?.cleanupWhitespace?.capitalizeFirstOfEach ?? ""}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), ), Text( - '${context.translation.department}: ${serviceRequest.device!.department?.departmentName?.cleanupWhitespace.capitalizeFirstOfEach}', + '${context.translation.department}: ${serviceRequest.device.department?.departmentName?.cleanupWhitespace?.capitalizeFirstOfEach}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), ), Text( - '${context.translation.room}: ${(serviceRequest.device!.room?.name ?? "").cleanupWhitespace.capitalizeFirstOfEach}', + '${context.translation.room}: ${(serviceRequest.device.room?.name ?? "").cleanupWhitespace?.capitalizeFirstOfEach}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), ), ], @@ -300,7 +232,7 @@ class _RequestDetailViewState extends State { ), 8.height, Text( - '${context.translation.requestType}: ${serviceRequest.type!.name}', + '${context.translation.requestType}: ${serviceRequest.type.name}', style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), ), Text( @@ -317,24 +249,24 @@ class _RequestDetailViewState extends State { const Divider().defaultStyle(context), 8.height, Text( - serviceRequest.callComments!, + serviceRequest.callComments, style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), ), ], - if (serviceRequest.devicePhotos?.isNotEmpty ?? false) ...[ + if (serviceRequest.devicePhotos.isNotEmpty) ...[ 8.height, const Divider().defaultStyle(context), - FilesList(images: serviceRequest.devicePhotos!), + FilesList(images: serviceRequest.devicePhotos), ], if (serviceRequest.audio?.isNotEmpty ?? false) ...[ const Divider().defaultStyle(context), 16.height, - ASoundPlayer(audio: serviceRequest.audio!), + ASoundPlayer(audio: serviceRequest.audio), 8.height, ], ], ).paddingOnly(start: 16, end: 16, top: 16, bottom: 8), - (userProvider.user!.type == UsersTypes.normal_user + (userProvider.user.type == UsersTypes.normal_user ? Container( height: 50, padding: const EdgeInsets.only(left: 16, right: 16), @@ -387,10 +319,59 @@ class _RequestDetailViewState extends State { isScrollControlled: true, useRootNavigator: true, backgroundColor: Colors.transparent, - builder: (context) => CommentsBottomSheet(requestId: serviceRequest.id!), + builder: (context) => CommentsBottomSheet(requestId: serviceRequest.id), ); }), + //set condition for show asset detail button... + if(true)...[ + assetRetiredButton(serviceRequest: serviceRequest), + ] ], ).toShadowContainer(context, padding: 0); } + + Widget assetRetiredButton({ServiceRequest serviceRequest}){ + return Padding( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenHeight,vertical: 12.toScreenWidth), + child: AppFilledButton( + label: context.translation.assetToBeRetired, + maxWidth: true, + buttonColor: Colors.white54, + textColor: AppColor.red30, + showBorder: true, + onPressed: () async { + // ServiceRequestBottomSheet.nurseTakeActionBottomSheet(context: context); + Navigator.push(context, MaterialPageRoute(builder: (context)=>const AssetRetired())); + + } + ), + ); + + + + + } + + Widget skipForLater (ServiceRequest serviceRequest){ + return Center( + child: InkWell( + onTap: () async { + try { + //use a common list + AllRequestsProvider allRequestProvider = Provider.of(context, listen: false); + int index = allRequestProvider.requestDetailList.requestsDetails.indexWhere((element) => element.id.toString() == serviceRequest.id); + if (index != -1 && index != allRequestProvider.requestDetailList.requestsDetails.length) { + getServiceRequest(requestId: allRequestProvider.requestDetailList.requestsDetails[index + 1].id.toString()); + } + } catch (e) { + print(e); + } + }, + child: Text( + context.translation.skipForLater, + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20, decoration: TextDecoration.underline, fontSize: 16), + ), + ), + ); + } } diff --git a/lib/service_request_latest/views/components/timer_widget.dart b/lib/service_request_latest/views/components/timer_widget.dart new file mode 100644 index 00000000..b96b3186 --- /dev/null +++ b/lib/service_request_latest/views/components/timer_widget.dart @@ -0,0 +1,195 @@ +import 'dart:async'; + +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/models/size_config.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/service_request_latest/request_detail_provider.dart'; + +class TimerWidget extends StatefulWidget { + const TimerWidget({Key key}) : super(key: key); + + @override + _TimerWidgetState createState() => _TimerWidgetState(); +} + + +class _TimerWidgetState extends State { + Offset position = Offset(SizeConfig.screenWidth - 100, SizeConfig.screenHeight / 2 - 50); + @override + void initState() { + // TODO: implement initState + Provider.of(context,listen: false).startTimer(); + super.initState(); + } + @override + void dispose() { + // TODO: implement dispose + //dispose the timer... + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, provider, child) { + return Positioned( + left: position.dx, + top: position.dy, + child: GestureDetector( + onPanEnd: (details){}, + onPanUpdate: (details) { + setState(() { + if (position.dy + details.delta.dy > 0 && position.dy + details.delta.dy < 560) { + position = Offset( + position.dx + details.delta.dx, // Update the X position + position.dy + details.delta.dy, // Update the Y position + ); + } + }); + }, + child: buildTimerWidget(provider), + ), + ); + }, + ); + } + + Widget buildTimerWidget(RequestDetailProvider provider) { + return GestureDetector( + onTap: () { + if (provider.isTimerRunning) { + provider.stopTimer(); + } else { + provider.startTimer(); + } + }, + child: Container( + padding: EdgeInsets.all(8.toScreenHeight), + width: 80.toScreenWidth, + decoration: BoxDecoration( + color: AppColor.black10, + borderRadius: BorderRadius.circular(10), + ), + child: + Column( + children: [ + 'drag_icon'.toSvgAsset(), + 12.height, + provider.currentTime.toString().toDragAbleTimerFormat.tinyFont(context).custom(color: AppColor.white10, fontWeight: FontWeight.w600), + 2.height, + context.translation.hours.tinyFont(context).custom(color: AppColor.white10, fontWeight: FontWeight.w600), + ], + ), + ), + ); + } +} + + //older code... + // DateTime startTime = DateTime(0, 0, 0, 0, 0, 0); // Start from 00:00:00 + // Timer timer; + // bool isRunning = false; + // + // @override + // void initState() { + // super.initState(); + // startTimer(); + // } + // + // void startTimer() { + // if (isRunning) return; + // timer = Timer.periodic(const Duration(seconds: 1), (Timer t) { + // setState(() { + // startTime = startTime.add(const Duration(seconds: 1)); + // }); + // }); + // setState(() { + // isRunning = true; + // }); + // } + // + // void stopTimer() { + // timer?.cancel(); + // setState(() { + // isRunning = false; + // }); + // } + // @override + // void dispose() { + // timer?.cancel(); + // super.dispose(); + // } + // + // @override + // Widget build(BuildContext context) { + // return Positioned( + // left: position.dx, + // top: position.dy, + // child: GestureDetector( + // onPanUpdate: (details) { + // setState(() { + // //calculate the exact bonds to be restrict the drag.. + // if(position.dy + details.delta.dy>0&&position.dy + details.delta.dy<560){ + // position = Offset( + // position.dx + details.delta.dx, // Update the X position + // position.dy + details.delta.dy, // Update the Y position + // ); + // } + // }); + // }, + // child: buildTimerWidget(), + // ), + // ); + // // return Positioned( + // // left: position.dx, + // // top: position.dy, + // // child: Draggable( + // // feedback: buildTimerWidget(), + // // childWhenDragging: Container(), + // // onDragEnd: (dragDetails) { + // // setState(() { + // // // Get the RenderBox of the parent widget (Stack) + // // final renderBox = context.findRenderObject() as RenderBox; + // // + // // // Convert the global position to a local position inside the Stack + // // position = dragDetails.offset; + // // }); + // // }, + // // child: buildTimerWidget(), + // // ), + // // ); + // } + // + // Widget buildTimerWidget() { + // return GestureDetector( + // onTap: (){ + // if(isRunning){ + // stopTimer(); + // }else{ + // startTimer(); + // } + // }, + // child: Container( + // padding: EdgeInsets.all(8.toScreenHeight), + // width: 80.toScreenWidth, + // decoration: BoxDecoration( + // color: AppColor.black10, + // borderRadius: BorderRadius.circular(10), + // ), + // child: Column( + // children: [ + // 'drag_icon'.toSvgAsset(), + // 12.height, + // startTime.toString().toDragAbleTimerFormat.tinyFont(context).custom(color: AppColor.white10, fontWeight: FontWeight.w600), + // 2.height, + // context.translation.hours.tinyFont(context).custom(color: AppColor.white10, fontWeight: FontWeight.w600), + // ], + // ), + // ), + // ); + // } diff --git a/lib/service_request_latest/views/components/verify_arrival_view.dart b/lib/service_request_latest/views/components/verify_arrival_view.dart index 5eae6d76..a5661d0e 100644 --- a/lib/service_request_latest/views/components/verify_arrival_view.dart +++ b/lib/service_request_latest/views/components/verify_arrival_view.dart @@ -6,14 +6,16 @@ import 'package:test_sa/controllers/providers/api/service_requests_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/service_request/service_request.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/service_request_latest/views/components/scan_qr_view.dart'; +import 'package:test_sa/views/widgets/qr/scan_qr.dart'; import 'activities_list_view.dart'; class VerifyArrivalView extends StatelessWidget { - const VerifyArrivalView({Key? key}) : super(key: key); + VerifyArrivalView({Key key}) : super(key: key); @override Widget build(BuildContext context) { @@ -29,18 +31,19 @@ class VerifyArrivalView extends StatelessWidget { body: Consumer(builder: (context, serviceRequestsProvider, child) { return SafeArea( child: ListView.builder( - padding: EdgeInsets.symmetric(vertical: 12.toScreenHeight), + padding: EdgeInsets.symmetric(vertical: 12.toScreenHeight), // padding: EdgeInsets.zero, itemCount: items.length, itemBuilder: (context, index) { final item = items[index]; return listItem( - icon: item['icon']!, - heading: item['heading']!, - subHeading: item['subHeading']!, - //context: context, + icon: item['icon'], + heading: item['heading'], + subHeading: item['subHeading'], + context: context, onTap: () { - onItemTap(serviceRequest: serviceRequestsProvider.currentSelectedRequest!, index: index, context: context); + + onItemTap(serviceRequest: serviceRequestsProvider.currentSelectedRequest, index: index,context: context); }); }, ), @@ -49,49 +52,60 @@ class VerifyArrivalView extends StatelessWidget { ); } - Widget listItem({required String icon, required String heading, required String subHeading, required VoidCallback onTap}) { + Widget listItem({@required BuildContext context, @required String icon, @required String heading, @required String subHeading, @required VoidCallback onTap}) { return Padding( - padding: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, bottom: 12.toScreenHeight), + padding: EdgeInsets.only(left: 16.toScreenWidth,right: 16.toScreenWidth,bottom: 12.toScreenHeight), + child: Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(14), // Circular border radius ), color: Colors.white, - child: ListTile( + child: + ListTile( minVerticalPadding: 12, horizontalTitleGap: 10, onTap: onTap, // contentPadding: const EdgeInsets.all(12), leading: SvgPicture.asset(icon), - title: Text(heading, style: AppTextStyles.heading5), - subtitle: Text(subHeading, style: AppTextStyles.bodyText), + title: Text( + heading, + style: AppTextStyles.heading5, + ), + subtitle: Text( + subHeading, + style: AppTextStyles.bodyText, + ), ), ), ); } - void onItemTap({required int index, required ServiceRequest serviceRequest, required BuildContext context}) { - print('on item tap i got index is $index'); - switch (index) { + void onItemTap({@required int index, @required ServiceRequest serviceRequest,@required BuildContext context}) { + switch(index){ case 0: Navigator.push( context, - MaterialPageRoute(builder: (context) => const ScanQrView()), + MaterialPageRoute(builder: (context) => const ScanQrView()), ); - break; - case 1: - //push to specific screen... + break;case 1: + //push to specific screen... Navigator.push( context, - MaterialPageRoute(builder: (context) => const ActivitiesListView()), + MaterialPageRoute(builder: (context) => ActivitiesListView()), ); - break; - case 2: - //push to specific screen... - // Navigator.push( - // context, - // MaterialPageRoute(builder: (context) => const ScanQrView()), - // ); + break;case 2: + //push to specific screen... + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => const ScanQrView()), + // ); + break;case 2: + //push to specific screen... + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) => const ScanQrView()), + // ); break; } // ScanQr diff --git a/lib/service_request_latest/views/components/spare_part_request.dart b/lib/service_request_latest/views/components/verify_assets_details.dart similarity index 92% rename from lib/service_request_latest/views/components/spare_part_request.dart rename to lib/service_request_latest/views/components/verify_assets_details.dart index 9a670118..7b702b26 100644 --- a/lib/service_request_latest/views/components/spare_part_request.dart +++ b/lib/service_request_latest/views/components/verify_assets_details.dart @@ -10,6 +10,7 @@ import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; import 'package:test_sa/models/service_request/service_report.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; @@ -19,7 +20,6 @@ import 'package:test_sa/providers/work_order/reason_provider.dart'; import 'package:test_sa/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; - import '../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; import '../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; import '../../../../../models/lookup.dart'; @@ -29,21 +29,21 @@ import '../../../../../new_views/common_widgets/default_app_bar.dart'; import '../../../controllers/validator/validator.dart'; class SparePartRequest extends StatefulWidget { - static const String id = "/spare-part-request"; + static const String id = "/verify-assets-detail"; - const SparePartRequest({Key? key}) : super(key: key); + const SparePartRequest({Key key}) : super(key: key); @override _SparePartRequestState createState() => _SparePartRequestState(); } class _SparePartRequestState extends State with TickerProviderStateMixin { - late UserProvider _userProvider; - late SettingProvider _settingProvider; - late ServiceRequestsProvider _serviceRequestsProvider; - late ServiceStatusProvider _assetTypeProvider; - late PartsProvider _partsProvider; - late ServiceReport _serviceReport; + UserProvider _userProvider; + SettingProvider _settingProvider; + ServiceRequestsProvider _serviceRequestsProvider; + ServiceStatusProvider _assetTypeProvider; + PartsProvider _partsProvider; + ServiceReport _serviceReport; bool _isLoading = false; List _spareParts = []; @@ -68,12 +68,12 @@ class _SparePartRequestState extends State with TickerProvider ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); Provider.of(context, listen: false).reset(); Provider.of(context, listen: false).reset(); - Provider.of(context, listen: false).serviceRequestId = serviceRequestsProvider.currentSelectedRequest?.id; + Provider.of(context, listen: false).serviceRequestId = serviceRequestsProvider.currentSelectedRequest.id; } // _isLoading = true; } - //Asset loanAvailabilityAsset; + Asset loanAvailabilityAsset; @override void dispose() { @@ -87,12 +87,12 @@ class _SparePartRequestState extends State with TickerProvider _isLoading = true; setState(() {}); ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); - _serviceReport.callRequest = await _serviceRequestsProvider.getCallRequestForWorkOrder(callId: serviceRequestsProvider.currentSelectedRequest!.id!); - await _assetTypeProvider.getTypes(); + _serviceReport.callRequest = await _serviceRequestsProvider.getCallRequestForWorkOrder(callId: serviceRequestsProvider.currentSelectedRequest.id); + await _assetTypeProvider.getTypes(user: _userProvider.user, host: _settingProvider.host); _serviceReport.assignedEmployee = _serviceReport.callRequest?.assignedEmployee; _serviceReport.equipmentStatus = _serviceReport.callRequest?.defectType; _serviceReport.serviceType = Lookup(id: 65, name: "Interval", value: 1); // default value in service type as in web - _spareParts = await _partsProvider.getPartsList(assetId: serviceRequestsProvider.currentSelectedRequest?.deviceId); + _spareParts = await _partsProvider.getPartsList(assetId: serviceRequestsProvider.currentSelectedRequest.deviceId); _isLoading = false; setState(() {}); } @@ -109,7 +109,7 @@ class _SparePartRequestState extends State with TickerProvider } _serviceReport.assetType = _assetTypeProvider.statuses?.firstWhere( (element) => element.value == _serviceReport.callRequest?.assetType, - orElse: null, + orElse: () => null, ); return Scaffold( @@ -156,7 +156,7 @@ class _SparePartRequestState extends State with TickerProvider contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 20.toScreenHeight), showWithoutDecoration: true, backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, - enable: serviceRequestProvider.initialSelectedSparePart.sparePart?.id != null, + enable: serviceRequestProvider.initialSelectedSparePart != null && serviceRequestProvider.initialSelectedSparePart.sparePart?.id != null, validator: (value) => value == null || value.isEmpty ? context.translation.requiredField : Validator.isNumeric(value) @@ -174,7 +174,7 @@ class _SparePartRequestState extends State with TickerProvider contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 20.toScreenHeight), showWithoutDecoration: true, backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, - enable: serviceRequestProvider.initialSelectedSparePart.sparePart?.id != null, + enable: serviceRequestProvider.initialSelectedSparePart != null && serviceRequestProvider.initialSelectedSparePart.sparePart?.id != null, validator: (value) => value == null || value.isEmpty ? context.translation.requiredField : Validator.isNumeric(value) @@ -187,7 +187,7 @@ class _SparePartRequestState extends State with TickerProvider ), 15.height, AppTextFormField( - initialValue: _serviceReport.comment ?? "", + initialValue: _serviceReport?.comment, backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, labelText: context.translation.description, alignLabelWithHint: true, diff --git a/lib/service_request_latest/views/components/work_order_card_view.dart b/lib/service_request_latest/views/components/work_order_card_view.dart new file mode 100644 index 00000000..3aaf39cb --- /dev/null +++ b/lib/service_request_latest/views/components/work_order_card_view.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/all_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/enums/user_types.dart'; +import 'package:test_sa/models/service_request/search_work_order.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/views/pages/user/requests/work_order/update_service_report.dart'; +import 'package:test_sa/views/pages/user/requests/work_order/work_order_details_page.dart'; + +import '../../../../views/widgets/requests/request_status.dart'; + +class WorkOrderCardView extends StatelessWidget { + final SearchWorkOrder workOrder; + final ServiceRequest serviceRequest; + final bool showShadow; + + WorkOrderCardView(this.workOrder, this.serviceRequest, {Key key, this.showShadow = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + UserProvider _userProvider = Provider.of(context, listen: false); + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: workOrder.currentSituation.name, + textColor: AppColor.getRequestStatusTextColorByName(context, workOrder.currentSituation.name), + backgroundColor: AppColor.getRequestStatusColorByName(context, workOrder.currentSituation.name), + ), + 8.height, + Text(serviceRequest.requestCode, style: AppTextStyles.heading5.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + Text( + '${context.translation.assetName}: ${workOrder.callRequest.asset.modelDefinition.assetName?.cleanupWhitespace?.capitalizeFirstOfEach}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + Text( + '${context.translation.currentSituation}: ${workOrder.currentSituation.name}', + style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral20), + ), + 16.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.translation.readCompleteThread, + style: AppTextStyles.bodyText.copyWith(color: AppColor.blueStatus(context), decoration: TextDecoration.underline), + ), + // 4.width, + // Icon(Icons.arrow_forward, color: AppColor.blueStatus(context), size: 14) + ], + ), + ], + ).onPress(() { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => WorkOrderDetailsPage(workOrder: workOrder, serviceRequest: serviceRequest)), + ); + }).expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + if (_userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3) + "edit_icon".toSvgAsset(height: 21, width: 21).onPress(() { + Navigator.of(context).push( + MaterialPageRoute(builder: (_) => UpdateServiceReport(request: serviceRequest, workOrder: workOrder)), + ); + }), + if (_userProvider.user.type == UsersTypes.engineer && serviceRequest.statusValue != 5 && serviceRequest.statusValue != 3) 8.height, + Text(workOrder.visitDate?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.end, style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral30 : const Color(0xFF3B3D4A))), + ], + ) + ], + ).toShadowContainer(context); + } +} diff --git a/lib/service_request_latest/views/forms/asset_retired/asset_retired.dart b/lib/service_request_latest/views/forms/asset_retired/asset_retired.dart new file mode 100644 index 00000000..fec8d708 --- /dev/null +++ b/lib/service_request_latest/views/forms/asset_retired/asset_retired.dart @@ -0,0 +1,168 @@ + +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_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/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/service_request/service_report.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/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/work_order/reason_provider.dart'; +import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import '../../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; +import '../../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import '../../../../../../models/lookup.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; +class AssetRetired extends StatefulWidget { + static const String id = "/asset-tobe-retired"; + + const AssetRetired({Key key}) : super(key: key); + + @override + _AssetRetiredState createState() => _AssetRetiredState(); +} + +class _AssetRetiredState extends State with TickerProviderStateMixin { + UserProvider _userProvider; + SettingProvider _settingProvider; + ServiceRequestsProvider _serviceRequestsProvider; + ServiceStatusProvider _assetTypeProvider; + ServiceReport _serviceReport; + bool _isLoading = false; + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + void initState() { + _serviceReport = ServiceReport( + // returnToService: DateTime.now(), + // //type: const Lookup(value: 2), + // device: widget.request.device, + sparePartsWorkOrders: [], + ); + super.initState(); + if (context.mounted) { + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).serviceRequestId = serviceRequestsProvider.currentSelectedRequest.id; + } + // _isLoading = true; + } + + Asset loanAvailabilityAsset; + + void getRequestForWorkOrder() async { + _isLoading = true; + setState(() {}); + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + _serviceReport.callRequest = await _serviceRequestsProvider.getCallRequestForWorkOrder(callId: serviceRequestsProvider.currentSelectedRequest.id); + await _assetTypeProvider.getTypes(user: _userProvider.user, host: _settingProvider.host); + _serviceReport.assignedEmployee = _serviceReport.callRequest?.assignedEmployee; + _serviceReport.equipmentStatus = _serviceReport.callRequest?.defectType; + _serviceReport.serviceType = Lookup(id: 65, name: "Interval", value: 1); // default value in service type as in web + _isLoading = false; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + _userProvider = Provider.of(context); + _settingProvider = Provider.of(context); + _serviceRequestsProvider = Provider.of(context); + _assetTypeProvider = Provider.of(context); + if (_serviceReport.callRequest == null) { + getRequestForWorkOrder(); + } + _serviceReport.assetType = _assetTypeProvider.statuses?.firstWhere( + (element) => element.value == _serviceReport.callRequest?.assetType, + orElse: () => null, + ); + final List _files = []; + + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: context.translation.assetToBeRetired), + body: Consumer(builder: (context, serviceRequestProvider, child) { + return SafeArea( + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + child: Card( + child: Column( + children: [ + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.failureReason, + backgroundColor: AppColor.neutral100, + height: 70.toScreenHeight, + showShadow: false, + // initialValue: _subWorkOrders.reason, + onSelect: (value) { + if (value != null) { + // _subWorkOrders.reason = value; + } + }, + ), + 8.height, + AppTextFormField( + labelText: context.translation.comments, + textInputType: TextInputType.multiline, + showWithoutDecoration: true, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100, + alignLabelWithHint: true, + onChange: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + onSaved: (text) { + serviceRequestProvider.currentSelectedRequest.comments = text; + }, + ), + 23.height, + MultiFilesPicker(label: context.translation.attachFiles, + files: _files, + buttonIcon: 'image-plus'?.toSvgAsset(), + ), + + + ], + ).paddingOnly(start:13,end: 13,top: 16,bottom: 16), + ).paddingAll(16), + ).expanded, + FooterActionButton.footerContainer( + child: AppFilledButton( + label: context.translation.submit, + buttonColor: AppColor.primary10, + onPressed: () async { + // + }, + ), + ), + ], + ), + ), + ), + ); + }), + ); + } +} diff --git a/lib/service_request_latest/views/forms/asset_retired/verify_asset_detail.dart b/lib/service_request_latest/views/forms/asset_retired/verify_asset_detail.dart new file mode 100644 index 00000000..f37c1852 --- /dev/null +++ b/lib/service_request_latest/views/forms/asset_retired/verify_asset_detail.dart @@ -0,0 +1,283 @@ + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/parts_provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/providers/settings/setting_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/service_request/service_report.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/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/service_request_providers/loan_availability_provider.dart'; +import 'package:test_sa/providers/work_order/reason_provider.dart'; +import 'package:test_sa/views/widgets/date_and_time/date_picker.dart'; +import 'package:test_sa/views/widgets/equipment/pick_asset.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import '../../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; +import '../../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import '../../../../../../models/lookup.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; +class VerifyAssetDetails extends StatefulWidget { + static const String id = "/verify-asset-detail"; + + const VerifyAssetDetails({Key key}) : super(key: key); + + @override + _VerifyAssetDetailsState createState() => _VerifyAssetDetailsState(); +} + +class _VerifyAssetDetailsState extends State with TickerProviderStateMixin { + UserProvider _userProvider; + SettingProvider _settingProvider; + ServiceRequestsProvider _serviceRequestsProvider; + ServiceStatusProvider _assetTypeProvider; + PartsProvider _partsProvider; + ServiceReport _serviceReport; + bool _isLoading = false; + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + int _selectedValue = 1; + + @override + void initState() { + _serviceReport = ServiceReport( + // returnToService: DateTime.now(), + // //type: const Lookup(value: 2), + // device: widget.request.device, + sparePartsWorkOrders: [], + ); + super.initState(); + if (context.mounted) { + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).serviceRequestId = serviceRequestsProvider.currentSelectedRequest.id; + } + // _isLoading = true; + } + + Asset loanAvailabilityAsset; + + void getRequestForWorkOrder() async { + _isLoading = true; + setState(() {}); + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + _serviceReport.callRequest = await _serviceRequestsProvider.getCallRequestForWorkOrder(callId: serviceRequestsProvider.currentSelectedRequest.id); + await _assetTypeProvider.getTypes(user: _userProvider.user, host: _settingProvider.host); + _serviceReport.assignedEmployee = _serviceReport.callRequest?.assignedEmployee; + _serviceReport.equipmentStatus = _serviceReport.callRequest?.defectType; + _serviceReport.serviceType = Lookup(id: 65, name: "Interval", value: 1); // default value in service type as in web + _isLoading = false; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + _userProvider = Provider.of(context); + _settingProvider = Provider.of(context); + _serviceRequestsProvider = Provider.of(context); + _assetTypeProvider = Provider.of(context); + _partsProvider = Provider.of(context); + if (_serviceReport.callRequest == null) { + getRequestForWorkOrder(); + } + _serviceReport.assetType = _assetTypeProvider.statuses?.firstWhere( + (element) => element.value == _serviceReport.callRequest?.assetType, + orElse: () => null, + ); + + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: context.translation.verify_asset_details), + body: Consumer(builder: (context, serviceRequestProvider, child) { + return SafeArea( + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + child: Card( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + context.translation.equipmentStatus.bodyText(context).custom(color: AppColor.black20), + 12.height, + assetStatusWidget(context), + 24.height, + ADatePicker( + label: context.translation.returnToService, + hideShadow: true, + height: 70.toScreenHeight, + backgroundColor: AppColor.neutral100, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.startDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + // Handle the selected date and time here. + if (selectedTime != null) { + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + if (selectedDateTime.isBefore(DateTime.parse(serviceRequestProvider.currentSelectedRequest.date))) { + "Visit Date time must be greater then request date".showToast; + return; + } + + setState(() { + serviceRequestProvider.currentSelectedRequest.startDate = selectedDateTime?.toIso8601String(); + }); + print('start date i got is ${serviceRequestProvider.currentSelectedRequest.startDate}'); + } + } + }); + } + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.loanAvailability, + initialValue: _serviceReport?.loanAvailablity, + onSelect: (status) { + if (status != null) { + setState(() { + _serviceReport.loanAvailablity = status; + if (_serviceReport.loanAvailablity.value != 1) { + loanAvailabilityAsset = null; + _serviceReport.assetLoan = null; + } + }); + } + }, + ), + if (_serviceReport?.loanAvailablity?.value == 1) 8.height, + if (_serviceReport?.loanAvailablity?.value == 1) + PickAsset( + device: loanAvailabilityAsset, // ?? _serviceReport.device, + onPickAsset: (asset) { + if (asset != null) { + _serviceReport.assetLoan = AssetInfo.fromJson(asset.toJson()); + setState(() { + loanAvailabilityAsset = asset; + }); + } + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.failureReason, + backgroundColor: AppColor.neutral100, + height: 70.toScreenHeight, + showShadow: false, + // initialValue: _subWorkOrders.reason, + onSelect: (value) { + if (value != null) { + // _subWorkOrders.reason = value; + } + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.faultDescription, + backgroundColor: AppColor.neutral100, + height: 70.toScreenHeight, + showShadow: false, + // initialValue: _subWorkOrders.reason, + onSelect: (value) { + if (value != null) { + // _subWorkOrders.reason = value; + } + }, + ), + 11.height, + context.translation.solutions.heading6(context).custom(color: AppColor.neutral50), + 11.height, + //TODO solution from api... + 'Solution number one \nSolution number two'.heading6(context).custom(color: AppColor.neutral50), + + ], + ).paddingOnly(start:13,end: 13,top: 16,bottom: 16), + ).paddingAll(16), + ).expanded, + Container( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth,vertical: 16.toScreenHeight), + color: AppColor.white10, + child: AppFilledButton( + label: context.translation.verify_asset_details, + buttonColor: AppColor.primary10, + onPressed: () async { + }, + ), + ), + ], + ), + ), + ), + ); + }), + ); + } + + Widget assetStatusWidget(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + radioButtonWidget(label: context.translation.up_and_running, value: 1), + radioButtonWidget(label: context.translation.partially_down, value: 2), + radioButtonWidget(label: context.translation.fully_down, value: 3), + ], + ); + } + + Widget radioButtonWidget({@required String label, @required dynamic value}) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 20.toScreenWidth, + height: 40.toScreenHeight, + //TODO use the type required according data.. + child: Radio( + activeColor: AppColor.primary10, + value: value, + groupValue: _selectedValue, + onChanged: (int value) { + setState(() { + _selectedValue = value; + }); + }, + ), + ), + 8.width, + Text( + label, + style: AppTextStyles.tinyFont, + ), + 13.width, + ], + ); + } +} diff --git a/lib/service_request_latest/views/forms/maintenance_request/components/external_request.dart b/lib/service_request_latest/views/forms/maintenance_request/components/external_request.dart new file mode 100644 index 00000000..592f4f9e --- /dev/null +++ b/lib/service_request_latest/views/forms/maintenance_request/components/external_request.dart @@ -0,0 +1,279 @@ + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/parts_provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_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/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/service_request/service_report.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/models/service_request/supp_engineer_work_orders.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/providers/loading_list_notifier.dart'; +import 'package:test_sa/providers/work_order/reason_provider.dart'; +import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/views/widgets/date_and_time/time_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import '../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; +import '../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import '../../../../../models/lookup.dart'; +import '../../../../../new_views/common_widgets/app_text_form_field.dart'; +import '../../../../../new_views/common_widgets/single_item_drop_down_menu.dart'; + +class ExternalMaintenanceRequest extends StatefulWidget { + static const String id = "/add-external-activity"; + + const ExternalMaintenanceRequest({Key key}) : super(key: key); + + @override + _ExternalMaintenanceRequestState createState() => _ExternalMaintenanceRequestState(); +} + +class _ExternalMaintenanceRequestState extends State with TickerProviderStateMixin { + UserProvider _userProvider; + SettingProvider _settingProvider; + ServiceRequest _request; + ServiceRequestsProvider _serviceRequestsProvider; + ServiceStatusProvider _assetTypeProvider; + ServiceReport _serviceReport; + bool _isLoading = false; + TimeOfDay _startTime; + int _selectedValue = 1; + + TimeOfDay _endTime; + + final GlobalKey _formKey = GlobalKey(); + final TextEditingController _faultController = TextEditingController(); + final TextEditingController _workPreformedController = TextEditingController(); + final TextEditingController _partQtyController = TextEditingController(); + + @override + void initState() { + _serviceReport = ServiceReport( + // returnToService: DateTime.now(), + // //type: const Lookup(value: 2), + // device: widget.request.device, + sparePartsWorkOrders: [], + ); + + super.initState(); + if (context.mounted) { + _request = Provider.of(context, listen: false).currentSelectedRequest; + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).serviceRequestId = _request.id; + } + // _isLoading = true; + } + + Asset loanAvailabilityAsset; + + @override + void dispose() { + _faultController.dispose(); + _workPreformedController.dispose(); + _partQtyController.dispose(); + super.dispose(); + } + + void getRequestForWorkOrder() async { + _isLoading = true; + setState(() {}); + _serviceReport.callRequest = await _serviceRequestsProvider.getCallRequestForWorkOrder(callId: _request.id); + await _assetTypeProvider.getTypes(user: _userProvider.user, host: _settingProvider.host); + _serviceReport.assignedEmployee = _serviceReport.callRequest?.assignedEmployee; + _serviceReport.equipmentStatus = _serviceReport.callRequest?.defectType; + _serviceReport.serviceType = Lookup(id: 65, name: "Interval", value: 1); // default value in service type as in web + _isLoading = false; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + _userProvider = Provider.of(context); + _settingProvider = Provider.of(context); + _serviceRequestsProvider = Provider.of(context); + _assetTypeProvider = Provider.of(context); + if (_serviceReport.callRequest == null) { + getRequestForWorkOrder(); + } + _serviceReport.assetType = _assetTypeProvider.statuses?.firstWhere( + (element) => element.value == _serviceReport.callRequest?.assetType, + orElse: () => null, + ); + + return LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Stack( + children: [ + SingleChildScrollView( + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + 8.height, + SingleItemDropDownMenu( + context: context, + height: 70.toScreenHeight, + title: context.translation.supplier, + showShadow: false, + backgroundColor: AppColor.neutral100, + staticData: Provider.of(context).calls, + initialValue: _serviceReport?.calllastSituation, + onSelect: (status) { + _serviceReport.calllastSituation = status; + }, + ), + // Container( + // height: 60.toScreenHeight, + // width: 60.toScreenWidth, + // decoration: BoxDecoration( + // color: _subWorkOrders.supplier?.suppliername == null ? AppColor.neutral40 : AppColor.background(context), + // borderRadius: BorderRadius.circular(10), + // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + // ), + // child: Icon( + // Icons.add, + // color: context.isDark ? null : AppColor.neutral60, + // ), + // ).onPress(_subWorkOrders.supplier?.suppliername == null + // ? null + // : () async { + // SuppEngineerWorkOrders suppEngineer = (await showModalBottomSheet( + // context: context, + // useSafeArea: true, + // isScrollControlled: true, + // backgroundColor: Colors.transparent, + // builder: (context) => AddSupplierEngineerBottomSheet(_subWorkOrders.supplier.id), + // )) as SuppEngineerWorkOrders; + // if (suppEngineer != null) { + // _subWorkOrders?.supplier?.suppPersons ??= []; + // _subWorkOrders?.supplier?.suppPersons?.add(SuppPersons.fromJson(suppEngineer.toJson())); + // engineer = suppEngineer; + // setState(() {}); + // } + // }), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + ATimePicker( + label: context.translation.startTime, + hint: context.translation.select, + withBorder: false, + icon: 'clock', + withIcon: true, + backgroundColor: AppColor.neutral100, + height: 70.toScreenHeight, + time: _startTime, + onTimePicker: (selectedTime) { + if (selectedTime != null) { + print('time selected $selectedTime'); + setState(() { + _startTime = selectedTime; + }); + } + }, + ).expanded, + 8.width, + ATimePicker( + label: context.translation.endTime, + hint: context.translation.select, + icon: 'clock', + withIcon: true, + backgroundColor: AppColor.neutral100, + withBorder: false, + height: 70.toScreenHeight, + time: _endTime, + onTimePicker: (selectedTime) { + if (selectedTime != null) { + setState(() { + _endTime = selectedTime; + }); + } + }, + ).expanded, + ], + ), + 8.height, + AppTextFormField( + labelText: context.translation.workingHours, + backgroundColor: AppColor.neutral80, + suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), + contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth), + initialValue: _serviceReport?.workingHours.toString(), + textAlign: TextAlign.center, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + + ], + ), + ), + ).toShadowContainer(context).paddingOnly(start: 16, end: 16, top: 12), + FooterActionButton.footerContainer( + child: AppFilledButton( + label:context.translation.addExternalActivity, // Use the dynamic label + buttonColor: AppColor.primary10, + onPressed: () async { + // Handle button press + + }, + ), + ), + ], + ), + ); + } + Widget repairLocationWidget(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + radioButtonWidget(label: context.translation.remotely, value: 1), + radioButtonWidget(label: context.translation.workshop, value: 2), + radioButtonWidget(label: context.translation.abroad, value: 3), + ], + ); + } + + Widget radioButtonWidget({@required String label, @required dynamic value}) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 20.toScreenWidth, + height: 40.toScreenHeight, + //TODO use the type required according data.. + child: Radio( + activeColor: AppColor.primary10, + value: value, + groupValue: _selectedValue, + onChanged: (int value) { + setState(() { + _selectedValue = value; + }); + }, + ), + ), + 8.width, + Text( + label, + style: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120), + ), + 13.width, + ], + ); + } +} diff --git a/lib/service_request_latest/views/forms/maintenance_request/components/internal_request.dart b/lib/service_request_latest/views/forms/maintenance_request/components/internal_request.dart new file mode 100644 index 00000000..82dde80e --- /dev/null +++ b/lib/service_request_latest/views/forms/maintenance_request/components/internal_request.dart @@ -0,0 +1,303 @@ + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/parts_provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_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/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/service_request/service_report.dart'; +import 'package:test_sa/models/service_request/service_request.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; +import 'package:test_sa/providers/work_order/reason_provider.dart'; +import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/views/widgets/date_and_time/time_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import '../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; +import '../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import '../../../../../models/lookup.dart'; +import '../../../../../new_views/common_widgets/app_text_form_field.dart'; +import '../../../../../new_views/common_widgets/single_item_drop_down_menu.dart'; + +class InternalMaintenanceRequest extends StatefulWidget { + static const String id = "/add-internal-activity"; + + const InternalMaintenanceRequest({Key key}) : super(key: key); + + @override + _InternalMaintenanceRequestState createState() => _InternalMaintenanceRequestState(); +} + +class _InternalMaintenanceRequestState extends State with TickerProviderStateMixin { + UserProvider _userProvider; + SettingProvider _settingProvider; + ServiceRequest _request; + ServiceRequestsProvider _serviceRequestsProvider; + ServiceStatusProvider _assetTypeProvider; + PartsProvider _partsProvider; + ServiceReport _serviceReport; + bool _isLoading = false; + TimeOfDay _startTime; + int _selectedValue = 1; + + TimeOfDay _endTime; + + final GlobalKey _formKey = GlobalKey(); + final TextEditingController _faultController = TextEditingController(); + final TextEditingController _workPreformedController = TextEditingController(); + final TextEditingController _partQtyController = TextEditingController(); + + @override + void initState() { + _serviceReport = ServiceReport( + // returnToService: DateTime.now(), + // //type: const Lookup(value: 2), + // device: widget.request.device, + sparePartsWorkOrders: [], + ); + + super.initState(); + if (context.mounted) { + _request = Provider.of(context, listen: false).currentSelectedRequest; + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).serviceRequestId = _request.id; + } + // _isLoading = true; + } + + Asset loanAvailabilityAsset; + + @override + void dispose() { + _faultController.dispose(); + _workPreformedController.dispose(); + _partQtyController.dispose(); + super.dispose(); + } + + void getRequestForWorkOrder() async { + _isLoading = true; + setState(() {}); + _serviceReport.callRequest = await _serviceRequestsProvider.getCallRequestForWorkOrder(callId: _request.id); + await _assetTypeProvider.getTypes(user: _userProvider.user, host: _settingProvider.host); + _serviceReport.assignedEmployee = _serviceReport.callRequest?.assignedEmployee; + _serviceReport.equipmentStatus = _serviceReport.callRequest?.defectType; + _serviceReport.serviceType = Lookup(id: 65, name: "Interval", value: 1); // default value in service type as in web + _isLoading = false; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + _userProvider = Provider.of(context); + _settingProvider = Provider.of(context); + _serviceRequestsProvider = Provider.of(context); + _assetTypeProvider = Provider.of(context); + _partsProvider = Provider.of(context); + if (_serviceReport.callRequest == null) { + getRequestForWorkOrder(); + } + _serviceReport.assetType = _assetTypeProvider.statuses?.firstWhere( + (element) => element.value == _serviceReport.callRequest?.assetType, + orElse: () => null, + ); + + return LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Stack( + children: [ + SingleChildScrollView( + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + 8.height, + SingleItemDropDownMenu( + context: context, + height: 70.toScreenHeight, + title: context.translation.activityStatus, + showShadow: false, + backgroundColor: AppColor.neutral100, + staticData: Provider.of(context).calls, + initialValue: _serviceReport?.calllastSituation, + onSelect: (status) { + _serviceReport.calllastSituation = status; + }, + ), + 8.height, + Row( + mainAxisSize: MainAxisSize.min, + children: [ + ATimePicker( + label: context.translation.startTime, + hint: context.translation.select, + withBorder: false, + icon: 'clock', + withIcon: true, + backgroundColor: AppColor.neutral100, + height: 70.toScreenHeight, + time: _startTime, + onTimePicker: (selectedTime) { + if (selectedTime != null) { + print('time selected $selectedTime'); + setState(() { + _startTime = selectedTime; + }); + } + }, + ).expanded, + 8.width, + ATimePicker( + label: context.translation.endTime, + hint: context.translation.select, + icon: 'clock', + withIcon: true, + backgroundColor: AppColor.neutral100, + withBorder: false, + height: 70.toScreenHeight, + time: _endTime, + onTimePicker: (selectedTime) { + if (selectedTime != null) { + setState(() { + _endTime = selectedTime; + }); + } + }, + ).expanded, + ], + ), + 8.height, + AppTextFormField( + labelText: context.translation.workingHours, + backgroundColor: AppColor.neutral80, + suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), + contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth), + initialValue: _serviceReport?.workingHours.toString(), + textAlign: TextAlign.center, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + + //TODO need to be selected when submit... + // SingleItemDropDownMenu( + // context: context, + // title: context.translation.serviceType, + // initialValue: _serviceReport.serviceType, + // onSelect: (value) { + // _serviceReport.serviceType = value; + // }, + // ), + //Provider.of(context) + + 8.height, + AppTextFormField( + labelText: context.translation.travelingHours, + backgroundColor: AppColor.neutral100, + suffixIcon: "clock".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null).paddingOnly(end: 16), + initialValue: _serviceReport?.travelingHours?.toString(), + textInputType: TextInputType.number, + contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth), + showShadow: false, + onSaved: (value) { + _serviceReport.travelingHours = double.tryParse(value) ?? 0.0; + }, + ), + 16.height, + context.translation.repairLocation.bodyText(context).custom(color: AppColor.black20, fontWeight: FontWeight.w500), + 8.height, + repairLocationWidget(context), + 16.height, + AppTextFormField( + labelText: context.translation.assignedEmployee, + backgroundColor: AppColor.neutral80, + contentPadding: EdgeInsets.symmetric(vertical: 18.toScreenHeight, horizontal: 16.toScreenWidth), + initialValue: _serviceReport?.workingHours.toString(), + textAlign: TextAlign.center, + showShadow: false, + enable: false, + style: Theme.of(context).textTheme.titleMedium, + ), + 8.height, + AppTextFormField( + initialValue: _serviceReport?.comment, + labelText: context.translation.technicalComment, + backgroundColor: AppColor.neutral100, + showShadow: false, + alignLabelWithHint: true, + textInputType: TextInputType.multiline, + onSaved: (value) { + _serviceReport.comment = value; + }, + ), + ], + ), + ), + ).toShadowContainer(context).paddingOnly(start: 16, end: 16, top: 12), + + FooterActionButton.footerContainer( + child: AppFilledButton( + label:context.translation.addInternalActivity, // Use the dynamic label + buttonColor: AppColor.primary10, + onPressed: () async { + // Handle button press + + }, + ), + ), + ], + ), + ); + } + Widget repairLocationWidget(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + radioButtonWidget(label: context.translation.remotely, value: 1), + radioButtonWidget(label: context.translation.workshop, value: 2), + radioButtonWidget(label: context.translation.abroad, value: 3), + ], + ); + } + + Widget radioButtonWidget({@required String label, @required dynamic value}) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 20.toScreenWidth, + height: 40.toScreenHeight, + //TODO use the type required according data.. + child: Radio( + activeColor: AppColor.primary10, + value: value, + groupValue: _selectedValue, + onChanged: (int value) { + setState(() { + _selectedValue = value; + }); + }, + ), + ), + 8.width, + Text( + label, + style: AppTextStyles.tinyFont.copyWith(color: AppColor.neutral120), + ), + 13.width, + ], + ); + } +} diff --git a/lib/service_request_latest/views/forms/maintenance_request/maintenance_request_main.dart b/lib/service_request_latest/views/forms/maintenance_request/maintenance_request_main.dart new file mode 100644 index 00000000..dbddb731 --- /dev/null +++ b/lib/service_request_latest/views/forms/maintenance_request/maintenance_request_main.dart @@ -0,0 +1,94 @@ +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/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/service_request_latest/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/service_request_latest/views/forms/maintenance_request/components/external_request.dart'; +import 'package:test_sa/service_request_latest/views/forms/maintenance_request/components/internal_request.dart'; + +class MaintenanceRequestForm extends StatefulWidget { + const MaintenanceRequestForm({Key key}) : super(key: key); + + @override + _MaintenanceRequestFormState createState() => _MaintenanceRequestFormState(); +} + +class _MaintenanceRequestFormState extends State with SingleTickerProviderStateMixin { + TabController _tabController; + int initialIndex = 0; + + @override + void initState() { + super.initState(); + // _tabController = TabController(length: 2, vsync: this); + // print('tab controller i got is ${_tabController.length}'); + // _tabController.addListener(() { + // print('add listner called..'); + // setState(() { + // print('index i got is ${_tabController.index}'); + // if (_tabController.index == 0) { + // _buttonLabel = 'abc'; + // } else if (_tabController.index == 1) { + // _buttonLabel = 'def'; + // } + // }); + // }); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColor.neutral100, + appBar: DefaultAppBar(title: context.translation.maintenanceRequest), + body: DefaultTabController( + length: 2, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: EdgeInsets.only(left: 16.toScreenWidth, right: 16.toScreenWidth, top: 12.toScreenHeight), + decoration: BoxDecoration( + color: context.isDark ? AppColor.neutral50 : AppColor.white10, + borderRadius: BorderRadius.circular(10), + ), + child: TabBar( + padding: EdgeInsets.symmetric(vertical: 4.toScreenHeight, horizontal: 4.toScreenWidth), + labelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, + unselectedLabelColor: context.isDark ? AppColor.neutral30 : AppColor.black20, + unselectedLabelStyle: AppTextStyles.bodyText, + labelStyle: AppTextStyles.bodyText, + indicatorPadding: EdgeInsets.zero, + indicator: BoxDecoration( + color: context.isDark ? AppColor.neutral60 : AppColor.neutral110, + borderRadius: BorderRadius.circular(7), + ), + tabs: [ + Tab(text: context.translation.internal, height: 57.toScreenHeight), + Tab(text: context.translation.external, height: 57.toScreenHeight), + ], + ), + ), + // 12.height, + const TabBarView( + children: [ + InternalMaintenanceRequest(), + ExternalMaintenanceRequest(), + ], + ).expanded, + + ], + ), + ), + ); + } +} diff --git a/lib/service_request_latest/views/forms/spare_part/spare_part_request.dart b/lib/service_request_latest/views/forms/spare_part/spare_part_request.dart new file mode 100644 index 00000000..90ae345f --- /dev/null +++ b/lib/service_request_latest/views/forms/spare_part/spare_part_request.dart @@ -0,0 +1,244 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/parts_provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_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/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/service_request/service_report.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/single_item_drop_down_menu.dart'; +import 'package:test_sa/providers/loading_list_notifier.dart'; +import 'package:test_sa/providers/work_order/reason_provider.dart'; +import 'package:test_sa/service_request_latest/views/components/bottom_sheets/service_request_bottomsheet.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import '../../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; +import '../../../../../../controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import '../../../../../../models/lookup.dart'; +import '../../../../../../models/service_request/spare_parts.dart'; +import '../../../../../../new_views/common_widgets/app_text_form_field.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; +import '../../../../controllers/validator/validator.dart'; + +class SparePartRequest extends StatefulWidget { + static const String id = "/spare-part-request"; + + const SparePartRequest({Key key}) : super(key: key); + + @override + _SparePartRequestState createState() => _SparePartRequestState(); +} + +class _SparePartRequestState extends State with TickerProviderStateMixin { + UserProvider _userProvider; + SettingProvider _settingProvider; + ServiceRequestsProvider _serviceRequestsProvider; + ServiceStatusProvider _assetTypeProvider; + PartsProvider _partsProvider; + ServiceReport _serviceReport; + bool _isLoading = false; + List _spareParts = []; + + final List _files = []; + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + final TextEditingController _partQtyController = TextEditingController(); + final TextEditingController _oracleNoController = TextEditingController(); + + @override + void initState() { + _serviceReport = ServiceReport( + // returnToService: DateTime.now(), + // //type: const Lookup(value: 2), + // device: widget.request.device, + sparePartsWorkOrders: [], + ); + super.initState(); + if (context.mounted) { + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).serviceRequestId = serviceRequestsProvider.currentSelectedRequest.id; + } + // _isLoading = true; + } + + Asset loanAvailabilityAsset; + + @override + void dispose() { + _partQtyController.dispose(); + _oracleNoController.dispose(); + super.dispose(); + } + + void getRequestForWorkOrder() async { + _isLoading = true; + setState(() {}); + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + _serviceReport.callRequest = await _serviceRequestsProvider.getCallRequestForWorkOrder(callId: serviceRequestsProvider.currentSelectedRequest.id); + await _assetTypeProvider.getTypes(user: _userProvider.user, host: _settingProvider.host); + _serviceReport.assignedEmployee = _serviceReport.callRequest?.assignedEmployee; + _serviceReport.equipmentStatus = _serviceReport.callRequest?.defectType; + _serviceReport.serviceType = Lookup(id: 65, name: "Interval", value: 1); // default value in service type as in web + _spareParts = await _partsProvider.getPartsList(assetId: serviceRequestsProvider.currentSelectedRequest.deviceId); + _isLoading = false; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + _userProvider = Provider.of(context); + _settingProvider = Provider.of(context); + _serviceRequestsProvider = Provider.of(context); + _assetTypeProvider = Provider.of(context); + _partsProvider = Provider.of(context); + if (_serviceReport.callRequest == null) { + getRequestForWorkOrder(); + } + _serviceReport.assetType = _assetTypeProvider.statuses?.firstWhere( + (element) => element.value == _serviceReport.callRequest?.assetType, + orElse: () => null, + ); + + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: context.translation.sparePartRequest), + body: Consumer(builder: (context, serviceRequestProvider, child) { + return SafeArea( + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Card( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + context.translation.sparePartDetails.heading5(context), + 12.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.partNo, + staticData: _spareParts, + height: 80.toScreenHeight, + showShadow: false, + initialValue: serviceRequestProvider.initialSelectedSparePart.sparePart, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + onSelect: (part) { + print('part i got is ${part.id}'); + serviceRequestProvider.initialSelectedSparePart = SparePartsWorkOrders(id: 0, sparePart: part, qty: 0); + }, + ), + 15.height, + AppTextFormField( + controller: _partQtyController, + labelText: context.translation.quantity, + textInputType: TextInputType.number, + contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 20.toScreenHeight), + showWithoutDecoration: true, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + enable: serviceRequestProvider.initialSelectedSparePart != null && serviceRequestProvider.initialSelectedSparePart.sparePart?.id != null, + validator: (value) => value == null || value.isEmpty + ? context.translation.requiredField + : Validator.isNumeric(value) + ? null + : context.translation.onlyNumbers, + onSaved: (text) { + serviceRequestProvider.initialSelectedSparePart.qty = num.tryParse(text ?? ""); + }, + ), + 15.height, + AppTextFormField( + controller: _oracleNoController, + labelText: context.translation.oracleNo, + textInputType: TextInputType.number, + contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 20.toScreenHeight), + showWithoutDecoration: true, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + enable: serviceRequestProvider.initialSelectedSparePart != null && serviceRequestProvider.initialSelectedSparePart.sparePart?.id != null, + validator: (value) => value == null || value.isEmpty + ? context.translation.requiredField + : Validator.isNumeric(value) + ? null + : context.translation.onlyNumbers, + onSaved: (text) { + //TODO set the values... + // serviceRequestProvider.initialSelectedSparePart. = num.tryParse(text ?? ""); + }, + ), + 15.height, + AppTextFormField( + initialValue: _serviceReport?.comment, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + labelText: context.translation.description, + alignLabelWithHint: true, + showWithoutDecoration: true, + textInputType: TextInputType.multiline, + onSaved: (value) { + _serviceReport.comment = value; + }, + ), + 15.height, + MultiFilesPicker(label: context.translation.attachQuotation, files: _files), + ], + ).paddingAll(16), + ), + 8.height, + ], + ), + ).expanded, + AppFilledButton( + label: context.translation.addSparePartActivity, + buttonColor: AppColor.green70, + onPressed: () async { + ServiceRequestBottomSheet.actionBottomSheet(context: context, title: context.translation.addSparePartActionHeading); + // bool shouldReloadData = (await showModalBottomSheet( + // context: context, + // useSafeArea: true, + // isScrollControlled: true, + // backgroundColor: Colors.transparent, + // builder: (context) => ActionBottomSheet(title: context.translation.addSparePartActionHeading), + // )) as bool; + // if (shouldReloadData ?? false) {} + //TODO write add sparepart logic + + // if ((!_formKey.currentState.validate()) || (!(await _serviceReport.validate(context)))) { + // setState(() {}); + // return; + // } + // _formKey.currentState.save(); + // _serviceReport.attachmentsWorkOrder ??= []; + // if (_files.isEmpty) _serviceReport.attachmentsWorkOrder = []; + // for (var file in _files) { + // _serviceReport.attachmentsWorkOrder.add(Attachment(id: 0, name: "${file.path.split("/").last}|${base64Encode(file.readAsBytesSync())}")); + // } + // final user = Provider.of(context, listen: false).user; + // await _serviceRequestsProvider.createServiceReport(context, report: _serviceReport, request: serviceRequestProvider.serviceRequest, user: user); + }, + ), + ], + ).paddingAll(16), + ), + ), + ); + }), + ); + } +} diff --git a/lib/service_request_latest/views/forms/work_order/components/asset_conditon_view.dart b/lib/service_request_latest/views/forms/work_order/components/asset_conditon_view.dart new file mode 100644 index 00000000..1b881fa1 --- /dev/null +++ b/lib/service_request_latest/views/forms/work_order/components/asset_conditon_view.dart @@ -0,0 +1,263 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/parts_provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_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/status_drop_down/report/service_report_last_calls_provider.dart'; +import 'package:test_sa/controllers/providers/api/status_drop_down/report/service_types_provider.dart'; +import 'package:test_sa/controllers/providers/api/user_provider.dart'; +import 'package:test_sa/controllers/validator/validator.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/models/device/asset.dart'; +import 'package:test_sa/models/lookup.dart'; +import 'package:test_sa/models/service_request/search_work_order.dart'; +import 'package:test_sa/models/service_request/service_report.dart'; +import 'package:test_sa/models/service_request/spare_parts.dart'; +import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart'; +import 'package:test_sa/models/service_request/supplier_details.dart'; +import 'package:test_sa/models/service_request/wo_call_request.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.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/service_request_providers/equipment_status_provider.dart'; +import 'package:test_sa/providers/work_order/reason_provider.dart'; +import 'package:test_sa/views/widgets/loaders/app_loading.dart'; + + +class AssetConditionView extends StatefulWidget { + static const id = "/CreateSubWorkOrder"; + final SearchWorkOrder workOrder; + + const AssetConditionView({this.workOrder, Key key}) : super(key: key); + + @override + State createState() => _AssetConditionViewState(); +} + +class _AssetConditionViewState extends State { + final GlobalKey _formKey = GlobalKey(); + SearchWorkOrder _subWorkOrders; + ServiceReport _serviceReport; + PartsProvider _partsProvider; + List _spareParts = []; + bool _isLoading = false; + bool _showVendorFields = false; + SuppEngineerWorkOrders engineer; + SupplierDetails initialSupplier; + final TextEditingController _workPreformedController = TextEditingController(); + final TextEditingController _partQtyController = TextEditingController(); + + @override + void initState() { + _subWorkOrders = SearchWorkOrder( + assignedEmployee: widget?.workOrder?.callRequest?.assignedEmployee, + callRequest: CallRequest(id: widget?.workOrder?.callRequest?.id), + currentSituation: null, + supplier: null, + // parentWOId: widget.workOrder.id, + ); + getData(); + _serviceReport = ServiceReport(); + // _isLoading = true; + super.initState(); + // if (context.mounted) { + // Provider.of(context, listen: false).reset(); + // Provider.of(context, listen: false).reset(); + // Provider.of(context, listen: false).serviceRequestId = widget.workOrder.callRequest.id.toString(); + // } + } + + ServiceStatusProvider assetTypesProvider; + CallRequest _callRequestForWorkOrder; + + void getData() async { + ReasonProvider reasonProvider = Provider.of(context,listen: false); + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context,listen: false); + _spareParts = await Provider.of(context,listen: false).getPartsList(assetId: serviceRequestsProvider.currentSelectedRequest.deviceId); + + // _serviceReport = serviceRequestsProvider.currentSelectedRequest; + // Provider.of(context).getDate(); + // Provider.of(context).getDate(); + reasonProvider.serviceRequestId = serviceRequestsProvider.currentSelectedRequest.id; + reasonProvider.getDate(); + // Provider.of(context).getDate(); + // Provider.of(context).getDate(); + } + Future getAssetType() async { + Provider.of(context, listen: false).reset(); + final serviceRequestProvider = Provider.of(context); + Provider.of(context, listen: false).reset(); + assetTypesProvider = Provider.of(context, listen: false); + _callRequestForWorkOrder = await serviceRequestProvider.getCallRequestForWorkOrder(callId: widget.workOrder?.callRequest?.id?.toString()); + if (_subWorkOrders?.parentWOId != null) { + final subWoDetails = await serviceRequestProvider.getSubWorkOrderDetails(parentId: _subWorkOrders?.parentWOId.toString()); + _subWorkOrders.copyDetails(subWoDetails); + _serviceReport.equipmentStatus = subWoDetails.equipmentStatus; + _serviceReport.reason = subWoDetails.reason; + initialSupplier = subWoDetails.supplier; + _serviceReport.faultDescription = subWoDetails.faultDescription; + _subWorkOrders.visitDate = subWoDetails.visitDate; + _subWorkOrders.sparePartsWorkOrders = subWoDetails.sparePartsWorkOrders; + } + await assetTypesProvider.getTypes(); + _subWorkOrders?.assetType = assetTypesProvider.statuses?.firstWhere( + (element) => element.value == _callRequestForWorkOrder?.assetType, + orElse: () => null, + ); + if (checkVendorFieldsVisibility(_subWorkOrders.calllastSituation)) { + if (_subWorkOrders.suppEngineerWorkOrders?.isNotEmpty ?? false) { + engineer = _subWorkOrders.suppEngineerWorkOrders?.last; + engineer?.id = engineer?.supplierContactId; + } + _subWorkOrders.supplier ??= SupplierDetails(id: _subWorkOrders?.supplier?.id); + } + _spareParts = await _partsProvider.getPartsList(assetId: widget.workOrder?.callRequest?.asset?.id); + setState(() { + _isLoading = false; + }); + } + + Asset loanAvailabilityAsset; + + @override + void dispose() { + _workPreformedController?.dispose(); + _partQtyController?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final user = Provider.of(context).user; + // final isCurrentUserIsAssistantEmp = (user.userID != widget.workOrder.assignedEmployee?.id); + // if (isCurrentUserIsAssistantEmp) { + // // _subWorkOrders.assistantEmployees = [widget.workOrder.assistantEmployees?.first?.copyWith(id: 0)]; + // _subWorkOrders.assistantEmployees = [AssistantEmployees(id: 0, user: AssignedEmployee(id: user.userID, name: user.username))]; + // } else {} + // if (_callRequestForWorkOrder == null) { + // _partsProvider = Provider.of(context); + // // getAssetType(); + // } + + bool disablePart = _subWorkOrders.calllastSituation?.value == 12; + + return Consumer( + builder: (context, serviceRequestProvider,child) { + return SafeArea( + child: _isLoading + ? const ALoading() + : Container( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth), + child: Column( + children: [ + SingleChildScrollView( + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SingleItemDropDownMenu( + context: context, + title: context.translation.reason, + initialValue: _subWorkOrders.reason, + onSelect: (value) { + if (value != null) { + _subWorkOrders.reason = value; + } + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.equipmentStatus, + initialValue: _subWorkOrders.equipmentStatus, + onSelect: (value) { + if (value != null) { + _subWorkOrders.equipmentStatus = value; + } + }, + ), + 8.height, + SingleItemDropDownMenu( + context: context, + title: context.translation.partNo, + staticData: _spareParts, + showShadow: true, + initialValue: serviceRequestProvider.initialSelectedSparePart.sparePart, + backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.white10, + onSelect: (part) { + serviceRequestProvider.initialSelectedSparePart = SparePartsWorkOrders(id: 0, sparePart: part, qty: 0); + }, + ), + // AppTextFormField( + // controller: _partQtyController, + // labelText: context.translation.quantity, + // textInputType: TextInputType.number, + // contentPadding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 20.toScreenHeight), + // showWithoutDecoration: true, + // backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral90, + // enable: serviceRequestProvider.initialSelectedSparePart != null && serviceRequestProvider.initialSelectedSparePart.sparePart?.id != null, + // validator: (value) => value == null || value.isEmpty + // ? context.translation.requiredField + // : Validator.isNumeric(value) + // ? null + // : context.translation.onlyNumbers, + // onSaved: (text) { + // serviceRequestProvider.initialSelectedSparePart.qty = num.tryParse(text ?? ""); + // }, + // ), + 15.height, + ], + ), + ),),]), + )); + } + ); + + // ), + // ); + } + + bool checkVendorFieldsVisibility(Lookup callsLastSituation) { + bool result = (initialSupplier?.suppliername?.isNotEmpty ?? false) || + (callsLastSituation?.name?.toLowerCase()?.contains("under repair-vendor") ?? false) || + (callsLastSituation?.name?.toLowerCase()?.contains("waiting for vendor") ?? false); + setState(() { + _showVendorFields = result; + }); + return result; + } + + Future validate() async { + if (_subWorkOrders.reason == null) { + Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.reason}"); + return false; + } else if (_subWorkOrders.equipmentStatus == null) { + Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.equipmentStatus}"); + return false; + } else if (_subWorkOrders.calllastSituation == null) { + Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.callLastSituation}"); + return false; + } else if (_showVendorFields && _subWorkOrders.suppEngineerWorkOrders == null) { + Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.supplierEngineer}"); + return false; + } else if (_showVendorFields && (_subWorkOrders.supplier.suppliername == null || _subWorkOrders.supplier.suppliername.isEmpty)) { + Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.supplier}"); + return false; + } else if (_subWorkOrders.calllastSituation.value == 12 && (_subWorkOrders.sparePartsWorkOrders == null || _subWorkOrders.sparePartsWorkOrders.isEmpty)) { + Fluttertoast.showToast(msg: "${context.translation.youHaveToSelect} ${context.translation.partNo}"); + return false; + } else if (_subWorkOrders?.timer?.startAt == null) { + await Fluttertoast.showToast(msg: "Working Hours Required"); + return false; + } else if (_subWorkOrders?.timer?.endAt == null) { + await Fluttertoast.showToast(msg: "Please Stop The Timer"); + return false; + } + return true; + } +} diff --git a/lib/service_request_latest/views/forms/work_order/components/attachments_view.dart b/lib/service_request_latest/views/forms/work_order/components/attachments_view.dart new file mode 100644 index 00000000..5a07b5d1 --- /dev/null +++ b/lib/service_request_latest/views/forms/work_order/components/attachments_view.dart @@ -0,0 +1,39 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_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/views/widgets/images/multi_image_picker.dart'; + +class AttachmentView extends StatelessWidget { + const AttachmentView({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + //TODO user the same form key everywhere.... + final GlobalKey _formKey = GlobalKey(); + final List _files = []; + return Consumer(builder: (context, serviceRequestProvider, child) { + serviceRequestProvider.currentSelectedRequest.visitDate = ''; + return Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + children: [ + MultiFilesPicker( + label: context.translation.attachImage, + buttonHeight: 108.toScreenHeight, + buttonIcon: 'image_icon'?.toSvgAsset(), + files: _files, + onlyImages: true, + ), + 16.height, + ], + ), + ), + ); + }); + } +} diff --git a/lib/service_request_latest/views/forms/work_order/components/time_duration_view.dart b/lib/service_request_latest/views/forms/work_order/components/time_duration_view.dart new file mode 100644 index 00000000..7f81c0cc --- /dev/null +++ b/lib/service_request_latest/views/forms/work_order/components/time_duration_view.dart @@ -0,0 +1,120 @@ + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/new_views/app_style/app_color.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/timer/app_timer.dart'; + +class TimeDurationView extends StatelessWidget { + const TimeDurationView({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + //TODO user the same form key everywhere.... + final GlobalKey _formKey = GlobalKey(); + return Consumer( + builder: (context, serviceRequestProvider,child) { + serviceRequestProvider.currentSelectedRequest.visitDate = ''; + return Form( + key: _formKey, + child: SingleChildScrollView( + child: Column( + children: [ + ADatePicker( + label: context.translation.visitDate, + hideShadow: true, + withIcon: false, + hint: context.translation.select, + height: 70.toScreenHeight, + date: DateTime.tryParse(serviceRequestProvider.currentSelectedRequest.visitDate ?? ""), + formatDateWithTime: true, + onDatePicker: (selectedDate) { + if (selectedDate != null) { + showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ).then((selectedTime) { + // Handle the selected date and time here. + if (selectedTime != null) { + DateTime selectedDateTime = DateTime( + selectedDate.year, + selectedDate.month, + selectedDate.day, + selectedTime.hour, + selectedTime.minute, + ); + if (selectedDateTime != null) { + serviceRequestProvider.currentSelectedRequest.visitDate = selectedDateTime?.toIso8601String(); + } + } + }); + } + }, + ), + 8.height, + ATimePicker( + label: context.translation.startTime, + hint: context.translation.select, + withIcon: false, + withBorder: false, + height: 70.toScreenHeight, + time: serviceRequestProvider.selectedTime, + onTimePicker: (selectedTime) { + if (selectedTime != null) { + print('time selected $selectedTime'); + serviceRequestProvider.selectedTime = selectedTime; + } + }, + ), + 8.height, + ATimePicker( + label: context.translation.endTime, + hint: context.translation.select, + withIcon: false, + withBorder: false, + height: 70.toScreenHeight, + time: serviceRequestProvider.selectedTime, + onTimePicker: (selectedTime) { + if (selectedTime != null) { + print('time selected $selectedTime'); + serviceRequestProvider.selectedTime = selectedTime; + } + }, + ), + 8.height, + SizedBox( + width: double.infinity, + height: 70.toScreenHeight, + child: AppTimer( + label: context.translation.workingHours, + timer: TimerModel(), + decoration: BoxDecoration( + color: AppColor.background(context), + borderRadius: BorderRadius.circular(10), + // boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + ), + // enabled: serviceRequestProvider.currentSelectedRequest.date == null, + enabled: true, + onChange: (timer) async { + print('timer i got is ${timer.toString()}'); + return true; + }, + ), + + ), + 16.height, + ], + ), + ), + ); + } + ); + } +} diff --git a/lib/service_request_latest/views/forms/work_order/work_order_form_view.dart b/lib/service_request_latest/views/forms/work_order/work_order_form_view.dart new file mode 100644 index 00000000..20f4a53a --- /dev/null +++ b/lib/service_request_latest/views/forms/work_order/work_order_form_view.dart @@ -0,0 +1,242 @@ +import 'package:flutter/material.dart'; +import 'package:test_sa/common_widgets/stapper_widget/components/base_step.dart'; +import 'package:test_sa/common_widgets/stapper_widget/components/custom_line.dart'; +import 'package:test_sa/common_widgets/stapper_widget/custom_stepper.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_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/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/service_request_latest/views/forms/work_order/components/asset_conditon_view.dart'; +import 'package:test_sa/service_request_latest/views/forms/work_order/components/attachments_view.dart'; +import 'package:test_sa/service_request_latest/views/forms/work_order/components/time_duration_view.dart'; + +class WorkOrderFormView extends StatefulWidget { + + const WorkOrderFormView({Key key}) : super(key: key); + + @override + _WorkOrderFormViewState createState() => _WorkOrderFormViewState(); +} + +class _WorkOrderFormViewState extends State { + int currentStep = 0; + int activeStep = 0; + int reachedStep = 0; + int upperBound = 2; + final formKey = GlobalKey(); + + @override + void initState() { + WidgetsBinding.instance.addPostFrameCallback((_) { + getInitialData(); + }); + super.initState(); + } + + Future getInitialData() async { + // ListingVm listingVm = Provider.of(context, listen: false); + // listingVm.listingPropertyType = widget.arguments['listingType']; + // if (widget.arguments['formType'] == AppConstants.addListing) { + // listingVm.landLordModel = LandLordModel(); + // listingVm.listing['propertyType'] = widget.arguments['listingType']; + // if (listingVm.listing['propertyType'] == AppConstants.sell) { + // listingVm.listingParameter = 'sellParameter'; + // listingVm.listing[listingVm.listingParameter] = + // SellParameter().toJson(); + // listingVm.listing[listingVm.listingParameter]?['ownerDocs'] = []; + // } + // if (listingVm.listing['propertyType'] == AppConstants.rent) { + // listingVm.listingParameter = 'rentParameter'; + // listingVm.listing[listingVm.listingParameter] = + // RentParameter().toJson(); + // listingVm.listing[listingVm.listingParameter]?['ownerDocs'] = []; + // } + // } else if (widget.arguments['formType'] == AppConstants.editListing) { + // if (listingVm.listing['propertyType'] == AppConstants.sell) { + // listingVm.listingParameter = 'sellParameter'; + // } + // if (listingVm.listing['propertyType'] == AppConstants.rent) { + // listingVm.listingParameter = 'rentParameter'; + // } + // if (widget.arguments['isDuplicate'] == true) { + // FormUtils.setDuplicateValues( + // listingVm: listingVm, listType: widget.arguments['listingType']); + // } + // listingVm.formLocationController.clear(); + // listingVm.formCommunityInitialValue = + // await FormUtils.setLocation(listingVm.listing, context); + // listingVm.formLocationController.text = + // listingVm.formCommunityInitialValue ?? ''; + // + // listingVm.formAvailabilityDate = + // listingVm.listing[listingVm.listingParameter]['availabilityDate'] ?? + // ''; + // listingVm.formBuildYearDate = + // listingVm.listing[listingVm.listingParameter]['buildYear'] ?? ''; + // + // listingVm.listing['photos'] ??= []; + // listingVm.listing[listingVm.listingParameter]['ownerDocs'] ??= []; + // } + // GeneralUtil.initilizePortalsSwitch(listingVm: listingVm); + // listingVm.getTenantExtent(); + // await listingVm.getRegion(); + // if (listingVm.listing[listingVm.listingParameter] + // ['propertyFinderLocation'] != + // null) { + // await listingVm.getPropertyFinderLocationList( + // searchQuery: listingVm.listing[listingVm.listingParameter] + // ['propertyFinderLocation']); + // } + // await listingVm.getWaterMarkImage(); + // await listingVm.getDeveloper(); + // await GeneralUtil.loadPortalsLocationsData(listingVm); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColor.neutral100, + appBar: DefaultAppBar(title: context.translation.createWorkOrder), + body: Column( + children: [ + 16.height, + CustomStepper( + activeStep: activeStep, + lineStyle: LineStyle( + activeLineColor: AppColor.primary10, + finishedLineColor: AppColor.primary10, + defaultLineColor: AppColor.white40, + lineThickness: 1, + lineLength: 93.toScreenWidth, + lineType: LineType.normal, + ), + internalPadding: 2.toScreenWidth, + steps: [ + StepModel(customStep: customStepWidget(index: 0, stepIndex: 1), customTitle: customStepLabel(index: 1, label: context.translation.timeAndDuration)), + StepModel(customStep: customStepWidget(index: 1, stepIndex: 2), customTitle: customStepLabel(index: 1, label: context.translation.assetsCondition)), + StepModel(customStep: customStepWidget(index: 2, stepIndex: 3), customTitle: customStepLabel(index: 1, label: context.translation.attachmentsAcknowledge)), + ], + onStepReached: (index) => setState(() => activeStep = index), + ), + Expanded( + child: Padding( + padding: EdgeInsetsDirectional.symmetric(horizontal: 16.toScreenWidth, vertical: 25.toScreenHeight), + child: getStepWidget(), + )), + bottomContainerWidget(), + ], + ), + ); + } + + Widget bottomContainerWidget() { + return Container( + padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth,vertical: 16.toScreenHeight), + color: AppColor.white10, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + AppFilledButton( + label: context.translation.cancel, + loading: false, + buttonColor: AppColor.white60, + textColor: AppColor.black10, + onPressed: () async { + Navigator.pop(context); + // await snapshot.updateRequest(user: userProvider.user, request: serviceRequestProvider.serviceRequest); + // Navigator.pop(context, true); + }, + ).expanded, + 12.width, + AppFilledButton( + label: context.translation.next, + buttonColor: AppColor.primary10, + loading: false, + onPressed: () { + _incrementActiveStep(); + //TODO move to next step.. + }, + ).expanded, + ], + )); + } + + void _incrementActiveStep() { + setState(() { + ++activeStep; + if (reachedStep < activeStep) { + reachedStep = activeStep; + } + }); + } + + Future _navigateNext(ServiceRequestsProvider serviceRequestsProvider) async { + if (activeStep < upperBound) { + switch (activeStep) { + case 0: + // await _navigateNextStep(listingVm); + break; + case 1: + break; + case 2: + _incrementActiveStep(); + break; + } + } + } + +// Your onPressed code + + Widget customStepWidget({@required int index, @required int stepIndex}) { + return CircleAvatar( + backgroundColor: activeStep >= index ? AppColor.primary10 : AppColor.background(context), + child: activeStep > index + ? Icon( + Icons.done, + color: AppColor.white10, + size: 26.toScreenHeight, + ) + : activeStep == index + ? Text( + '0$stepIndex', + style: const TextStyle(fontWeight: FontWeight.w500, color: AppColor.white10), + textAlign: TextAlign.center, + ) + : Text( + '0$stepIndex', + style: const TextStyle(color: AppColor.black20), + ), + ); + } + + Widget customStepLabel({@required String label, @required int index}) { + return Column( + children: [ + Text( + label, + textAlign: TextAlign.center, + style: AppTextStyles.bodyText2.copyWith(color: AppColor.black20), + ), + ], + ); + } + + /// Returns the previous button. + + Widget getStepWidget() { + switch (activeStep) { + case 0: + return const TimeDurationView(); + case 1: + return const AssetConditionView(); + case 2: + return const AttachmentView(); + default: + return const SizedBox(); + } + } +} diff --git a/lib/service_request_latest/views/nurse/create_new_request_view.dart b/lib/service_request_latest/views/nurse/create_new_request_view.dart new file mode 100644 index 00000000..26e3a6fa --- /dev/null +++ b/lib/service_request_latest/views/nurse/create_new_request_view.dart @@ -0,0 +1,215 @@ + +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/devices_provider.dart'; +import 'package:test_sa/controllers/providers/api/service_requests_provider.dart'; +import 'package:test_sa/controllers/validator/validator.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/device/asset.dart'; +import 'package:test_sa/models/device/asset_search.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/providers/work_order/reason_provider.dart'; +import 'package:test_sa/service_request_latest/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/loaders/loading_manager.dart'; +import 'package:test_sa/views/widgets/qr/scan_qr.dart'; +import '../../../../../../controllers/providers/api/status_drop_down/report/service_report_last_calls_provider.dart'; +import '../../../../../../new_views/common_widgets/default_app_bar.dart'; +class CreateNewRequest extends StatefulWidget { + static const String id = "/create-new-request"; + + const CreateNewRequest({Key key}) : super(key: key); + + @override + _CreateNewRequestState createState() => _CreateNewRequestState(); +} + +class _CreateNewRequestState extends State with TickerProviderStateMixin { + + AssetProvider _devicesProvider; + bool _isLoading = false; + int _selectedEStatus = 1; + bool _isHighPrority = false; + String text; + + final GlobalKey _formKey = GlobalKey(); + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + void initState() { + super.initState(); + if (context.mounted) { + ServiceRequestsProvider serviceRequestsProvider = Provider.of(context, listen: false); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).serviceRequestId = serviceRequestsProvider.currentSelectedRequest.id; + } + // _isLoading = true; + } + _getDevice(String result, {bool isQr = false}) async { + if (result == null) return; + _devicesProvider.reset(); + await _devicesProvider.getAssets( + search: AssetSearch(assetNo: result, assetSerialNumber: ""), + isQr: isQr, + ); + } + Asset loanAvailabilityAsset; + + + @override + Widget build(BuildContext context) { + + final List _files = []; + + return Scaffold( + key: _scaffoldKey, + appBar: DefaultAppBar(title: context.translation.createNewRequest), + body: Consumer(builder: (context, serviceRequestProvider, child) { + return SafeArea( + child: LoadingManager( + isLoading: _isLoading, + isFailedLoading: false, + stateCode: 200, + onRefresh: () async {}, + child: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + child: Card( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppFilledButton( + label: context.translation.scanOrPickAsset, + showIcon: true, + icon: "scan_asset".toSvgAsset(height: 20, fit: BoxFit.contain, color: Theme.of(context).scaffoldBackgroundColor), + buttonColor: AppColor.neutral50, + onPressed: () async { + String result = await Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const ScanQr()), + ) as String; + _getDevice(result, isQr: true); + } , + ), + 21.height, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + context.translation.highPriority.bodyText(context).custom(color: AppColor.black20), + CupertinoSwitch( + value: _isHighPrority, + + onChanged: (value) { + setState(() { + // listingVm.listing[listingVm.listingParameter]['bayut'] = value; + _isHighPrority = value; + }); + }, + thumbColor: AppColor.red70, + activeColor: AppColor.red30.withOpacity(0.4), + + ), + ], + ), + 20.height, + context.translation.equipmentStatus.bodyText(context).custom(color: AppColor.black20), + 12.height, + assetStatusWidget(context), + 8.height, + + 23.height, + MultiFilesPicker(label: context.translation.attachImage, + files: _files, + buttonColor: AppColor.primary10, + onlyImages: true, + buttonIcon: 'image-plus'?.toSvgAsset(color: AppColor.primary10), + ), + AppTextFormField( + labelText: "Type any comment", + backgroundColor: AppColor.neutral30, + alignLabelWithHint: true, + showShadow: false, + validator: (value) => Validator.hasValue(value) ? null : context.translation.requiredField, + textInputType: TextInputType.multiline, + suffixIcon: "comment_send".toSvgAsset().paddingOnly(end: 16).onPress(() { + if (_formKey.currentState.validate()) { + _formKey.currentState.save(); + // final comment = Comment(id: 0, callRequestId: num.tryParse(widget.requestId ?? ""), comment: text); + // commentsProvider.addComment(context, comment: comment); + } + }), + onSaved: (value) { + text = value; + }, + ), + + + ], + ).paddingOnly(start:13,end: 13,top: 15,bottom: 16), + ).paddingAll(16), + ).expanded, + FooterActionButton.footerContainer( + child: AppFilledButton( + label: context.translation.submitRequest, + buttonColor: AppColor.primary10, + onPressed: (){}, + ), + ), + ], + ), + ), + ), + ); + }), + ); + } + Widget assetStatusWidget(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + radioButtonWidget(label: context.translation.up_and_running, value: 1), + radioButtonWidget(label: context.translation.partially_down, value: 2), + radioButtonWidget(label: context.translation.fully_down, value: 3), + ], + ); + } + + Widget radioButtonWidget({@required String label, @required dynamic value}) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 20.toScreenWidth, + height: 40.toScreenHeight, + //TODO use the type required according data.. + child: Radio( + activeColor: AppColor.primary10, + value: value, + groupValue: _selectedEStatus, + onChanged: (int value) { + setState(() { + _selectedEStatus = value; + }); + }, + ), + ), + 8.width, + Text( + label, + style: AppTextStyles.tinyFont, + ), + 13.width, + ], + ); + } +} diff --git a/lib/service_request_latest/views/request_detail_main_view.dart b/lib/service_request_latest/views/request_detail_main_view.dart index 3feab526..aaefa7c7 100644 --- a/lib/service_request_latest/views/request_detail_main_view.dart +++ b/lib/service_request_latest/views/request_detail_main_view.dart @@ -7,6 +7,7 @@ import 'package:test_sa/models/service_request/service_request.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/service_request_latest/views/components/history_log_view.dart'; +import 'package:test_sa/service_request_latest/views/components/initial_visit_card.dart'; import 'components/request_detail_view.dart'; @@ -52,7 +53,6 @@ class RequestDetailMain extends StatelessWidget { serviceRequest: ServiceRequest(id: requestId.toString()), fromTabView: true, ), - // HistoryLogView(), const HistoryLogView(), ], ).expanded, diff --git a/lib/utilities/general_utils.dart b/lib/utilities/general_utils.dart deleted file mode 100644 index 08e06ce4..00000000 --- a/lib/utilities/general_utils.dart +++ /dev/null @@ -1,47 +0,0 @@ -// import 'package:another_flushbar/flushbar.dart'; -// import 'package:flutter/foundation.dart'; -// import 'package:flutter/material.dart'; -// import 'package:test_sa/new_views/app_style/app_color.dart'; -// todo delete -// class GeneralUtils { -// static Duration parseTimeString(String timeString) { -// try { -// print('time string i got is ${timeString}'); -// List timeParts = timeString.split(':'); -// -// int hours = int.parse(timeParts[0]); -// int minutes = int.parse(timeParts[1]); -// int seconds = int.parse(timeParts[2]); -// -// print(''); -// -// return Duration(hours: hours, minutes: minutes, seconds: seconds); -// } catch (e) { -// if (kDebugMode) { -// print("Error parsing time string: $e"); -// } -// return Duration.zero; // Return zero duration in case of an error -// } -// } -// -// static Widget showFlushBar({required BuildContext context, String? title, String? message, double? duration}) { -// return Flushbar( -// flushbarPosition: FlushbarPosition.TOP, -// backgroundColor: AppColor.green70, -// title: title ?? "Hey Ninja", -// message: message ?? "Lorem Ipsum is simply dummy text of the printing and typesetting industry", -// duration: Duration(seconds: duration?.toInt() ?? 3), -// flushbarStyle: FlushbarStyle.GROUNDED, -// reverseAnimationCurve: Curves.easeInOut, -// mainButton: IconButton( -// onPressed: () { -// Navigator.pop(context); -// }, -// icon: const Icon( -// Icons.close, -// color: AppColor.white20, -// ), -// ), -// )..show(context); -// } -// } diff --git a/lib/views/widgets/date_and_time/date_picker.dart b/lib/views/widgets/date_and_time/date_picker.dart index 783b677f..03b25ea2 100644 --- a/lib/views/widgets/date_and_time/date_picker.dart +++ b/lib/views/widgets/date_and_time/date_picker.dart @@ -7,26 +7,26 @@ import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; class ADatePicker extends StatelessWidget { - final DateTime? date; // Nullable - final DateTime? from; // Nullable - final DateTime? to; // Nullable + final DateTime date; + final DateTime from; + final DateTime to; final String label; final bool hideShadow; - final String? hint; // Nullable - final Function(DateTime)? onDatePicker; // Nullable - final bool enable; - final bool withBorder; - final Color? backgroundColor; // Nullable + final String hint; + final Function(DateTime) onDatePicker; + final bool enable, withBorder, withIcon; + final Color backgroundColor; final bool formatDateWithTime; - final double? height; // Nullable + final double height; const ADatePicker({ - Key? key, - required this.label, + Key key, + @required this.label, this.withBorder = true, this.height, this.backgroundColor, this.hideShadow = false, + this.withIcon = true, this.hint, this.date, this.formatDateWithTime = false, @@ -42,9 +42,9 @@ class ADatePicker extends StatelessWidget { height: height, decoration: BoxDecoration( color: backgroundColor ?? - (context.isDark && !enable + (context.isDark && (enable == false) ? AppColor.neutral50 - : !enable + : (enable == false) ? AppColor.neutral40 : AppColor.background(context)), borderRadius: BorderRadius.circular(10), @@ -54,36 +54,34 @@ class ADatePicker extends StatelessWidget { padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), child: Row( children: [ + // enable + // ? Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min, children: [ label.tinyFont(context), - (date == null + (date?.toIso8601String == null ? hint ?? context.translation.pickADate - : (formatDateWithTime - ? date?.toIso8601String().toFirstActionFormat // Use null-aware operator - : (date?.toIso8601String().split("T").first ?? context.translation.pickADate)))! + : (formatDateWithTime ? date?.toIso8601String()?.toFirstActionFormat : (date?.toIso8601String()?.split("T")?.first ?? context.translation.pickADate))) .bodyText(context) .custom(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ], ).expanded, + //: label.bodyText(context).paddingOnly(top: 8, bottom: 8), enable ? 16.width : const Spacer(), - "calender".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null), + withIcon ? "calender".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null) : const SizedBox(), ], ), ).onPress(enable ? () async { - final DateTime? picked = await showDatePicker( - // Nullable DateTime + DateTime picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: from ?? DateTime.now(), lastDate: to ?? DateTime.now().add(const Duration(days: 365)), ); - if (picked != null && onDatePicker != null) { - onDatePicker!(picked); // Use null-aware operator - } + if (onDatePicker != null) onDatePicker(picked); } : null); } diff --git a/lib/views/widgets/date_and_time/time_picker.dart b/lib/views/widgets/date_and_time/time_picker.dart index 7196512a..74ea5bb6 100644 --- a/lib/views/widgets/date_and_time/time_picker.dart +++ b/lib/views/widgets/date_and_time/time_picker.dart @@ -1,24 +1,27 @@ 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/new_views/app_style/app_color.dart'; class ATimePicker extends StatelessWidget { - final TimeOfDay? time; // Nullable + final TimeOfDay time; final String label; - final String? hint; // Nullable - final Function(TimeOfDay)? onTimePicker; // Nullable - final bool enable; - final bool withBorder; - final Color? backgroundColor; // Nullable - final double? height; // Nullable + final String icon; + final String hint; + final Function(TimeOfDay) onTimePicker; + final bool enable, withBorder, withIcon; + final Color backgroundColor; + final double height; const ATimePicker({ - Key? key, - required this.label, + Key key, + @required this.label, this.withBorder = true, + this.icon, + this.withIcon = true, this.height, this.backgroundColor, this.hint, @@ -33,9 +36,9 @@ class ATimePicker extends StatelessWidget { height: height, decoration: BoxDecoration( color: backgroundColor ?? - (context.isDark && !enable + (context.isDark && (enable == false) ? AppColor.neutral50 - : !enable + : (enable == false) ? AppColor.neutral40 : AppColor.background(context)), borderRadius: BorderRadius.circular(10), @@ -45,32 +48,42 @@ class ATimePicker extends StatelessWidget { padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), child: Row( children: [ + // enable + // ? Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min, children: [ label.tinyFont(context), - (time == null - ? hint ?? context.translation.pickTime - : (time!.format(context) ?? // Use null assertion operator - context.translation.pickADate)) + (time == null ? hint ?? context.translation.pickTime : (time.format(context) ?? context.translation.pickADate)) .bodyText(context) .custom(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ], ).expanded, + //: label.bodyText(context).paddingOnly(top: 8, bottom: 8), enable ? 16.width : const Spacer(), - "calender".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null), + withIcon + ? icon != null + ? icon.toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null) + : "calender".toSvgAsset(width: 20, color: context.isDark ? AppColor.neutral10 : null) + : const SizedBox(), ], ), ).onPress(enable ? () async { - final TimeOfDay? pickedTime = await showTimePicker( - // Nullable TimeOfDay + // Define the initial time + TimeOfDay initialTime = TimeOfDay.now(); + + // Show the time picker with the initial time set + TimeOfDay pickedTime = await showTimePicker( context: context, - initialTime: TimeOfDay.now(), + initialTime: initialTime, ); - if (pickedTime != null && onTimePicker != null) { - onTimePicker!(pickedTime); // Use null-aware operator + + // Handle the selected time (if user didn't cancel) + if (pickedTime != null) { + if (onTimePicker != null) onTimePicker(pickedTime); + print("Selected time: ${pickedTime.format(context)}"); } } : null); diff --git a/lib/views/widgets/e_signature/e_signature.dart b/lib/views/widgets/e_signature/e_signature.dart index 6afd7aa3..4fbc46ba 100644 --- a/lib/views/widgets/e_signature/e_signature.dart +++ b/lib/views/widgets/e_signature/e_signature.dart @@ -11,13 +11,15 @@ import 'package:test_sa/new_views/app_style/app_color.dart'; import '../loaders/image_loader.dart'; class ESignature extends StatefulWidget { - final String? oldSignature; - final Uint8List? newSignature; - final Function(Uint8List?)? onSaved; - final Function(Uint8List)? onChange; + final String oldSignature; + final Uint8List newSignature; + Color backgroundColor; + bool showShadow=true; + final Function(Uint8List) onSaved; + final Function(Uint8List) onChange; final String title; - const ESignature({Key? key, required this.title, required this.oldSignature, this.onSaved, this.onChange, required this.newSignature}) : super(key: key); + ESignature({Key key, this.title, this.oldSignature, this.onSaved, this.onChange, this.newSignature,this.backgroundColor,this.showShadow=true}) : super(key: key); @override State createState() => _ESignatureState(); @@ -25,9 +27,9 @@ class ESignature extends StatefulWidget { class _ESignatureState extends State { // Initialise a controller. It will contains signature points, stroke width and pen color. - SignatureController? _controller; + SignatureController _controller; - Uint8List? signature; + Uint8List signature; bool _editable = false; @@ -42,7 +44,7 @@ class _ESignatureState extends State { @override void dispose() { - _controller?.dispose(); + _controller.dispose(); super.dispose(); } @@ -55,7 +57,7 @@ class _ESignatureState extends State { ); print(widget.oldSignature); return FormField(onSaved: (_) async { - if (widget.onSaved != null) widget.onSaved!(signature); + widget.onSaved(signature); }, builder: (FormFieldState state) { return Column( children: [ @@ -63,9 +65,9 @@ class _ESignatureState extends State { width: MediaQuery.of(context).size.width, padding: EdgeInsets.symmetric(horizontal: 16.toScreenWidth, vertical: 8.toScreenHeight), decoration: BoxDecoration( - color: context.isDark ? AppColor.background(context) : Colors.white, + color:widget.backgroundColor ?? (context.isDark ? AppColor.background(context) : Colors.white), borderRadius: _editable ? const BorderRadius.only(topLeft: Radius.circular(10), topRight: Radius.circular(10)) : BorderRadius.circular(10), - boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)], + boxShadow:widget.showShadow? [BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)]:[], ), child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -87,9 +89,9 @@ class _ESignatureState extends State { )) .onPress(() async { if (_editable) { - signature = await _controller!.toPngBytes(); + signature = await _controller.toPngBytes(); if (widget.onChange != null) { - widget.onChange!(signature!); + widget.onChange(signature); } } _editable = !_editable; @@ -102,12 +104,12 @@ class _ESignatureState extends State { height: 135.toScreenHeight, width: MediaQuery.of(context).size.width, padding: const EdgeInsets.only(bottom: 8), - child: signature != null ? Image.memory(signature!) : ImageLoader(boxFit: BoxFit.contain, url: URLs.getFileUrl(widget.oldSignature)!), + child: signature != null ? Image.memory(signature) : ImageLoader(boxFit: BoxFit.contain, url: URLs.getFileUrl(widget.oldSignature)), ) : AbsorbPointer( absorbing: !_editable, child: Signature( - controller: _controller!, + controller: _controller, height: 135.toScreenHeight, width: MediaQuery.of(context).size.width - 64.toScreenWidth, backgroundColor: Colors.transparent, @@ -125,15 +127,15 @@ class _ESignatureState extends State { child: Row( children: [ "clear".toSvgAsset(width: 14).paddingOnly(start: 16).onPress(() { - _controller!.clear(); + _controller.clear(); }), 35.width, "back".toSvgAsset(width: 17).onPress(() { - _controller!.undo(); + _controller.undo(); }), 27.width, "redo".toSvgAsset(width: 17).onPress(() { - _controller!.redo(); + _controller.redo(); }), // IconButton( // onPressed: () { diff --git a/lib/views/widgets/images/multi_image_picker.dart b/lib/views/widgets/images/multi_image_picker.dart index cce9be4b..c8e114bb 100644 --- a/lib/views/widgets/images/multi_image_picker.dart +++ b/lib/views/widgets/images/multi_image_picker.dart @@ -18,10 +18,13 @@ class MultiFilesPicker extends StatefulWidget { final bool error; final List files; final bool enabled, onlyImages; - final Function(List)? onChange; + double buttonHeight; + Widget buttonIcon; + Color buttonColor; + final Function(List) onChange; final bool showAsGrid; - const MultiFilesPicker({Key? key, this.files = const [], required this.label, this.error = false, this.enabled = true, this.onlyImages = false, this.onChange, this.showAsGrid = false}) + MultiFilesPicker({Key key, this.files, this.label, this.error = false, this.buttonHeight, this.buttonIcon, this.enabled = true, this.onlyImages = false, this.onChange, this.showAsGrid = false,this.buttonColor}) : super(key: key); @override @@ -36,13 +39,16 @@ class _MultiFilesPickerState extends State { children: [ AppDashedButton( title: widget.label, + height: widget.buttonHeight, + buttonColor: widget.buttonColor, + icon: widget.buttonIcon, onPressed: (widget.enabled == false) ? () {} : widget.showAsGrid ? showFileSourceSheet : onFilePicker), 16.height, - if (widget.files.isNotEmpty ?? false) + if (widget.files?.isNotEmpty ?? false) Wrap( spacing: 8.toScreenWidth, children: List.generate( @@ -58,7 +64,7 @@ class _MultiFilesPickerState extends State { } widget.files.remove(image); if (widget.onChange != null) { - widget.onChange!(widget.files); + widget.onChange(widget.files); } setState(() {}); }, @@ -71,14 +77,14 @@ class _MultiFilesPickerState extends State { } fromFilePicker() async { - FilePickerResult? result = await FilePicker.platform.pickFiles( + FilePickerResult result = await FilePicker.platform.pickFiles( type: FileType.custom, allowMultiple: true, allowedExtensions: widget.onlyImages ? ['jpg', 'jpeg', 'png'] : ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx'], ); if (result != null) { for (var path in result.paths) { - widget.files.add(File(path!)); + widget.files.add(File(path)); } setState(() {}); } @@ -90,7 +96,7 @@ class _MultiFilesPickerState extends State { return; } - ImageSource? source = (await showModalBottomSheet( + ImageSource source = (await showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical( @@ -105,10 +111,10 @@ class _MultiFilesPickerState extends State { "Attach File".heading4(context), 12.height, GridView( - padding: const EdgeInsets.all(0), + padding: EdgeInsets.all(0), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12), children: [ gridItem(Icons.camera_enhance_rounded, context.translation.pickFromCamera).onPress(() => Navigator.of(context).pop(ImageSource.camera)), gridItem(Icons.image_rounded, context.translation.pickFromGallery).onPress(() => Navigator.of(context).pop(ImageSource.gallery)), @@ -121,7 +127,7 @@ class _MultiFilesPickerState extends State { 12.height, ], ).paddingAll(21), - )) as ImageSource?; + )) as ImageSource; if (source == null) return; @@ -129,30 +135,32 @@ class _MultiFilesPickerState extends State { if (pickedFile != null) { File fileImage = File(pickedFile.path); - widget.files.add(fileImage); - if (widget.onChange != null) { - widget.onChange!(widget.files); + if (fileImage != null) { + widget.files.add(fileImage); + if (widget.onChange != null) { + widget.onChange(widget.files); + } + setState(() {}); } - setState(() {}); } } Widget gridItem(IconData iconData, String title) { return Container( - padding: const EdgeInsets.all(12), + padding: EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), - border: Border.all(color: const Color(0xffF1F1F1), width: 1), + border: Border.all(color: Color(0xffF1F1F1), width: 1), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Icon(iconData, color: const Color(0xff7D859A), size: 36), + Icon(iconData, color: Color(0xff7D859A), size: 36), Text( title, - style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500), + style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500), ), ], ), @@ -164,7 +172,7 @@ class _MultiFilesPickerState extends State { Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); return; } - ImageSource? source = await showDialog( + ImageSource source = await showDialog( context: context, builder: (dialogContext) => CupertinoAlertDialog( actions: [ @@ -196,12 +204,14 @@ class _MultiFilesPickerState extends State { if (pickedFile != null) { File fileImage = File(pickedFile.path); - widget.files.add(fileImage); - if (widget.onChange != null) { - widget.onChange!(widget.files); - } - setState(() {}); + if (fileImage != null) { + widget.files.add(fileImage); + if (widget.onChange != null) { + widget.onChange(widget.files); } + setState(() {}); + } + } setState(() {}); } diff --git a/lib/views/widgets/images/multi_image_picker_item.dart b/lib/views/widgets/images/multi_image_picker_item.dart index b892de93..0b365bf3 100644 --- a/lib/views/widgets/images/multi_image_picker_item.dart +++ b/lib/views/widgets/images/multi_image_picker_item.dart @@ -35,6 +35,7 @@ class MultiFilesPickerItem extends StatelessWidget { Container( margin: EdgeInsetsDirectional.only(top: 4.toScreenHeight, end: 6.toScreenWidth), decoration: BoxDecoration( + color: Colors.red, border: Border.all(width: 1, color: context.isDark ? AppColor.neutral30 : AppColor.neutral30), image: DecorationImage( image: getImage(isImage, isPdf, isExcel, file), diff --git a/pubspec.yaml b/pubspec.yaml index d9ec191f..a599ca43 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.2.2+9 environment: - sdk: ">=3.5.0 <4.0.0" + sdk: ">=2.7.0 <3.0.0" localization_dir: assets\translations @@ -38,57 +38,54 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.5 font_awesome_flutter: ^10.2.1 - http: ^1.2.2 + http: ^0.13.5 provider: ^6.0.3 shared_preferences: ^2.0.15 fluttertoast: ^8.0.9 - image_picker: ^1.1.2 + image_picker: ^0.8.6 url_launcher: ^6.1.6 - flutter_launcher_icons: ^0.13.1 + flutter_launcher_icons: ^0.10.0 package_info: ^2.0.2 share: ^2.0.4 - flutter_local_notifications: ^17.2.2 + flutter_local_notifications: ^12.0.1+1 cached_network_image: ^3.2.2 - carousel_slider: ^5.0.0 - intl: ^0.19.0 - flutter_typeahead: ^5.2.0 - speech_to_text: ^7.0.0 - firebase_core: ^3.4.1 - firebase_messaging: ^15.1.1 + carousel_slider: ^4.1.1 + intl: ^0.17.0 + flutter_typeahead: ^4.1.1 + speech_to_text: ^6.1.1 + firebase_core: ^2.4.0 + firebase_messaging: ^14.2.0 qr_code_scanner: ^1.0.1 flutter_sound: ^9.2.13 - permission_handler: ^11.3.1 - rive: ^0.13.13 + permission_handler: ^10.2.0 + rive: ^0.9.1 another_flushbar: pinput: - audioplayers: ^6.1.0 + audioplayers: ^1.1.1 flare_flutter: ^3.0.2 signature: ^5.3.0 - flutter_svg: ^2.0.10+1 - file_picker: ^8.1.2 - record_mp3_plus: any + flutter_svg: ^1.1.6 + file_picker: ^5.2.5 + record_mp3: ^2.1.0 path_provider: ^2.1.0 open_file: ^3.3.2 localization: ^2.1.0 dotted_border: ^2.1.0 - lottie: ^3.1.2 - shimmer: ^3.0.0 + lottie: ^2.3.0 + shimmer: ^2.0.0 flutter_advanced_switch: ^3.0.1 table_calendar: ^3.0.8 - image_cropper: ^8.0.2 - + image_cropper: ^3.0.3 + touchable: ^0.2.1 badges: ^3.1.1 -# buttons_tabbar: ^1.1.2 - flutter_custom_month_picker: ^0.1.3 - syncfusion_flutter_charts: ^26.2.14 - local_auth: ^2.3.0 + flutter_month_picker: ^0.0.2 + syncfusion_flutter_charts: ^21.2.3 + local_auth: ^2.1.6 - local_auth_darwin: any dev_dependencies: flutter_test: sdk: flutter -dependency_overrides: - win32: ^5.5.4 + # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your