From d3bee4f39af4181369daaa8ba806b747e7ccf749 Mon Sep 17 00:00:00 2001 From: nextwo <1234> Date: Thu, 4 Jan 2024 10:54:47 +0300 Subject: [PATCH] gas refill comments --- lib/controllers/api_routes/urls.dart | 2 + .../providers/api/gas_refill_comments.dart | 112 ++++++++++++++ lib/main.dart | 2 + lib/models/gas_refill_comments_model.dart | 81 ++++++++++ .../user/gas_refill/gas_refill_comments.dart | 143 ++++++++++++++++++ .../user/gas_refill/gas_refill_details.dart | 12 +- 6 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 lib/controllers/providers/api/gas_refill_comments.dart create mode 100644 lib/models/gas_refill_comments_model.dart create mode 100644 lib/views/pages/user/gas_refill/gas_refill_comments.dart diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index b209b104..efafd2a4 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -97,6 +97,8 @@ class URLs { static get updateGasRefill => "$_baseUrl/GazRefill/UpdateGazRefill"; // get static get getGasRefill => "$_baseUrl/GazRefill/GetGazRefills"; // get static get getGasRefillById => "$_baseUrl/GazRefill/GetGazRefillById"; // get + static get getGazRefillComments => "$_baseUrl/GazRefill/GetHistoryComments"; // get + static get addGazRefillComment => "$_baseUrl/GazRefill/AddHistoryComment"; // add //device transfer static get requestDeviceTransfer => "$_baseUrl/AssetTransfer/AddAssetTransfer"; // get diff --git a/lib/controllers/providers/api/gas_refill_comments.dart b/lib/controllers/providers/api/gas_refill_comments.dart new file mode 100644 index 00000000..9a06013e --- /dev/null +++ b/lib/controllers/providers/api/gas_refill_comments.dart @@ -0,0 +1,112 @@ +import 'dart:convert'; + +import 'package:flutter/material.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/urls.dart'; +import 'package:test_sa/extensions/context_extension.dart'; + +import '../../../models/gas_refill_comments_model.dart'; +import '../../../new_views/common_widgets/app_lazy_loading.dart'; + +class GasRefillCommentsProvider extends ChangeNotifier { + // number of items call in each request + final pageItemNumber = 12; + + //reset provider data + void reset() { + comments = []; + nextPage = true; + stateCode = null; + } + + // state code of current request to defied error message + // like 400 customer request failed + // 500 service not available + int stateCode; + + // true if there is next page in product list and false if not + bool nextPage = true; + + // list of user requests + List comments = []; + + // when requests in-process _loading = true + // done _loading = true + // failed _loading = false + bool isLoading; + + /// return -2 if request in progress + /// return -1 if error happen when sending request + /// return state code if request complete may be 200, 404 or 403 + /// for more details check http state manager + /// lib\controllers\http_status_manger\http_status_manger.dart + Future getComments({@required String callId}) async { + if (isLoading == true) return -2; + isLoading = true; + notifyListeners(); + Response response; + try { + response = await ApiManager.instance.get(URLs.getGazRefillComments + "?callRequestId=$callId"); + + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + List requestsListJson = json.decode(response.body)["data"]; + List commentsPage = requestsListJson.map((request) => GasRefillComment.fromJson(request)).toList(); + comments ??= []; + comments.addAll(commentsPage); + if (commentsPage.length == pageItemNumber) { + nextPage = true; + } else { + nextPage = false; + } + } + isLoading = false; + notifyListeners(); + return response.statusCode; + } catch (error) { + print(error); + isLoading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } + + /// return -2 if request in progress + /// return -1 if error happen when sending request + /// return state code if request complete may be 200, 404 or 403 + /// for more details check http state manager + /// lib\controllers\http_status_manger\http_status_manger.dart + Future addComment(BuildContext context, {@required GasRefillComment comment}) async { + if (isLoading == true) return -2; + isLoading = true; + Response response; + try { + comment.id = 0; + showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading()); + response = await ApiManager.instance.post(URLs.addGazRefillComment, body: comment.toJson()); + + stateCode = response.statusCode; + if (response.statusCode >= 200 && response.statusCode < 300) { + reset(); //visit.status = pentry.ppmVisitStatus; + notifyListeners(); + Fluttertoast.showToast(msg: context.translation.successfulRequestMessage); + Navigator.of(context).pop(); + } else { + Fluttertoast.showToast(msg: "${context.translation.failedToCompleteRequest} ${jsonDecode(response.body)["message"]}"); + } + isLoading = false; + notifyListeners(); + Navigator.of(context).pop(); + return response.statusCode; + } catch (error) { + print(error); + isLoading = false; + stateCode = -1; + notifyListeners(); + return -1; + } + } +} diff --git a/lib/main.dart b/lib/main.dart index a2babaf6..e828298e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -94,6 +94,7 @@ import 'package:test_sa/views/widgets/equipment/asset_detail_page.dart'; import 'package:test_sa/views/widgets/equipment/single_device_picker.dart'; import 'package:test_sa/views/widgets/hospitals/single_hospital_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 'new_views/pages/new_gas_refill_request_page.dart'; @@ -196,6 +197,7 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider(create: (_) => PentryTaskStatusProvider()), ChangeNotifierProvider(create: (_) => PPMDeviceStatusProvider()), ChangeNotifierProvider(create: (_) => CommentsProvider()), + ChangeNotifierProvider(create: (_) => GasRefillCommentsProvider()), ChangeNotifierProvider(create: (_) => RequestStatusProvider()), ChangeNotifierProvider(create: (_) => VendorProvider()), ChangeNotifierProvider(create: (_) => PpmChecklistStatusProvider()), diff --git a/lib/models/gas_refill_comments_model.dart b/lib/models/gas_refill_comments_model.dart new file mode 100644 index 00000000..32f2d702 --- /dev/null +++ b/lib/models/gas_refill_comments_model.dart @@ -0,0 +1,81 @@ +class GasRefillComment { + GasRefillComment({ + this.id, + this.gasRefillId, + this.createdOn, + this.createdBy, + this.comment, + }); + + GasRefillComment.fromJson(dynamic json) { + id = json['id']; + gasRefillId = json['gasRefillId']; + createdOn = json['createdOn']; + createdBy = json['createdBy'] != null ? CreatedBy.fromJson(json['createdBy']) : null; + comment = json['comment']; + } + + num id; + num gasRefillId; + String createdOn; + CreatedBy createdBy; + String comment; + + GasRefillComment copyWith({ + num id, + num callRequestId, + String createdOn, + CreatedBy createdBy, + String comment, + }) => + GasRefillComment( + id: id ?? this.id, + gasRefillId: callRequestId ?? this.gasRefillId, + createdOn: createdOn ?? this.createdOn, + createdBy: createdBy ?? this.createdBy, + comment: comment ?? this.comment, + ); + + Map toJson() { + final map = {}; + map['id'] = id; + map['gasRefillId'] = gasRefillId; + map['createdOn'] = createdOn; + if (createdBy != null) { + map['createdBy'] = createdBy.toJson(); + } + map['comment'] = comment; + return map; + } +} + +class CreatedBy { + CreatedBy({ + this.userId, + this.userName, + }); + + CreatedBy.fromJson(dynamic json) { + userId = json['userId']; + userName = json['userName']; + } + + String userId; + String userName; + + CreatedBy copyWith({ + String userId, + String userName, + }) => + CreatedBy( + userId: userId ?? this.userId, + userName: userName ?? this.userName, + ); + + Map toJson() { + final map = {}; + map['userId'] = userId; + map['userName'] = userName; + return map; + } +} diff --git a/lib/views/pages/user/gas_refill/gas_refill_comments.dart b/lib/views/pages/user/gas_refill/gas_refill_comments.dart new file mode 100644 index 00000000..fa45981e --- /dev/null +++ b/lib/views/pages/user/gas_refill/gas_refill_comments.dart @@ -0,0 +1,143 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/providers/api/gas_refill_comments.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/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/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/views/widgets/loaders/lazy_loading.dart'; +import 'package:test_sa/views/widgets/loaders/no_item_found.dart'; + +import '../../../../models/gas_refill_comments_model.dart'; +import '../../../../new_views/app_style/app_color.dart'; +import '../../../widgets/loaders/loading_manager.dart'; + +class GasRefillCommentsBottomSheet extends StatefulWidget { + final String requestId; + + const GasRefillCommentsBottomSheet({Key key, @required this.requestId}) : super(key: key); + + @override + State createState() => _GasRefillCommentsBottomSheetState(); +} + +class _GasRefillCommentsBottomSheetState extends State { + final GlobalKey _formKey = GlobalKey(); + String text; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + final commentsProvider = Provider.of(context); + final userProvider = Provider.of(context, listen: false); + return SingleChildScrollView( + child: 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: Column( + children: [ + LoadingManager( + isLoading: commentsProvider.isLoading, + isFailedLoading: commentsProvider.comments == null, + stateCode: commentsProvider.stateCode, + onRefresh: () async { + commentsProvider.reset(); + await commentsProvider.getComments(callId: widget.requestId); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 40.toScreenWidth, + height: 5.toScreenHeight, + decoration: BoxDecoration(color: AppColor.neutral40, borderRadius: BorderRadius.circular(30)), + ), + 16.height, + Align( + alignment: AlignmentDirectional.centerStart, + child: context.translation.comments.heading3(context).custom(fontWeight: FontWeight.w600), + ), + commentsProvider.comments.isEmpty + ? SizedBox( + height: MediaQuery.of(context).size.height * 0.25, + child: NoItemFound(message: context.translation.noDataFound), + ) + : LazyLoading( + nextPage: commentsProvider.nextPage, + onLazyLoad: () async => await commentsProvider.getComments(callId: widget.requestId), + child: ListView.separated( + itemCount: commentsProvider.comments.length, + padding: const EdgeInsets.only(top: 16, bottom: 8), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (cxt, index) => 8.height, + itemBuilder: (context, itemIndex) { + final model = commentsProvider.comments[itemIndex]; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (model?.createdBy?.userName ?? "Nurse").heading6(context), + 8.height, + (model?.comment ?? "").bodyText(context), + 8.height, + Align( + alignment: AlignmentDirectional.bottomEnd, + child: Text(DateTime.tryParse(model.createdOn).toIso8601String().toServiceRequestDetailsFormat, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50)), + ), + ], + ).toShadowContainer(context); + }, + ), + ), + ], + ), + ), + if (userProvider.user.type == UsersTypes.normal_user) 8.height, + if (userProvider.user.type == UsersTypes.normal_user) + 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 = GasRefillComment(id: 0, gasRefillId: num.tryParse(widget.requestId ?? ""), comment: text); + commentsProvider.addComment(context, comment: comment); + } + }), + onSaved: (value) { + text = value; + }, + ), + 16.height, + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/views/pages/user/gas_refill/gas_refill_details.dart b/lib/views/pages/user/gas_refill/gas_refill_details.dart index 9ea15801..6fee2bec 100644 --- a/lib/views/pages/user/gas_refill/gas_refill_details.dart +++ b/lib/views/pages/user/gas_refill/gas_refill_details.dart @@ -16,6 +16,7 @@ import '../../../../models/new_models/gas_refill_model.dart'; import '../../../../new_views/app_style/app_color.dart'; import '../../../../new_views/common_widgets/default_app_bar.dart'; import '../../../widgets/requests/request_status.dart'; +import 'gas_refill_comments.dart'; class GasRefillDetailsPage extends StatefulWidget { GasRefillModel model; @@ -196,7 +197,16 @@ class _GasRefillDetailsPageState extends State { ), ], ).paddingOnly(bottom: 16, start: 16, end: 16)) - .onPress(() {}), + .onPress(() { + showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + useRootNavigator: true, + backgroundColor: Colors.transparent, + builder: (context) => GasRefillCommentsBottomSheet(requestId: gasRefillModel.id.toString()), + ); + }), ], ).toShadowContainer(context, padding: 0); }