diff --git a/lib/controllers/api_routes/urls.dart b/lib/controllers/api_routes/urls.dart index f4bf299a..c66150e9 100644 --- a/lib/controllers/api_routes/urls.dart +++ b/lib/controllers/api_routes/urls.dart @@ -393,4 +393,5 @@ class URLs { static get getLoanByWorkOrderId => '$_baseUrl/Loan/GetLoanByWorkOrderId'; static get addLoan => '$_baseUrl/Loan/AddLoan'; + static get loanWorkflowAction => '$_baseUrl/Loan/LoanWorkflowAction'; } diff --git a/lib/models/generic_attachment_model.dart b/lib/models/generic_attachment_model.dart index 1d3cd5ea..821bcb59 100644 --- a/lib/models/generic_attachment_model.dart +++ b/lib/models/generic_attachment_model.dart @@ -1,12 +1,13 @@ import 'dart:io'; class GenericAttachmentModel { - GenericAttachmentModel({this.id, this.name,this.originalName,this.createdBy}); + GenericAttachmentModel({this.id, this.name, this.originalName, this.createdBy}); int? id; String? name; - String ?createdBy; + String? createdBy; String? originalName; + GenericAttachmentModel.fromJson(Map json) { print('created by here is ${json['createdBy']}'); id = json['id']; @@ -23,4 +24,4 @@ class GenericAttachmentModel { data['originalName'] = originalName; return data; } -} \ No newline at end of file +} 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..ca70faa3 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 incidentProvider = Provider.of(context, listen: false); + bool isSuccess = await incidentProvider.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 8506292c..2b1175aa 100644 --- a/lib/modules/loan_module/pages/loan_equipment_detail_page.dart +++ b/lib/modules/loan_module/pages/loan_equipment_detail_page.dart @@ -8,6 +8,7 @@ import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.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'; @@ -20,101 +21,118 @@ 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; - - List allAttachments = snapshot.data!.loanAttachments!; - - return Column( - 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, - 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!), - 12.height, - ...requestDetails(context, snapshot.data!), - 12.height, - ...assetDetails(context, snapshot.data!), - 12.height, - ...installationDetails(context, snapshot.data!), - 12.height, - ...doctorDetails(context, snapshot.data!), - 12.height, - ...vendorDetails(context, snapshot.data!), - if (allAttachments.isNotEmpty) ...[ - const Divider().defaultStyle(context), + 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!; + + return Column( + 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, Text( - "Attachments".addTranslation, - style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), + snapshot.data!.createdDate?.toServiceRequestCardFormat ?? "-", + textAlign: TextAlign.end, + style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : 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 == 5 || snapshot.data?.loanStatusValue == 8)) + FooterActionButton.footerContainer( + context: context, + child: AppFilledButton( + onPressed: () async { + 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 == 5 ? 'Installation Report' : 'PullOut Report', + ), + ) + ], + ); + })); } List requestDetails(BuildContext context, LoanRequestModel loanData) { return [ - Text("Request Details", style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + Text("Request Details", style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), 'Loan Type: ${loanData.loanTypeName ?? "-"}'.bodyText(context), 'Loan No: ${loanData.reqCode ?? "-"}'.bodyText(context), 'Loan Period: ${loanData.loanPeriodName ?? "-"}'.bodyText(context), @@ -127,7 +145,7 @@ class LoanEquipmentDetailPage extends StatelessWidget { List vendorDetails(BuildContext context, LoanRequestModel loanData) { return [ - Text("Vendor Information", style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + Text("Vendor Information", style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), 'Name: ${loanData.vendorName ?? "-"}'.bodyText(context), 'Representative Name: ${loanData.vendorRepName ?? "-"}'.bodyText(context), 'Contact: ${loanData.vendorContact ?? "-"}'.bodyText(context), @@ -137,7 +155,7 @@ class LoanEquipmentDetailPage extends StatelessWidget { List assetDetails(BuildContext context, LoanRequestModel loanData) { return [ - Text("Asset Information", style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + Text("Asset Information", style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), '${context.translation.assetName}: ${loanData.assetName ?? "-"}'.bodyText(context), '${context.translation.assetNo}: ${loanData.assetNumber ?? "-"}'.bodyText(context), '${context.translation.serialNumber}: ${loanData.assetSerialNumber ?? "-"}'.bodyText(context), @@ -148,7 +166,7 @@ class LoanEquipmentDetailPage extends StatelessWidget { List installationDetails(BuildContext context, LoanRequestModel loanData) { return [ - Text("Installation & Pullout Information", style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + Text("Installation & Pullout Information", style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), 'Installation EDD: ${loanData.installationEDD?.toServiceRequestDetailsFormat ?? "-"}'.bodyText(context), 'Installation Date: ${loanData.installationEDD?.toAssetDetailsFormat ?? "-"}'.bodyText(context), 'Pullout EDD: ${loanData.pulloutEDD?.toServiceRequestDetailsFormat ?? "-"}'.bodyText(context), @@ -158,7 +176,7 @@ class LoanEquipmentDetailPage extends StatelessWidget { List doctorDetails(BuildContext context, LoanRequestModel loanData) { return [ - Text("Doctor Information", style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + Text("Doctor Information", style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), 'Name: ${loanData.doctorName ?? "-"}'.bodyText(context), 'Contact: ${loanData.doctorContact ?? "-"}'.bodyText(context), 'Email: ${loanData.doctorEmail ?? "-"}'.bodyText(context), @@ -167,7 +185,7 @@ class LoanEquipmentDetailPage extends StatelessWidget { List requesterDetails(BuildContext context, LoanRequestModel loanData) { return [ - Text("Requester Information", style: AppTextStyles.heading4.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), + Text("Requester Information", style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50)), 'Name: ${loanData.requestorUserIdForDisplay ?? "-"}'.bodyText(context), 'Email: ${loanData.requestorUserEmail ?? "-"}'.bodyText(context), 'Contact: ${loanData.requestorUserMobileNumber ?? "-"}'.bodyText(context), 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; + } + } }