Merge branch 'design_3.0_loan_module' into design_3.0_demo_module

# Conflicts:
#	lib/controllers/api_routes/urls.dart
#	lib/models/generic_attachment_model.dart
#	lib/modules/loan_module/pages/loan_equipment_detail_page.dart
design_3.0_demo_module
Sikander Saleem 1 day ago
commit 2e3736cdc9

@ -19,6 +19,7 @@ class URLs {
static const String chatHubUrlApi = "$chatHubUrl/api"; // new V2 apis static const String chatHubUrlApi = "$chatHubUrl/api"; // new V2 apis
static const String chatHubUrlChat = "$chatHubUrl/hubs/chat"; // 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 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 const String chatApiKey = "f53a98286f82798d588f67a7f0db19f7aebc839e"; // new V2 apis
static String _host = host1; static String _host = host1;
@ -421,6 +422,7 @@ class URLs {
static get getOvrTicketDetails => '$_baseUrl/Incident/GetOvrTicketDetails'; static get getOvrTicketDetails => '$_baseUrl/Incident/GetOvrTicketDetails';
static get addLoan => '$_baseUrl/Loan/AddLoan'; static get addLoan => '$_baseUrl/Loan/AddLoan';
static get loanWorkflowAction => '$_baseUrl/Loan/LoanWorkflowAction';
static get addIncident => '$_baseUrl/Incident/AddIncident'; static get addIncident => '$_baseUrl/Incident/AddIncident';
static get addDemoTrialOutcome => '$_baseUrl/DemoRequest/addDemoTrialOutcome'; static get addDemoTrialOutcome => '$_baseUrl/DemoRequest/addDemoTrialOutcome';

@ -1,3 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/api_manager.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/helper/utils.dart';
import 'package:test_sa/new_views/app_style/app_color.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/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 'package:test_sa/views/widgets/dialogs/confirm_dialog.dart';
import '../../controllers/providers/api/user_provider.dart'; import '../../controllers/providers/api/user_provider.dart';
@ -127,6 +129,12 @@ class AppBarWidget extends StatelessWidget {
); );
}), }),
16.width, 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( Stack(
alignment: Alignment.topRight, alignment: Alignment.topRight,
children: [ children: [

@ -42,12 +42,12 @@ extension BuildContextExtension on BuildContext {
builder: (BuildContext cxt) => InfoDialog(message: message, onTap: onTap, title: title, okTitle: okTitle, content: content), 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, context: this,
useSafeArea: true, useSafeArea: true,
isScrollControlled: true, isScrollControlled: true,
isDismissible: true, isDismissible: true,
backgroundColor: Colors.transparent, 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),
); );
} }

@ -23,7 +23,7 @@ extension TextStyles on String {
Text heading6(BuildContext context) => getTextWithStyle(this, AppTextStyles.heading6, context.isDark ? AppColor.neutral30 : AppColor.neutral50); 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); Text bodyText2(BuildContext context) => getTextWithStyle(this, AppTextStyles.bodyText2, context.isDark ? AppColor.neutral10 : AppColor.neutral20);

@ -145,7 +145,7 @@ extension WidgetExtensions on Widget {
child: this, 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, clipBehavior: Clip.antiAlias,
margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -164,7 +164,21 @@ extension WidgetExtensions on Widget {
).center, ).center,
16.height, 16.height,
if (title != null) ...[ 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, 16.height,
], ],
this this

@ -491,6 +491,7 @@ class TaskTypeModel {
final List<dynamic>? taskTypeRoles; final List<dynamic>? taskTypeRoles;
final bool? isInstallation; final bool? isInstallation;
final bool? isRecallAndAlert; final bool? isRecallAndAlert;
final bool? isSignatureRequired;
TaskTypeModel({ TaskTypeModel({
this.id, this.id,
@ -500,6 +501,7 @@ class TaskTypeModel {
this.taskTypeRoles, this.taskTypeRoles,
this.isInstallation, this.isInstallation,
this.isRecallAndAlert, this.isRecallAndAlert,
this.isSignatureRequired,
}); });
factory TaskTypeModel.fromJson(Map<String, dynamic> json) => TaskTypeModel( factory TaskTypeModel.fromJson(Map<String, dynamic> json) => TaskTypeModel(
@ -510,6 +512,7 @@ class TaskTypeModel {
taskTypeRoles: json['taskTypeRoles'], taskTypeRoles: json['taskTypeRoles'],
isInstallation: json['isInstallation'], isInstallation: json['isInstallation'],
isRecallAndAlert: json['isRecallAndAlert'], isRecallAndAlert: json['isRecallAndAlert'],
isSignatureRequired: json['isSignatureRequired'],
); );
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
@ -520,6 +523,7 @@ class TaskTypeModel {
'taskTypeRoles': taskTypeRoles, 'taskTypeRoles': taskTypeRoles,
'isInstallation': isInstallation, 'isInstallation': isInstallation,
'isRecallAndAlert': isRecallAndAlert, 'isRecallAndAlert': isRecallAndAlert,
'isSignatureRequired': isSignatureRequired,
}; };
} }

