loan improvements

design_3.0_loan_module
Sikander Saleem 2 days ago
parent 35e494863f
commit 67da263e0d

@ -393,4 +393,5 @@ class URLs {
static get getLoanByWorkOrderId => '$_baseUrl/Loan/GetLoanByWorkOrderId';
static get addLoan => '$_baseUrl/Loan/AddLoan';
static get loanWorkflowAction => '$_baseUrl/Loan/LoanWorkflowAction';
}

@ -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<String, dynamic> json) {
print('created by here is ${json['createdBy']}');
id = json['id'];
@ -23,4 +24,4 @@ class GenericAttachmentModel {
data['originalName'] = originalName;
return data;
}
}
}

@ -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'];

@ -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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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,
};
}
}

@ -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;

@ -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<InstallationFormView> {
final _formKey = GlobalKey<FormState>();
List<GenericAttachmentModel> _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<void> _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<LoanProvider>(context, listen: false);
bool isSuccess = await incidentProvider.loanWorkflowAction(_formData.toInstallationJson());
Utils.hideLoading(context);
if (isSuccess) {
Navigator.pop(context, true);
}
}
}

@ -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<InstallationPullOutFormView> createState() => _InstallationPullOutFormViewState();
@ -34,7 +42,16 @@ class _InstallationPullOutFormViewState extends State<InstallationPullOutFormVie
final _formKey = GlobalKey<FormState>();
final _snController = TextEditingController();
List<GenericAttachmentModel> _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<InstallationPullOutFormVie
});
}
void _submitForm() {
if (!_formKey.currentState!.validate()) return;
//Validation if required .
// if (_formData.date == null) {
// context.showSnackBar('Please select installation date');
// return;
// }
//
// if (_formData.signature == null || _formData.signature!.isEmpty) {
// context.showSnackBar('Signature is required');
// return;
// }
_formData.snNo = _snController.text;
}
void updateTimer({TimerModel? timer}) {
if (timer?.startAt != null && timer?.endAt != null) {
final start = timer!.startAt!;
@ -98,90 +98,132 @@ class _InstallationPullOutFormViewState extends State<InstallationPullOutFormVie
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: widget.isPullout ? null : DefaultAppBar(title: 'Installation Report'.addTranslation),
body: SafeArea(
child: Form(
key: _formKey,
child: Column(
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (!widget.isPullout) ...[
AppTextFormField(
controller: _snController,
labelText: context.translation.snNo,
backgroundColor: AppColor.fieldBgColor(context),
textAlign: TextAlign.center,
labelStyle: AppTextStyles.textFieldLabelStyle,
hintStyle: AppTextStyles.textFieldLabelStyle,
textInputType: TextInputType.text,
textInputAction: TextInputAction.next,
showShadow: false,
validator: (v) => (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<void> _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<LoanProvider>(context, listen: false);
bool isSuccess = await incidentProvider.loanWorkflowAction(_formData.toPulloutJson());
Utils.hideLoading(context);
if (isSuccess) {
Navigator.pop(context, true);
}
}
}

@ -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),
],
);
}
}

@ -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<LoanEquipmentDetailPage> {
@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<LoanRequestModel?>(
future: Provider.of<LoanProvider>(context, listen: false).getLoanById(loanId),
builder: (BuildContext context, AsyncSnapshot<LoanRequestModel?> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) return const CircularProgressIndicator(color: AppColor.primary10).center;
if (snapshot.data == null) return const NoDataFound().center;
List<LoanAttachmentModel> 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<LoanRequestModel?>(
future: Provider.of<LoanProvider>(context, listen: false).getLoanById(widget.loanId),
builder: (BuildContext context, AsyncSnapshot<LoanRequestModel?> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) return const CircularProgressIndicator(color: AppColor.primary10).center;
if (snapshot.data == null) return const NoDataFound().center;
List<LoanAttachmentModel> 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<Widget> 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<Widget> 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<Widget> 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<Widget> 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<Widget> 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<Widget> 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),

@ -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<PullOutDetailsPage> {
@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<PullOutDetailsPage> {
],
),
),
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,
],

@ -48,4 +48,16 @@ class LoanProvider extends ChangeNotifier {
}
return loanData;
}
Future<bool> loanWorkflowAction(Map<String, dynamic> 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;
}
}
}

Loading…
Cancel
Save