diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index dd19cbec..2ff05c23 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -19,6 +19,7 @@ class URLs { static const String chatHubUrlApi = "$chatHubUrl/api"; // new V2 apis static const String chatHubUrlChat = "$chatHubUrl/hubs/chat"; // new V2 apis static const String resetMessageCount = "$chatHubUrlApi/userChatHistory/AckMessages"; // new V2 apis + static const String unreadMessages = "$chatHubUrlApi/userChatHistory/unread-messages"; // new V2 apis static const String chatApiKey = "f53a98286f82798d588f67a7f0db19f7aebc839e"; // new V2 apis static String _host = host1; @@ -421,6 +422,7 @@ class URLs { static get getOvrTicketDetails => '$_baseUrl/Incident/GetOvrTicketDetails'; static get addLoan => '$_baseUrl/Loan/AddLoan'; + static get loanWorkflowAction => '$_baseUrl/Loan/LoanWorkflowAction'; static get addIncident => '$_baseUrl/Incident/AddIncident'; static get addDemoTrialOutcome => '$_baseUrl/DemoRequest/addDemoTrialOutcome'; diff --git a/lib/dashboard_latest/widgets/app_bar_widget.dart b/lib/dashboard_latest/widgets/app_bar_widget.dart index d86a1750..0621065f 100644 --- a/lib/dashboard_latest/widgets/app_bar_widget.dart +++ b/lib/dashboard_latest/widgets/app_bar_widget.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; @@ -10,6 +11,7 @@ import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/pages/user/notifications/notifications_page.dart'; +import 'package:test_sa/views/pages/user/notifications/unread_chat_list.dart'; import 'package:test_sa/views/widgets/dialogs/confirm_dialog.dart'; import '../../controllers/providers/api/user_provider.dart'; @@ -127,6 +129,12 @@ class AppBarWidget extends StatelessWidget { ); }), 16.width, + if (context.settingProvider.isUserFlowMedical) ...[ + Icon(Icons.mark_unread_chat_alt_outlined, color: context.isDark ? AppColor.neutral30 : AppColor.neutral20, size: 30).paddingOnly(top: 6, end: 0).onPress(() { + Navigator.of(context).push(CupertinoPageRoute(builder: (_) => UnReadChatList())); + }), + 8.width, + ], Stack( alignment: Alignment.topRight, children: [ diff --git a/lib/extensions/context_extension.dart b/lib/extensions/context_extension.dart index d214cf98..792dd942 100644 --- a/lib/extensions/context_extension.dart +++ b/lib/extensions/context_extension.dart @@ -42,12 +42,12 @@ extension BuildContextExtension on BuildContext { builder: (BuildContext cxt) => InfoDialog(message: message, onTap: onTap, title: title, okTitle: okTitle, content: content), ); - Future showBottomSheet(Widget childWidget, {bool? isDismissible, String? title}) => showModalBottomSheet( + Future showBottomSheet(Widget childWidget, {bool? isDismissible, String? title, bool showCancelButton = false}) => showModalBottomSheet( context: this, useSafeArea: true, isScrollControlled: true, isDismissible: true, backgroundColor: Colors.transparent, - builder: (context) => SingleChildScrollView(padding: const EdgeInsets.all(0), child: childWidget.bottomSafeArea).bottomSheetContainerNew(context, title: title), + builder: (context) => SingleChildScrollView(padding: const EdgeInsets.all(0), child: childWidget.bottomSafeArea).bottomSheetContainerNew(context, title: title,showCancelButton: showCancelButton), ); } diff --git a/lib/extensions/text_extensions.dart b/lib/extensions/text_extensions.dart index e608131f..5ec00e5b 100644 --- a/lib/extensions/text_extensions.dart +++ b/lib/extensions/text_extensions.dart @@ -23,7 +23,7 @@ extension TextStyles on String { Text heading6(BuildContext context) => getTextWithStyle(this, AppTextStyles.heading6, context.isDark ? AppColor.neutral30 : AppColor.neutral50); - Text bodyText(BuildContext context) => getTextWithStyle(this, AppTextStyles.bodyText, context.isDark ? AppColor.neutral10 : AppColor.neutral20); + Text bodyText(BuildContext context) => getTextWithStyle(this, AppTextStyles.bodyText, context.isDarkNotListen ? AppColor.neutral10 : AppColor.neutral20); Text bodyText2(BuildContext context) => getTextWithStyle(this, AppTextStyles.bodyText2, context.isDark ? AppColor.neutral10 : AppColor.neutral20); diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 946d2b29..1d2d59f8 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -145,7 +145,7 @@ extension WidgetExtensions on Widget { child: this, ); - Widget bottomSheetContainerNew(BuildContext context, {EdgeInsets? padding, String? title}) => Container( + Widget bottomSheetContainerNew(BuildContext context, {EdgeInsets? padding, String? title, bool showCancelButton = false}) => Container( clipBehavior: Clip.antiAlias, margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), decoration: BoxDecoration( @@ -164,7 +164,21 @@ extension WidgetExtensions on Widget { ).center, 16.height, if (title != null) ...[ - title.bottomSheetHeadingTextStyle(context), + Row( + children: [ + title.bottomSheetHeadingTextStyle(context).expanded, + if (showCancelButton) ...[ + 8.width, + InkWell( + onTap: () => Navigator.pop(context), + child: Icon( + Icons.cancel_outlined, + color: context.isDarkNotListen ? AppColor.neutral30 : AppColor.black20, + ), + ) + ] + ], + ), 16.height, ], this diff --git a/lib/models/new_models/task_request/task_request_model.dart b/lib/models/new_models/task_request/task_request_model.dart index 6d7c9956..235b3851 100644 --- a/lib/models/new_models/task_request/task_request_model.dart +++ b/lib/models/new_models/task_request/task_request_model.dart @@ -491,6 +491,7 @@ class TaskTypeModel { final List? taskTypeRoles; final bool? isInstallation; final bool? isRecallAndAlert; + final bool? isSignatureRequired; TaskTypeModel({ this.id, @@ -500,6 +501,7 @@ class TaskTypeModel { this.taskTypeRoles, this.isInstallation, this.isRecallAndAlert, + this.isSignatureRequired, }); factory TaskTypeModel.fromJson(Map json) => TaskTypeModel( @@ -510,6 +512,7 @@ class TaskTypeModel { taskTypeRoles: json['taskTypeRoles'], isInstallation: json['isInstallation'], isRecallAndAlert: json['isRecallAndAlert'], + isSignatureRequired: json['isSignatureRequired'], ); Map toJson() => { @@ -520,6 +523,7 @@ class TaskTypeModel { 'taskTypeRoles': taskTypeRoles, 'isInstallation': isInstallation, 'isRecallAndAlert': isRecallAndAlert, + 'isSignatureRequired': isSignatureRequired, }; } diff --git a/lib/modules/cx_module/chat/chat_provider.dart b/lib/modules/cx_module/chat/chat_provider.dart index 0755d74f..31791231 100644 --- a/lib/modules/cx_module/chat/chat_provider.dart +++ b/lib/modules/cx_module/chat/chat_provider.dart @@ -48,11 +48,13 @@ import 'package:test_sa/modules/cx_module/chat/model/chat_login_response_model.d import 'package:uuid/uuid.dart'; import 'package:flutter/material.dart' as Material; +import 'api_client.dart'; import 'chat_api_client.dart'; import 'model/chat_attachment_model.dart'; import 'model/chat_participant_model.dart'; import 'model/get_search_user_chat_model.dart'; import 'model/get_single_user_chat_list_model.dart'; +import 'model/unread_message_model.dart'; import 'model/user_chat_history_model.dart'; // import 'get_single_user_chat_list_model.dart'; @@ -454,6 +456,25 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { return result; } + Future> getUnReadMessages(String employeeId) async { + // employeeId = "FMEngineer"; + + try { + Response response = await ApiClient().getJsonForResponse( + "${URLs.unreadMessages}?retrieveAll=true", + headers: {'x-api-key': URLs.chatApiKey, 'x-employee-number': employeeId}, + ); + if (response.statusCode == 200) { + List data = jsonDecode(response.body); + return data.map((elemet) => UnReadMessage.fromJson(elemet)).toList(); + } else { + return []; + } + } catch (error) { + return []; + } + } + // void updateUserChatStatus(List? args) { // dynamic items = args!.toList(); // for (var cItem in items[0]) { @@ -616,7 +637,6 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { } } - Future onAckSeenAsync(List? parameters) async { try { if (parameters == null || parameters.isEmpty) { diff --git a/lib/modules/cx_module/chat/model/unread_message_model.dart b/lib/modules/cx_module/chat/model/unread_message_model.dart new file mode 100644 index 00000000..da10d73e --- /dev/null +++ b/lib/modules/cx_module/chat/model/unread_message_model.dart @@ -0,0 +1,48 @@ +class UnReadMessage { + int? messageId; + int? conversationId; + String? senderEmployeeNumber; + String? senderUserName; + String? content; + String? createdAt; + String? moduleCode; + String? referenceId; + String? senderStatus; + + UnReadMessage( + {this.messageId, + this.conversationId, + this.senderEmployeeNumber, + this.senderUserName, + this.content, + this.createdAt, + this.moduleCode, + this.referenceId, + this.senderStatus}); + + UnReadMessage.fromJson(Map json) { + messageId = json['messageId']; + conversationId = json['conversationId']; + senderEmployeeNumber = json['senderEmployeeNumber']; + senderUserName = json['senderUserName']; + content = json['content']; + createdAt = json['createdAt']; + moduleCode = json['moduleCode']; + referenceId = json['referenceId']; + senderStatus = json['senderStatus']; + } + + Map toJson() { + final Map data = new Map(); + data['messageId'] = this.messageId; + data['conversationId'] = this.conversationId; + data['senderEmployeeNumber'] = this.senderEmployeeNumber; + data['senderUserName'] = this.senderUserName; + data['content'] = this.content; + data['createdAt'] = this.createdAt; + data['moduleCode'] = this.moduleCode; + data['referenceId'] = this.referenceId; + data['senderStatus'] = this.senderStatus; + return data; + } +} diff --git a/lib/modules/loan_module/models/loan_form_model.dart b/lib/modules/loan_module/models/loan_form_model.dart index 575dd147..e1722ba7 100644 --- a/lib/modules/loan_module/models/loan_form_model.dart +++ b/lib/modules/loan_module/models/loan_form_model.dart @@ -30,7 +30,7 @@ class LoanFormModel { LoanFormModel({ this.docName, - this.isNewVendor=false, + this.isNewVendor = false, this.docNumber, this.docEmail, this.itemDescription, @@ -118,7 +118,9 @@ class LoanAttachments { num? loanId; String? attachmentName; String? attachmentDescription; + LoanAttachments({this.id, this.loanAttachmentTypeId, this.attachmentName, this.loanId, this.attachmentDescription}); + LoanAttachments.fromJson(dynamic json) { id = json['id']; loanAttachmentTypeId = json['loanAttachmentTypeId']; diff --git a/lib/modules/loan_module/models/loan_installation_pullout_form_model.dart b/lib/modules/loan_module/models/loan_installation_pullout_form_model.dart index bcbbff31..ff2129db 100644 --- a/lib/modules/loan_module/models/loan_installation_pullout_form_model.dart +++ b/lib/modules/loan_module/models/loan_installation_pullout_form_model.dart @@ -13,6 +13,9 @@ class LoanInstallationPullOutFormModel { DateTime? startTime; DateTime? endTime; double? totalHours; + int? loanId; + String? userId; + int? loanStatusId; LoanInstallationPullOutFormModel({ this.loanAttachment, @@ -23,18 +26,71 @@ class LoanInstallationPullOutFormModel { this.startTime, this.endTime, this.totalHours, + this.loanId, + this.loanStatusId, + this.userId, }); Map toJson() { //Need to check payload parm they need return { - 'snNo': snNo, - 'InstallationDate': date?.toIso8601String(), + // 'snNo': snNo, + 'serialNumber': snNo, + 'installationDate': date?.toIso8601String(), + 'pulloutDate': date?.toIso8601String(), "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [], + "installationSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, "signature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, + "pulloutSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, 'startTime': startTime?.toIso8601String(), 'endTime': endTime?.toIso8601String(), 'totalHours': totalHours, + 'loanId': loanId, + 'loanStatusId': loanStatusId, + 'userId': userId, + 'isFromMobile': true, + }; + } + + Map toInstallationJson() { + //Need to check payload parm they need + return { + // 'snNo': snNo, + 'serialNumber': snNo, + 'installationDate': date?.toIso8601String(), + // 'pulloutDate': date?.toIso8601String(), + "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [], + "installationSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, + // "signature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, + // "pulloutSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, + 'startTime': startTime?.toIso8601String(), + 'endTime': endTime?.toIso8601String(), + 'totalHours': totalHours, + 'loanId': loanId, + 'loanStatusId': loanStatusId, + 'userId': userId, + 'isFromMobile': true, + }; + } + + Map toPulloutJson() { + //Need to check payload parm they need + return { + // 'snNo': snNo, + 'serialNumber': snNo, + // 'installationDate': date?.toIso8601String(), + 'pulloutDate': date?.toIso8601String(), + "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [], + // "installationSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, + // "signature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, + "pulloutSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null, + 'startTime': startTime?.toIso8601String(), + 'endTime': endTime?.toIso8601String(), + 'totalHours': totalHours, + 'loanId': loanId, + 'loanStatusId': loanStatusId, + 'userId': userId, + 'isFromMobile': true, }; } } diff --git a/lib/modules/loan_module/models/loan_request_model.dart b/lib/modules/loan_module/models/loan_request_model.dart index 2472f201..5757299f 100644 --- a/lib/modules/loan_module/models/loan_request_model.dart +++ b/lib/modules/loan_module/models/loan_request_model.dart @@ -55,6 +55,8 @@ class LoanRequestModel { int? pulloutWOItemId; int? id; String? installationDate; + String? startTime; + String? endTime; String? pulloutDate; String? createdBy; String? createdDate; @@ -114,6 +116,8 @@ class LoanRequestModel { this.id, this.createdBy, this.installationDate, + this.startTime, + this.endTime, this.pulloutDate, this.createdDate, this.modifiedBy, @@ -177,6 +181,8 @@ class LoanRequestModel { pulloutWOItemId = json['pulloutWOItemId']; id = json['id']; installationDate = json['installationDate']; + startTime = json['startTime']; + endTime = json['endTime']; pulloutDate = json['pulloutDate']; createdBy = json['createdBy']; createdDate = json['createdDate']; @@ -239,6 +245,8 @@ class LoanRequestModel { data['pulloutWOItemId'] = this.pulloutWOItemId; data['id'] = this.id; data['installationDate'] = this.installationDate; + data['startTime'] = this.startTime; + data['endTime'] = this.endTime; data['pulloutDate'] = this.pulloutDate; data['createdBy'] = this.createdBy; data['createdDate'] = this.createdDate; diff --git a/lib/modules/loan_module/pages/installation_form_view.dart b/lib/modules/loan_module/pages/installation_form_view.dart new file mode 100644 index 00000000..f39b3ac6 --- /dev/null +++ b/lib/modules/loan_module/pages/installation_form_view.dart @@ -0,0 +1,223 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/string_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/helper/utils.dart'; +import 'package:test_sa/models/generic_attachment_model.dart'; +import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; +import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/loan_module/models/loan_form_model.dart'; +import 'package:test_sa/modules/loan_module/models/loan_installation_pullout_form_model.dart'; +import 'package:test_sa/modules/loan_module/models/loan_request_model.dart'; +import 'package:test_sa/modules/loan_module/provider/loan_provider.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; +import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; +import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; +import 'package:test_sa/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/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/timer/app_timer.dart'; + +class InstallationFormView extends StatefulWidget { + LoanRequestModel? loanData; + bool isInstallation; + + InstallationFormView({Key? key, this.loanData, this.isInstallation = true}) : super(key: key); + + @override + _InstallationFormViewState createState() { + return _InstallationFormViewState(); + } +} + +class _InstallationFormViewState extends State { + final _formKey = GlobalKey(); + List _attachments = []; + + final LoanInstallationPullOutFormModel _formData = LoanInstallationPullOutFormModel(); + + @override + void initState() { + super.initState(); + _formData.loanId = widget.loanData?.id; + } + + @override + void dispose() { + super.dispose(); + } + + void updateTimer({TimerModel? timer}) { + if (timer?.startAt != null && timer?.endAt != null) { + final start = timer!.startAt!; + final end = timer.endAt!; + final difference = end.difference(start); + final totalHours = difference.inSeconds / 3600.0; + _formData.startTime = start; + _formData.endTime = end; + _formData.totalHours = totalHours; + } + + if (timer == null) { + _formData.startTime = null; + _formData.endTime = null; + _formData.totalHours = null; + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: DefaultAppBar(title: 'Installation Report'.addTranslation), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (widget.isInstallation) ...[ + AppTextFormField( + initialValue: "", + labelText: "Updates SN", + validator: (value) { + if ((value ?? "").isEmpty) return "Mandatory"; + return null; + }, + style: Theme.of(context).textTheme.titleMedium, + backgroundColor: AppColor.fieldBgColor(context), + labelStyle: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.textColor(context)), + showShadow: false, + textInputType: TextInputType.text, + textInputAction: TextInputAction.next, + onChange: (value) { + _formData.snNo = value; + }, + ), + 8.height, + ], + ADatePicker( + label: widget.isInstallation ? "Installation Date".addTranslation : "Validation Date".addTranslation, + hideShadow: true, + backgroundColor: AppColor.fieldBgColor(context), + to: DateTime.now().add(const Duration(days: 365)), + formatDateWithTime: true, + date: _formData.date, + onDatePicker: (DateTime date) async { + final time = await showTimePicker(context: context, initialTime: TimeOfDay.now()); + if (time == null) return; + setState(() { + _formData.date = DateTime(date.year, date.month, date.day, time.hour, time.minute); + }); + }, + ), + 8.height, + AppTimer( + label: context.translation.workingHours, + timer: _formData.timerModel, + // pickerFromDate: DateTime.tryParse(widget.createdDate ?? ''), + pickerFromDate: DateTime(DateTime.now().year, DateTime.now().month, 1), + pickerTimer: _formData.timerModel, + showTimer: false, + onPick: (timer) { + updateTimer(timer: timer); + }, + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.fieldBgColor(context), + borderRadius: BorderRadius.circular(10), + ), + timerProgress: (isRunning) {}, + onChange: (timer) async { + updateTimer(timer: timer); + return true; + }, + ), + ESignature( + title: 'End-user signature'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + oldSignature: '', + newSignature: _formData.signature, + onChange: (Uint8List signature) { + if (signature.isEmpty) return; + setState(() { + _formData.signature = signature; + }); + }, + ), + 24.height, + "Attachments".bodyText(context).custom(color: AppColor.black10), + 8.height, + AttachmentPicker( + label: context.translation.attachments, + attachment: _attachments, + buttonColor: AppColor.primary10, + onlyImages: false, + showAsListView: true, + buttonIcon: 'attachment_icon'.toSvgAsset(color: AppColor.primary10), + onChange: (attachments) { + _attachments = attachments; + setState(() {}); + }, + ), + ], + ).toShadowContainer(context, borderRadius: 20), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: context.translation.submitRequest, + onPressed: _submitForm, + ), + ), + ], + ), + ), + ); + } + + Future _submitForm() async { + if (!_formKey.currentState!.validate()) return; + if (_formData.date == null) { + "Please select installation date".showToast; + return; + } + if (_formData.startTime == null || _formData.endTime == null) { + "Please select start and end time".showToast; + return; + } + if (_formData.signature == null || _formData.signature!.isEmpty) { + "Signature is required".showToast; + return; + } + + _formData.loanAttachment = []; + + for (var item in _attachments) { + String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + _formData.loanAttachment!.add(LoanAttachments(id: 0, attachmentName: fileName, loanId: widget.loanData?.id)); + } + Utils.showLoading(context); + _formData.loanStatusId = widget.loanData?.loanStatusValue; + _formData.userId = context.userProvider.user?.userID; + LoanProvider incidentProvider = Provider.of(context, listen: false); + bool isSuccess = await incidentProvider.loanWorkflowAction(_formData.toInstallationJson()); + Utils.hideLoading(context); + if (isSuccess) { + Navigator.pop(context, true); + } + } +} diff --git a/lib/modules/loan_module/pages/installation_pullout_form_view.dart b/lib/modules/loan_module/pages/installation_pullout_form_view.dart index 11a3cbfd..6d60fb2d 100644 --- a/lib/modules/loan_module/pages/installation_pullout_form_view.dart +++ b/lib/modules/loan_module/pages/installation_pullout_form_view.dart @@ -1,16 +1,24 @@ +import 'dart:convert'; import 'dart:developer'; +import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/timer_model.dart'; +import 'package:test_sa/modules/cm_module/cm_request_utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; +import 'package:test_sa/modules/loan_module/models/loan_form_model.dart'; import 'package:test_sa/modules/loan_module/models/loan_installation_pullout_form_model.dart'; +import 'package:test_sa/modules/loan_module/models/loan_request_model.dart'; +import 'package:test_sa/modules/loan_module/provider/loan_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; @@ -21,10 +29,10 @@ import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/timer/app_timer.dart'; class InstallationPullOutFormView extends StatefulWidget { - final bool isPullout; final String? createdDate; + final LoanRequestModel? loanData; - const InstallationPullOutFormView({super.key, required this.isPullout, this.createdDate}); + const InstallationPullOutFormView({super.key, this.createdDate, this.loanData}); @override State createState() => _InstallationPullOutFormViewState(); @@ -34,7 +42,16 @@ class _InstallationPullOutFormViewState extends State(); final _snController = TextEditingController(); List _attachments = []; - final _formData = LoanInstallationPullOutFormModel(); + final LoanInstallationPullOutFormModel _formData = LoanInstallationPullOutFormModel(); + + @override + void initState() { + // TODO: implement initState + super.initState(); + _formData.loanId = widget.loanData?.id; + _formData.loanStatusId = widget.loanData?.loanStatusValue; + _formData.userId = context.userProvider.user?.userID; + } @override void dispose() { @@ -66,23 +83,6 @@ class _InstallationPullOutFormViewState extends State (v == null || v.isEmpty) ? 'Required' : null, - ), - 8.height, - ], - ADatePicker( - label: !widget.isPullout ? "Installation Date".addTranslation : "Validation Date".addTranslation, - hideShadow: true, - backgroundColor: AppColor.fieldBgColor(context), - to: DateTime.now().add(const Duration(days: 365)), - formatDateWithTime: true, - onDatePicker: _pickInstallationDate, - ), - 8.height, - AppTimer( - label: context.translation.workingHours, - timer: _formData.timerModel, - // pickerFromDate: DateTime.tryParse(widget.createdDate ?? ''), - pickerFromDate: DateTime(DateTime.now().year, DateTime.now().month, 1), - pickerTimer: _formData.timerModel, - showTimer: false, - onPick: (timer) { - updateTimer(timer: timer); - }, - width: double.infinity, - decoration: BoxDecoration( - color: AppColor.fieldBgColor(context), - borderRadius: BorderRadius.circular(10), - ), - timerProgress: (isRunning) {}, - onChange: (timer) async { - updateTimer(timer: timer); - return true; - }, - ), - ESignature( - title: 'End-user signature'.addTranslation, - backgroundColor: AppColor.fieldBgColor(context), - showShadow: false, - oldSignature: '', - newSignature: _formData.signature, - onChange: _onSignatureChanged, - ), - 24.height, - AttachmentPicker( - label: context.translation.attachments, - attachment: _attachments, + // appBar: DefaultAppBar(title: 'Pullout Report'.addTranslation), + body: Form( + key: _formKey, + child: Column( + children: [ + SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ADatePicker( + label: "Validation Date".addTranslation, + hideShadow: true, + backgroundColor: AppColor.fieldBgColor(context), + to: DateTime.now().add(const Duration(days: 365)), + formatDateWithTime: true, + date: _formData.date, + onDatePicker: (DateTime date) async { + final time = await showTimePicker(context: context, initialTime: TimeOfDay.now()); + if (time == null) return; + setState(() { + _formData.date = DateTime(date.year, date.month, date.day, time.hour, time.minute); + }); + }, + ), + // ADatePicker( + // label: !widget.isPullout ? "Installation Date".addTranslation : "Validation Date".addTranslation, + // hideShadow: true, + // backgroundColor: AppColor.fieldBgColor(context), + // to: DateTime.now().add(const Duration(days: 365)), + // formatDateWithTime: true, + // onDatePicker: _pickInstallationDate, + // ), + 8.height, + AppTimer( + label: context.translation.workingHours, + timer: _formData.timerModel, + // pickerFromDate: DateTime.tryParse(widget.createdDate ?? ''), + pickerFromDate: DateTime(DateTime.now().year, DateTime.now().month, 1), + pickerTimer: _formData.timerModel, + showTimer: false, + onPick: (timer) { + updateTimer(timer: timer); + }, + width: double.infinity, + decoration: BoxDecoration( + color: AppColor.fieldBgColor(context), + borderRadius: BorderRadius.circular(10), ), - ], - ).toShadowContainer(context, borderRadius: 20), - ).expanded, - FooterActionButton.footerContainer( - context: context, - child: AppFilledButton( - buttonColor: AppColor.primary10, - label: context.translation.submitRequest, - onPressed: _submitForm, - ), + timerProgress: (isRunning) {}, + onChange: (timer) async { + updateTimer(timer: timer); + return true; + }, + ), + ESignature( + title: 'End-user signature'.addTranslation, + backgroundColor: AppColor.fieldBgColor(context), + showShadow: false, + oldSignature: '', + newSignature: _formData.signature, + onChange: _onSignatureChanged, + ), + 24.height, + "Attachments".bodyText(context).custom(color: AppColor.black10), + 8.height, + AttachmentPicker( + label: context.translation.attachments, + attachment: _attachments, + buttonColor: AppColor.primary10, + onlyImages: false, + showAsListView: true, + buttonIcon: 'attachment_icon'.toSvgAsset(color: AppColor.primary10), + onChange: (attachments) { + _attachments = attachments; + setState(() {}); + }, + ), + // AttachmentPicker( + // label: context.translation.attachments, + // attachment: _attachments, + // ), + ], + ).toShadowContainer(context, borderRadius: 20), + ).expanded, + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + buttonColor: AppColor.primary10, + label: context.translation.submitRequest, + onPressed: _submitForm, ), - ], - ), + ), + ], ), ), ); } + + Future _submitForm() async { + if (!_formKey.currentState!.validate()) return; + if (_formData.date == null) { + "Please select Validation date".showToast; + return; + } + if (_formData.startTime == null || _formData.endTime == null) { + "Please select start and end time".showToast; + return; + } + if (_formData.signature == null || _formData.signature!.isEmpty) { + "Signature is required".showToast; + return; + } + + _formData.loanAttachment = []; + + for (var item in _attachments) { + String fileName = CMRequestUtils.isLocalUrl(item.name ?? '') ? ("${item.name ?? ''.split("/").last}|${base64Encode(File(item.name ?? '').readAsBytesSync())}") : item.name ?? ''; + _formData.loanAttachment!.add(LoanAttachments(id: 0, attachmentName: fileName, loanId: widget.loanData?.id)); + } + Utils.showLoading(context); + LoanProvider loanProvider = Provider.of(context, listen: false); + bool isSuccess = await loanProvider.loanWorkflowAction(_formData.toPulloutJson()); + Utils.hideLoading(context); + if (isSuccess) { + Navigator.pop(context, true); + } + } } diff --git a/lib/modules/loan_module/pages/intallation_details_view.dart b/lib/modules/loan_module/pages/intallation_details_view.dart index 67541c93..8bfd6e8b 100644 --- a/lib/modules/loan_module/pages/intallation_details_view.dart +++ b/lib/modules/loan_module/pages/intallation_details_view.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:test_sa/controllers/api_routes/urls.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/modules/cm_module/cm_request_utils.dart'; import 'package:test_sa/modules/loan_module/models/loan_request_model.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/images/files_list.dart'; @@ -16,72 +18,76 @@ class InstallationDetailsView extends StatelessWidget { @override Widget build(BuildContext context) { + String workingTime = "-"; + + if (loanData.startTime != null && loanData.endTime != null) { + try { + final timeFormat = DateFormat('h:mm a'); // Matches "3:00 PM" format + final now = DateTime.now(); + + final start = timeFormat.parse(loanData.startTime!); + var end = timeFormat.parse(loanData.endTime!); + + // Set the date to today for both times + var startDateTime = DateTime(now.year, now.month, now.day, start.hour, start.minute); + var endDateTime = DateTime(now.year, now.month, now.day, end.hour, end.minute); + + // If end time is before start time, shift crossed midnight + if (endDateTime.isBefore(startDateTime)) { + endDateTime = endDateTime.add(const Duration(days: 1)); + } + + double totalWorkingTime = endDateTime.difference(startDateTime).inSeconds / 3600.0; + } catch (ex) {} + } + + // if (loanData.startTime != null && loanData.endTime != null) { + // final start = DateTime.parse(loanData.startTime!); + // var end = DateTime.parse(loanData.endTime!); + // + // // If end time is before start time, it means the shift crossed midnight + // if (end.isBefore(start)) { + // end = end.add(const Duration(days: 1)); + // } + // + // double totalWorkingTime = end.difference(start).inSeconds / 3600.0; + // workingTime = CMRequestUtils.formatTotalWorkingHours(totalWorkingTime); + // } + + // if (loanData.startTime != null && loanData.endTime != null) { + // final start = DateTime.parse(loanData.startTime!); + // final end = DateTime.parse(loanData.endTime!); + // double totalWorkingTime = end.difference(start).inSeconds / 3600.0; + // workingTime = CMRequestUtils.formatTotalWorkingHours(totalWorkingTime); + // } + return Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - detailContent( - context: context, - heading: 'Updates SN:', - label: loanData.installationDate??'-' - ), - detailContent( - context: context, - heading: 'Installation Date', - label: loanData.installationDate??'-' - ), - ], - ), - 12.height, - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - detailContent( - context: context, - heading: 'Start Time', - label: loanData.installationDate??'-' - ), - detailContent( - context: context, - heading: 'End Time', - label: loanData.installationDate??'-' - ), - ], - ), - 12.height, - detailContent( - context: context, - heading: 'Total Time', - label: loanData.installationDate??'-' + Text( + "Installation Details".addTranslation, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), + 4.height, + 'Updates SN: ${loanData.assetSerialNumber ?? "-"}'.bodyText(context), + 'Installation Date: ${loanData.installationDate?.toAssetDetailsFormat ?? "-"}'.bodyText(context), + 'Start Time: ${loanData.startTime ?? "-"}'.bodyText(context), + 'End Time: ${loanData.endTime ?? "-"}'.bodyText(context), + 'Total Working Time: $workingTime'.bodyText(context), if (loanData.loanAttachments!.isNotEmpty) ...[ 12.height, Text( "Uploads Phase 2 docs".addTranslation, - style: AppTextStyles.bodyText.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), 8.height, - FilesList(images: loanData.loanAttachments?.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), + FilesList(showAsListView: true, images: loanData.loanAttachments?.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), ], ], ).toShadowContainer(context, borderRadius: 20), ); } - - Widget detailContent({required BuildContext context, required String label, required String heading}) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - heading.bodyText(context).custom(color: AppColor.neutral120), - 6.height, - //TODO Need to check which value need to show here - label.bodyText(context).custom(color: AppColor.neutral120), - ], - ); - } } diff --git a/lib/modules/loan_module/pages/loan_equipment_detail_page.dart b/lib/modules/loan_module/pages/loan_equipment_detail_page.dart index 2a5dd42a..5abb9118 100644 --- a/lib/modules/loan_module/pages/loan_equipment_detail_page.dart +++ b/lib/modules/loan_module/pages/loan_equipment_detail_page.dart @@ -6,12 +6,15 @@ import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/helper/utils.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/loan_module/models/loan_attachment_model.dart'; +import 'package:test_sa/modules/loan_module/pages/installation_form_view.dart'; import 'package:test_sa/modules/loan_module/pages/pullout_detail_page.dart'; import 'package:test_sa/modules/loan_module/provider/loan_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; +import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; @@ -20,95 +23,165 @@ import 'package:test_sa/views/widgets/requests/request_status.dart'; import '../models/loan_request_model.dart'; import 'installation_pullout_form_view.dart'; -class LoanEquipmentDetailPage extends StatelessWidget { +class LoanEquipmentDetailPage extends StatefulWidget { static const String id = "/loan-equipment-detail-page"; final int loanId; LoanEquipmentDetailPage({Key? key, required this.loanId}) : super(key: key); + @override + _LoanEquipmentDetailPageState createState() { + return _LoanEquipmentDetailPageState(); + } +} + +class _LoanEquipmentDetailPageState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + @override Widget build(BuildContext context) { return Scaffold( - appBar: const DefaultAppBar(title: "Request Details"), - body: SafeArea( - child: FutureBuilder( - future: Provider.of(context, listen: false).getLoanById(loanId), - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) return const CircularProgressIndicator(color: AppColor.primary10).center; - if (snapshot.data == null) return const NoDataFound().center; + appBar: const DefaultAppBar(title: "Request Details"), + body: FutureBuilder( + future: Provider.of(context, listen: false).getLoanById(widget.loanId), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) return const CircularProgressIndicator(color: AppColor.primary10).center; + if (snapshot.data == null) return const NoDataFound().center; - List allAttachments = snapshot.data!.loanAttachments!; + List allAttachments = snapshot.data!.loanAttachments!; - return Column( + return Column( + children: [ + ListView( + padding: const EdgeInsets.all(16), children: [ - ListView( - padding: const EdgeInsets.all(16), - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - StatusLabel( - label: snapshot.data!.loanStatusName!, - textColor: AppColor.getRequestStatusTextColorByName(context, snapshot.data!.loanStatusName!), - backgroundColor: AppColor.getRequestStatusColorByName(context, snapshot.data!.loanStatusName!), - ), - 1.width.expanded, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StatusLabel( + label: snapshot.data!.loanStatusName!, + textColor: AppColor.getRequestStatusTextColorByName(context, snapshot.data!.loanStatusName!), + backgroundColor: AppColor.getRequestStatusColorByName(context, snapshot.data!.loanStatusName!), + ), + 1.width.expanded, + Text( + snapshot.data!.createdDate?.toServiceRequestCardFormat ?? "-", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + ), + ], + ), + 12.height, + ...requesterDetails(context, snapshot.data!), + const Divider().defaultStyle(context), + ...requestDetails(context, snapshot.data!), + const Divider().defaultStyle(context), + ...assetDetails(context, snapshot.data!), + const Divider().defaultStyle(context), + ...installationDetails(context, snapshot.data!), + const Divider().defaultStyle(context), + ...doctorDetails(context, snapshot.data!), + const Divider().defaultStyle(context), + ...vendorDetails(context, snapshot.data!), + if (allAttachments.isNotEmpty) ...[ + const Divider().defaultStyle(context), Text( - snapshot.data!.createdDate?.toServiceRequestCardFormat ?? "-", - textAlign: TextAlign.end, - style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50), + "Attachments".addTranslation, + style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), ), + FilesList(images: allAttachments.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), ], - ), - 12.height, - ...requesterDetails(context, snapshot.data!), - const Divider().defaultStyle(context), - ...requestDetails(context, snapshot.data!), - const Divider().defaultStyle(context), - ...assetDetails(context, snapshot.data!), - const Divider().defaultStyle(context), - ...installationDetails(context, snapshot.data!), - const Divider().defaultStyle(context), - ...doctorDetails(context, snapshot.data!), - const Divider().defaultStyle(context), - ...vendorDetails(context, snapshot.data!), - if (allAttachments.isNotEmpty) ...[ - const Divider().defaultStyle(context), - Text( - "Attachments".addTranslation, - style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), - ), - FilesList(images: allAttachments.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []), ], - ], - ).toShadowContainer(context, padding: 12), - ], - ).expanded, - // if (context.userProvider.isEngineer && (snapshot.data?.loanStatusValue == 5 || snapshot.data?.loanStatusValue == 8)) - // FooterActionButton.footerContainer( - // context: context, - // child: AppFilledButton( - // onPressed: () async { - // if (snapshot.data?.loanStatusValue == 5) { - // Navigator.push( - // context, - // MaterialPageRoute( - // builder: (context) => PullOutDetailsPage( - // loanData: snapshot.data, - // ))); - // return; - // } - // Navigator.push(context, MaterialPageRoute(builder: (context) => const InstallationPullOutFormView(isPullout: false))); - // }, - // label: snapshot.data?.loanStatusValue == 5 ? 'Installation Report' : 'PullOut Report', - // ), - // ) + ).toShadowContainer(context, padding: 12), + ], + ).expanded, + // @todo ask backend to add loanTypeValue, so we can show or hide the buttons + if (snapshot.data?.loanTypeName == "Standard" && + context.userProvider.isEngineer && + (snapshot.data?.loanStatusValue == 4 || snapshot.data?.loanStatusValue == 5 || snapshot.data?.loanStatusValue == 8)) + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + onPressed: () async { + if (snapshot.data?.loanStatusValue == 4) { + String comment = ""; + context.showBottomSheet( + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + 'Estimated Date: ${snapshot.data?.installationEDD?.toAssetDetailsFormat ?? "-"}'.bodyText(context), + 16.height, + AppTextFormField( + labelText: context.translation.comments, + showSpeechToText: true, + textInputType: TextInputType.multiline, + labelStyle: AppTextStyles.textFieldLabelStyle, + showWithoutDecoration: true, + backgroundColor: context.isDarkNotListen ? AppColor.neutral20 : AppColor.neutral100, + alignLabelWithHint: true, + onChange: (text) { + comment = text; + }, + ), + 16.height, + AppFilledButton( + onPressed: () async { + Utils.showLoading(context); + LoanProvider loanProvider = Provider.of(context, listen: false); + bool isSuccess = await loanProvider.loanWorkflowAction({ + "userId": context.userProvider.user!.userID, + "isFromMobile": true, + "commentsFromMobile": comment, + 'loanId': snapshot.data?.id, + 'loanStatusId': snapshot.data?.loanStatusValue, + }); + Utils.hideLoading(context); + if (isSuccess) { + Navigator.pop(context, true); + setState(() {}); + } + }, + label: "Delivered"), + ], + ), + title: "EDD & Comments", + showCancelButton: true); + return; + } + if (snapshot.data?.loanStatusValue == 5) { + bool isSuccess = await Navigator.push(context, MaterialPageRoute(builder: (context) => InstallationFormView(loanData: snapshot.data))) ?? false; + if (isSuccess) { + setState(() {}); + } + return; + } + bool isSuccess = await Navigator.push(context, MaterialPageRoute(builder: (context) => PullOutDetailsPage(loanData: snapshot.data))) ?? false; + if (isSuccess) { + setState(() {}); + } + }, + label: snapshot.data?.loanStatusValue == 4 + ? "Delivered" + : snapshot.data?.loanStatusValue == 5 + ? 'Installation Report' + : 'PullOut Report', + ), + ) ]); - }), - )); + // }), + })); } List requestDetails(BuildContext context, LoanRequestModel loanData) { diff --git a/lib/modules/loan_module/pages/pullout_detail_page.dart b/lib/modules/loan_module/pages/pullout_detail_page.dart index 09b81048..9992ba8c 100644 --- a/lib/modules/loan_module/pages/pullout_detail_page.dart +++ b/lib/modules/loan_module/pages/pullout_detail_page.dart @@ -10,29 +10,17 @@ import 'package:test_sa/modules/loan_module/pages/intallation_details_view.dart' import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; -class PullOutDetailsPage extends StatefulWidget { +class PullOutDetailsPage extends StatelessWidget { final LoanRequestModel? loanData; PullOutDetailsPage({Key? key, required this.loanData}) : super(key: key); - @override - _PullOutDetailsPageState createState() { - return _PullOutDetailsPageState(); - } -} - -class _PullOutDetailsPageState extends State { - @override - void dispose() { - super.dispose(); - } - @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Theme.of(context).scaffoldBackgroundColor, appBar: DefaultAppBar( - title: 'Loan Request'.addTranslation, + title: 'Pullout Report'.addTranslation, ), body: DefaultTabController( length: 2, @@ -61,16 +49,15 @@ class _PullOutDetailsPageState extends State { ], ), ), - 12.height, + 0.height, TabBarView( children: [ - Align( - alignment: Alignment.topCenter, - child: InstallationDetailsView( - loanData: widget.loanData!, - ), + Column( + children: [ + InstallationDetailsView(loanData: loanData!), + ], ), - const InstallationPullOutFormView(isPullout: true), + InstallationPullOutFormView(loanData: loanData!), ], ).expanded, ], diff --git a/lib/modules/loan_module/provider/loan_provider.dart b/lib/modules/loan_module/provider/loan_provider.dart index 01153eef..d3ea225b 100644 --- a/lib/modules/loan_module/provider/loan_provider.dart +++ b/lib/modules/loan_module/provider/loan_provider.dart @@ -48,4 +48,16 @@ class LoanProvider extends ChangeNotifier { } return loanData; } + + Future loanWorkflowAction(Map body) async { + try { + Response response = await ApiManager.instance.post(URLs.loanWorkflowAction, body: body, showToast: true); + if (response.statusCode >= 200 && response.statusCode < 300) { + return true; + } + return false; + } catch (error) { + return false; + } + } } diff --git a/lib/modules/tm_module/tasks/update_task_request_view.dart b/lib/modules/tm_module/tasks/update_task_request_view.dart index 72fd8ab3..141ac7c0 100644 --- a/lib/modules/tm_module/tasks/update_task_request_view.dart +++ b/lib/modules/tm_module/tasks/update_task_request_view.dart @@ -156,7 +156,7 @@ class _UpdateTaskRequestState extends State { recallAlertTypeWidget(taskModel: taskProvider.taskRequestModel!), ], //Not good approach need to use enums .... - if (taskProvider.taskRequestModel?.taskType?.typeName == "PullOut") ...[ + if (taskProvider.taskRequestModel?.taskType?.isSignatureRequired ?? false) ...[ ESignature( title: "End-user signature", backgroundColor: AppColor.fieldBgColor(context), @@ -262,7 +262,7 @@ class _UpdateTaskRequestState extends State { taskAttachment.add(TaskJobAttachment(id: item.id, name: fileName)); } taskModel.taskJobAttachments = taskAttachment; - + taskModel.taskJobActivityEngineerTimers = []; if (taskModel.taskTimePicker != null) { int durationInSecond = taskModel.taskTimePicker!.endAt!.difference(taskModel.taskTimePicker!.startAt!).inSeconds; taskModel.taskJobActivityEngineerTimers?.add( diff --git a/lib/views/pages/user/notifications/unread_chat_list.dart b/lib/views/pages/user/notifications/unread_chat_list.dart new file mode 100644 index 00000000..ed82f2f7 --- /dev/null +++ b/lib/views/pages/user/notifications/unread_chat_list.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:test_sa/controllers/notification/firebase_notification_manger.dart'; +import 'package:test_sa/extensions/context_extension.dart'; +import 'package:test_sa/extensions/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; +import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; +import 'package:test_sa/modules/cx_module/chat/model/unread_message_model.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/extensions/string_extensions.dart'; +import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; + +class UnReadChatList extends StatelessWidget { + UnReadChatList({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: const DefaultAppBar(title: "Unread Messages"), + body: FutureBuilder>( + future: Provider.of(context, listen: false).getUnReadMessages(context.userProvider.user!.employeeId ?? context.userProvider.user!.username!), + builder: (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) return const CircularProgressIndicator(color: AppColor.primary10).center; + if (snapshot.data?.isEmpty ?? true) return const NoDataFound().center; + + List messages = snapshot.data!; + + return SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.all(0), + itemCount: messages.length, + separatorBuilder: (context, itemIndex) => const Divider().defaultStyle(context), + itemBuilder: (context, index) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + messages[index].senderUserName ?? "", + style: AppTextStyles.bodyText.copyWith( + color: context.isDark ? AppColor.neutral30 : AppColor.neutral50, + ), + ).expanded, + 8.width, + Text( + messages[index].createdAt?.toServiceRequestCardFormat ?? "", + textAlign: TextAlign.right, + style: AppTextStyles.tinyFont.copyWith( + color: context.isDark ? AppColor.neutral20 : AppColor.neutral50, + ), + ), + ], + ), + Text( + messages[index].content ?? "", + style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral10 : const Color(0xFF757575)), + ), + ], + ).onPress(() { + FirebaseNotificationManger.handleMessage(context, { + "transactionType": "17", + "requestType": "chat", + "moduleId": messages[index].moduleCode, + "requestNumber": messages[index].referenceId, + }); + }); + }, + ).toShadowContainer(context), + ); + })); + } +}