@ -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:uuid/uuid.dart';
import 'package:flutter/material.dart' as Material; import 'package:flutter/material.dart' as Material;
import 'api_client.dart';
import 'chat_api_client.dart'; import 'chat_api_client.dart';
import 'model/chat_attachment_model.dart'; import 'model/chat_attachment_model.dart';
import 'model/chat_participant_model.dart'; import 'model/chat_participant_model.dart';
import 'model/get_search_user_chat_model.dart'; import 'model/get_search_user_chat_model.dart';
import 'model/get_single_user_chat_list_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 'model/user_chat_history_model.dart';
// import 'get_single_user_chat_list_model.dart'; // import 'get_single_user_chat_list_model.dart';
@ -454,6 +456,25 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
return result; return result;
} }
Future<List<UnReadMessage>> 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<Object?>? args) { // void updateUserChatStatus(List<Object?>? args) {
// dynamic items = args!.toList(); // dynamic items = args!.toList();
// for (var cItem in items[0]) { // for (var cItem in items[0]) {
@ -616,7 +637,6 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
} }
} }
Future<void> onAckSeenAsync(List<Object?>? parameters) async { Future<void> onAckSeenAsync(List<Object?>? parameters) async {
try { try {
if (parameters == null || parameters.isEmpty) { if (parameters == null || parameters.isEmpty) {

@ -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<String, dynamic> 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<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
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;
}
}

@ -30,7 +30,7 @@ class LoanFormModel {
LoanFormModel({ LoanFormModel({
this.docName, this.docName,
this.isNewVendor=false, this.isNewVendor = false,
this.docNumber, this.docNumber,
this.docEmail, this.docEmail,
this.itemDescription, this.itemDescription,
@ -118,7 +118,9 @@ class LoanAttachments {
num? loanId; num? loanId;
String? attachmentName; String? attachmentName;
String? attachmentDescription; String? attachmentDescription;
LoanAttachments({this.id, this.loanAttachmentTypeId, this.attachmentName, this.loanId, this.attachmentDescription}); LoanAttachments({this.id, this.loanAttachmentTypeId, this.attachmentName, this.loanId, this.attachmentDescription});
LoanAttachments.fromJson(dynamic json) { LoanAttachments.fromJson(dynamic json) {
id = json['id']; id = json['id'];
loanAttachmentTypeId = json['loanAttachmentTypeId']; loanAttachmentTypeId = json['loanAttachmentTypeId'];

@ -13,6 +13,9 @@ class LoanInstallationPullOutFormModel {
DateTime? startTime; DateTime? startTime;
DateTime? endTime; DateTime? endTime;
double? totalHours; double? totalHours;
int? loanId;
String? userId;
int? loanStatusId;
LoanInstallationPullOutFormModel({ LoanInstallationPullOutFormModel({
this.loanAttachment, this.loanAttachment,
@ -23,18 +26,71 @@ class LoanInstallationPullOutFormModel {
this.startTime, this.startTime,
this.endTime, this.endTime,
this.totalHours, this.totalHours,
this.loanId,
this.loanStatusId,
this.userId,
}); });
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
//Need to check payload parm they need //Need to check payload parm they need
return { return {
'snNo': snNo, // 'snNo': snNo,
'InstallationDate': date?.toIso8601String(), 'serialNumber': snNo,
'installationDate': date?.toIso8601String(),
'pulloutDate': date?.toIso8601String(),
"loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [], "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, "signature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null,
"pulloutSignature": signature != null ? "${DateTime.now().toIso8601String()}.png|${base64Encode(signature!)}" : null,
'startTime': startTime?.toIso8601String(), 'startTime': startTime?.toIso8601String(),
'endTime': endTime?.toIso8601String(), 'endTime': endTime?.toIso8601String(),
'totalHours': totalHours, '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? pulloutWOItemId;
int? id; int? id;
String? installationDate; String? installationDate;
String? startTime;
String? endTime;
String? pulloutDate; String? pulloutDate;
String? createdBy; String? createdBy;
String? createdDate; String? createdDate;
@ -114,6 +116,8 @@ class LoanRequestModel {
this.id, this.id,
this.createdBy, this.createdBy,
this.installationDate, this.installationDate,
this.startTime,
this.endTime,
this.pulloutDate, this.pulloutDate,
this.createdDate, this.createdDate,
this.modifiedBy, this.modifiedBy,
@ -177,6 +181,8 @@ class LoanRequestModel {
pulloutWOItemId = json['pulloutWOItemId']; pulloutWOItemId = json['pulloutWOItemId'];
id = json['id']; id = json['id'];
installationDate = json['installationDate']; installationDate = json['installationDate'];
startTime = json['startTime'];
endTime = json['endTime'];
pulloutDate = json['pulloutDate']; pulloutDate = json['pulloutDate'];
createdBy = json['createdBy']; createdBy = json['createdBy'];
createdDate = json['createdDate']; createdDate = json['createdDate'];
@ -239,6 +245,8 @@ class LoanRequestModel {
data['pulloutWOItemId'] = this.pulloutWOItemId; data['pulloutWOItemId'] = this.pulloutWOItemId;
data['id'] = this.id; data['id'] = this.id;
data['installationDate'] = this.installationDate; data['installationDate'] = this.installationDate;
data['startTime'] = this.startTime;
data['endTime'] = this.endTime;
data['pulloutDate'] = this.pulloutDate; data['pulloutDate'] = this.pulloutDate;
data['createdBy'] = this.createdBy; data['createdBy'] = this.createdBy;
data['createdDate'] = this.createdDate; 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:developer';
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_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/generic_attachment_model.dart';
import 'package:test_sa/models/timer_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/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_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/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_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.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'; import 'package:test_sa/views/widgets/timer/app_timer.dart';
class InstallationPullOutFormView extends StatefulWidget { class InstallationPullOutFormView extends StatefulWidget {
final bool isPullout;
final String? createdDate; final String? createdDate;
final LoanRequestModel? loanData;
const InstallationPullOutFormView({super.key, required this.isPullout, this.createdDate}); const InstallationPullOutFormView({super.key, this.createdDate, this.loanData});
@override @override
State<InstallationPullOutFormView> createState() => _InstallationPullOutFormViewState(); State<InstallationPullOutFormView> createState() => _InstallationPullOutFormViewState();
@ -34,7 +42,16 @@ class _InstallationPullOutFormViewState extends State<InstallationPullOutFormVie
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _snController = TextEditingController(); final _snController = TextEditingController();
List<GenericAttachmentModel> _attachments = []; 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 @override
void dispose() { 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}) { void updateTimer({TimerModel? timer}) {
if (timer?.startAt != null && timer?.endAt != null) { if (timer?.startAt != null && timer?.endAt != null) {
final start = timer!.startAt!; final start = timer!.startAt!;
@ -98,9 +98,8 @@ class _InstallationPullOutFormViewState extends State<InstallationPullOutFormVie
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: widget.isPullout ? null : DefaultAppBar(title: 'Installation Report'.addTranslation), // appBar: DefaultAppBar(title: 'Pullout Report'.addTranslation),
body: SafeArea( body: Form(
child: Form(
key: _formKey, key: _formKey,
child: Column( child: Column(
children: [ children: [
@ -109,29 +108,29 @@ class _InstallationPullOutFormViewState extends State<InstallationPullOutFormVie
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ 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( ADatePicker(
label: !widget.isPullout ? "Installation Date".addTranslation : "Validation Date".addTranslation, label: "Validation Date".addTranslation,
hideShadow: true, hideShadow: true,
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
to: DateTime.now().add(const Duration(days: 365)), to: DateTime.now().add(const Duration(days: 365)),
formatDateWithTime: true, formatDateWithTime: true,
onDatePicker: _pickInstallationDate, 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, 8.height,
AppTimer( AppTimer(
label: context.translation.workingHours, label: context.translation.workingHours,
@ -163,10 +162,24 @@ class _InstallationPullOutFormViewState extends State<InstallationPullOutFormVie
onChange: _onSignatureChanged, onChange: _onSignatureChanged,
), ),
24.height, 24.height,
"Attachments".bodyText(context).custom(color: AppColor.black10),
8.height,
AttachmentPicker( AttachmentPicker(
label: context.translation.attachments, label: context.translation.attachments,
attachment: _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), ).toShadowContainer(context, borderRadius: 20),
).expanded, ).expanded,
@ -181,7 +194,36 @@ class _InstallationPullOutFormViewState extends State<InstallationPullOutFormVie
], ],
), ),
), ),
),
); );
} }
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 loanProvider = Provider.of<LoanProvider>(context, listen: false);
bool isSuccess = await loanProvider.loanWorkflowAction(_formData.toPulloutJson());
Utils.hideLoading(context);
if (isSuccess) {
Navigator.pop(context, true);
}
}
} }

@ -1,10 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_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/modules/loan_module/models/loan_request_model.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/images/files_list.dart';
@ -16,72 +18,76 @@ class InstallationDetailsView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { 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( return Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Text(
mainAxisAlignment: MainAxisAlignment.spaceBetween, "Installation Details".addTranslation,
children: [ style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
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??'-'
), ),
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) ...[ if (loanData.loanAttachments!.isNotEmpty) ...[
12.height, 12.height,
Text( Text(
"Uploads Phase 2 docs".addTranslation, "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, 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), ).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),
],
);
}
} }

@ -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/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_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/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/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/pages/pullout_detail_page.dart';
import 'package:test_sa/modules/loan_module/provider/loan_provider.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/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_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/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/images/files_list.dart'; import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
@ -20,19 +23,35 @@ import 'package:test_sa/views/widgets/requests/request_status.dart';
import '../models/loan_request_model.dart'; import '../models/loan_request_model.dart';
import 'installation_pullout_form_view.dart'; import 'installation_pullout_form_view.dart';
class LoanEquipmentDetailPage extends StatelessWidget { class LoanEquipmentDetailPage extends StatefulWidget {
static const String id = "/loan-equipment-detail-page"; static const String id = "/loan-equipment-detail-page";
final int loanId; final int loanId;
LoanEquipmentDetailPage({Key? key, required this.loanId}) : super(key: key); 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: const DefaultAppBar(title: "Request Details"), appBar: const DefaultAppBar(title: "Request Details"),
body: SafeArea( body: FutureBuilder<LoanRequestModel?>(
child: FutureBuilder<LoanRequestModel?>( future: Provider.of<LoanProvider>(context, listen: false).getLoanById(widget.loanId),
future: Provider.of<LoanProvider>(context, listen: false).getLoanById(loanId),
builder: (BuildContext context, AsyncSnapshot<LoanRequestModel?> snapshot) { builder: (BuildContext context, AsyncSnapshot<LoanRequestModel?> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) return const CircularProgressIndicator(color: AppColor.primary10).center; if (snapshot.connectionState == ConnectionState.waiting) return const CircularProgressIndicator(color: AppColor.primary10).center;
if (snapshot.data == null) return const NoDataFound().center; if (snapshot.data == null) return const NoDataFound().center;
@ -87,28 +106,82 @@ class LoanEquipmentDetailPage extends StatelessWidget {
).toShadowContainer(context, padding: 12), ).toShadowContainer(context, padding: 12),
], ],
).expanded, ).expanded,
// if (context.userProvider.isEngineer && (snapshot.data?.loanStatusValue == 5 || snapshot.data?.loanStatusValue == 8)) // @todo ask backend to add loanTypeValue, so we can show or hide the buttons
// FooterActionButton.footerContainer( if (snapshot.data?.loanTypeName == "Standard" &&
// context: context, context.userProvider.isEngineer &&
// child: AppFilledButton( (snapshot.data?.loanStatusValue == 4 || snapshot.data?.loanStatusValue == 5 || snapshot.data?.loanStatusValue == 8))
// onPressed: () async { FooterActionButton.footerContainer(
// if (snapshot.data?.loanStatusValue == 5) { context: context,
// Navigator.push( child: AppFilledButton(
// context, onPressed: () async {
// MaterialPageRoute( if (snapshot.data?.loanStatusValue == 4) {
// builder: (context) => PullOutDetailsPage( String comment = "";
// loanData: snapshot.data, context.showBottomSheet(
// ))); Column(
// return; crossAxisAlignment: CrossAxisAlignment.start,
// } mainAxisSize: MainAxisSize.min,
// Navigator.push(context, MaterialPageRoute(builder: (context) => const InstallationPullOutFormView(isPullout: false))); children: [
// }, 'Estimated Date: ${snapshot.data?.installationEDD?.toAssetDetailsFormat ?? "-"}'.bodyText(context),
// label: snapshot.data?.loanStatusValue == 5 ? 'Installation Report' : 'PullOut Report', 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<LoanProvider>(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<Widget> requestDetails(BuildContext context, LoanRequestModel loanData) { List<Widget> requestDetails(BuildContext context, LoanRequestModel loanData) {

@ -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/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
class PullOutDetailsPage extends StatefulWidget { class PullOutDetailsPage extends StatelessWidget {
final LoanRequestModel? loanData; final LoanRequestModel? loanData;
PullOutDetailsPage({Key? key, required this.loanData}) : super(key: key); 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor, backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: DefaultAppBar( appBar: DefaultAppBar(
title: 'Loan Request'.addTranslation, title: 'Pullout Report'.addTranslation,
), ),
body: DefaultTabController( body: DefaultTabController(
length: 2, length: 2,
@ -61,16 +49,15 @@ class _PullOutDetailsPageState extends State<PullOutDetailsPage> {
], ],
), ),
), ),
12.height, 0.height,
TabBarView( TabBarView(
children: [ children: [
Align( Column(
alignment: Alignment.topCenter, children: [
child: InstallationDetailsView( InstallationDetailsView(loanData: loanData!),
loanData: widget.loanData!, ],
),
), ),
const InstallationPullOutFormView(isPullout: true), InstallationPullOutFormView(loanData: loanData!),
], ],
).expanded, ).expanded,
], ],

@ -48,4 +48,16 @@ class LoanProvider extends ChangeNotifier {
} }
return loanData; 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;
}
}
} }

@ -156,7 +156,7 @@ class _UpdateTaskRequestState extends State<UpdateTaskRequest> {
recallAlertTypeWidget(taskModel: taskProvider.taskRequestModel!), recallAlertTypeWidget(taskModel: taskProvider.taskRequestModel!),
], ],
//Not good approach need to use enums .... //Not good approach need to use enums ....
if (taskProvider.taskRequestModel?.taskType?.typeName == "PullOut") ...[ if (taskProvider.taskRequestModel?.taskType?.isSignatureRequired ?? false) ...[
ESignature( ESignature(
title: "End-user signature", title: "End-user signature",
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
@ -262,7 +262,7 @@ class _UpdateTaskRequestState extends State<UpdateTaskRequest> {
taskAttachment.add(TaskJobAttachment(id: item.id, name: fileName)); taskAttachment.add(TaskJobAttachment(id: item.id, name: fileName));
} }
taskModel.taskJobAttachments = taskAttachment; taskModel.taskJobAttachments = taskAttachment;
taskModel.taskJobActivityEngineerTimers = [];
if (taskModel.taskTimePicker != null) { if (taskModel.taskTimePicker != null) {
int durationInSecond = taskModel.taskTimePicker!.endAt!.difference(taskModel.taskTimePicker!.startAt!).inSeconds; int durationInSecond = taskModel.taskTimePicker!.endAt!.difference(taskModel.taskTimePicker!.startAt!).inSeconds;
taskModel.taskJobActivityEngineerTimers?.add( taskModel.taskJobActivityEngineerTimers?.add(

@ -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<List<UnReadMessage>>(
future: Provider.of<ChatProvider>(context, listen: false).getUnReadMessages(context.userProvider.user!.employeeId ?? context.userProvider.user!.username!),
builder: (BuildContext context, AsyncSnapshot<List<UnReadMessage>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) return const CircularProgressIndicator(color: AppColor.primary10).center;
if (snapshot.data?.isEmpty ?? true) return const NoDataFound().center;
List<UnReadMessage> 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),
);
}));
}
}
Loading…
Cancel
Save