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 23 hours ago
commit 2e3736cdc9

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

@ -1,3 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
@ -10,6 +11,7 @@ import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/helper/utils.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/pages/user/notifications/notifications_page.dart';
import 'package:test_sa/views/pages/user/notifications/unread_chat_list.dart';
import 'package:test_sa/views/widgets/dialogs/confirm_dialog.dart';
import '../../controllers/providers/api/user_provider.dart';
@ -127,6 +129,12 @@ class AppBarWidget extends StatelessWidget {
);
}),
16.width,
if (context.settingProvider.isUserFlowMedical) ...[
Icon(Icons.mark_unread_chat_alt_outlined, color: context.isDark ? AppColor.neutral30 : AppColor.neutral20, size: 30).paddingOnly(top: 6, end: 0).onPress(() {
Navigator.of(context).push(CupertinoPageRoute(builder: (_) => UnReadChatList()));
}),
8.width,
],
Stack(
alignment: Alignment.topRight,
children: [

@ -42,12 +42,12 @@ extension BuildContextExtension on BuildContext {
builder: (BuildContext cxt) => InfoDialog(message: message, onTap: onTap, title: title, okTitle: okTitle, content: content),
);
Future showBottomSheet(Widget childWidget, {bool? isDismissible, String? title}) => showModalBottomSheet(
Future showBottomSheet(Widget childWidget, {bool? isDismissible, String? title, bool showCancelButton = false}) => showModalBottomSheet(
context: this,
useSafeArea: true,
isScrollControlled: true,
isDismissible: true,
backgroundColor: Colors.transparent,
builder: (context) => SingleChildScrollView(padding: const EdgeInsets.all(0), child: childWidget.bottomSafeArea).bottomSheetContainerNew(context, title: title),
builder: (context) => SingleChildScrollView(padding: const EdgeInsets.all(0), child: childWidget.bottomSafeArea).bottomSheetContainerNew(context, title: title,showCancelButton: showCancelButton),
);
}

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

@ -145,7 +145,7 @@ extension WidgetExtensions on Widget {
child: this,
);
Widget bottomSheetContainerNew(BuildContext context, {EdgeInsets? padding, String? title}) => Container(
Widget bottomSheetContainerNew(BuildContext context, {EdgeInsets? padding, String? title, bool showCancelButton = false}) => Container(
clipBehavior: Clip.antiAlias,
margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
decoration: BoxDecoration(
@ -164,7 +164,21 @@ extension WidgetExtensions on Widget {
).center,
16.height,
if (title != null) ...[
title.bottomSheetHeadingTextStyle(context),
Row(
children: [
title.bottomSheetHeadingTextStyle(context).expanded,
if (showCancelButton) ...[
8.width,
InkWell(
onTap: () => Navigator.pop(context),
child: Icon(
Icons.cancel_outlined,
color: context.isDarkNotListen ? AppColor.neutral30 : AppColor.black20,
),
)
]
],
),
16.height,
],
this

@ -491,6 +491,7 @@ class TaskTypeModel {
final List<dynamic>? taskTypeRoles;
final bool? isInstallation;
final bool? isRecallAndAlert;
final bool? isSignatureRequired;
TaskTypeModel({
this.id,
@ -500,6 +501,7 @@ class TaskTypeModel {
this.taskTypeRoles,
this.isInstallation,
this.isRecallAndAlert,
this.isSignatureRequired,
});
factory TaskTypeModel.fromJson(Map<String, dynamic> json) => TaskTypeModel(
@ -510,6 +512,7 @@ class TaskTypeModel {
taskTypeRoles: json['taskTypeRoles'],
isInstallation: json['isInstallation'],
isRecallAndAlert: json['isRecallAndAlert'],
isSignatureRequired: json['isSignatureRequired'],
);
Map<String, dynamic> toJson() => {
@ -520,6 +523,7 @@ class TaskTypeModel {
'taskTypeRoles': taskTypeRoles,
'isInstallation': isInstallation,
'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:flutter/material.dart' as Material;
import 'api_client.dart';
import 'chat_api_client.dart';
import 'model/chat_attachment_model.dart';
import 'model/chat_participant_model.dart';
import 'model/get_search_user_chat_model.dart';
import 'model/get_single_user_chat_list_model.dart';
import 'model/unread_message_model.dart';
import 'model/user_chat_history_model.dart';
// import 'get_single_user_chat_list_model.dart';
@ -454,6 +456,25 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
return result;
}
Future<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) {
// dynamic items = args!.toList();
// for (var cItem in items[0]) {
@ -616,7 +637,6 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
}
}
Future<void> onAckSeenAsync(List<Object?>? parameters) async {
try {
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({
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 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: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),
],
);
}
}

@ -6,12 +6,15 @@ import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/helper/utils.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/modules/loan_module/models/loan_attachment_model.dart';
import 'package:test_sa/modules/loan_module/pages/installation_form_view.dart';
import 'package:test_sa/modules/loan_module/pages/pullout_detail_page.dart';
import 'package:test_sa/modules/loan_module/provider/loan_provider.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/images/files_list.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
@ -20,95 +23,165 @@ import 'package:test_sa/views/widgets/requests/request_status.dart';
import '../models/loan_request_model.dart';
import 'installation_pullout_form_view.dart';
class LoanEquipmentDetailPage extends StatelessWidget {
class LoanEquipmentDetailPage extends StatefulWidget {
static const String id = "/loan-equipment-detail-page";
final int loanId;
LoanEquipmentDetailPage({Key? key, required this.loanId}) : super(key: key);
@override
_LoanEquipmentDetailPageState createState() {
return _LoanEquipmentDetailPageState();
}
}
class _LoanEquipmentDetailPageState extends State<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;
appBar: const DefaultAppBar(title: "Request Details"),
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!;
List<LoanAttachmentModel> allAttachments = snapshot.data!.loanAttachments!;
return Column(
return Column(
children: [
ListView(
padding: const EdgeInsets.all(16),
children: [
ListView(
padding: const EdgeInsets.all(16),
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StatusLabel(
label: snapshot.data!.loanStatusName!,
textColor: AppColor.getRequestStatusTextColorByName(context, snapshot.data!.loanStatusName!),
backgroundColor: AppColor.getRequestStatusColorByName(context, snapshot.data!.loanStatusName!),
),
1.width.expanded,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StatusLabel(
label: snapshot.data!.loanStatusName!,
textColor: AppColor.getRequestStatusTextColorByName(context, snapshot.data!.loanStatusName!),
backgroundColor: AppColor.getRequestStatusColorByName(context, snapshot.data!.loanStatusName!),
),
1.width.expanded,
Text(
snapshot.data!.createdDate?.toServiceRequestCardFormat ?? "-",
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
),
],
),
12.height,
...requesterDetails(context, snapshot.data!),
const Divider().defaultStyle(context),
...requestDetails(context, snapshot.data!),
const Divider().defaultStyle(context),
...assetDetails(context, snapshot.data!),
const Divider().defaultStyle(context),
...installationDetails(context, snapshot.data!),
const Divider().defaultStyle(context),
...doctorDetails(context, snapshot.data!),
const Divider().defaultStyle(context),
...vendorDetails(context, snapshot.data!),
if (allAttachments.isNotEmpty) ...[
const Divider().defaultStyle(context),
Text(
snapshot.data!.createdDate?.toServiceRequestCardFormat ?? "-",
textAlign: TextAlign.end,
style: AppTextStyles.tinyFont.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral50),
"Attachments".addTranslation,
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
FilesList(images: allAttachments.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []),
],
),
12.height,
...requesterDetails(context, snapshot.data!),
const Divider().defaultStyle(context),
...requestDetails(context, snapshot.data!),
const Divider().defaultStyle(context),
...assetDetails(context, snapshot.data!),
const Divider().defaultStyle(context),
...installationDetails(context, snapshot.data!),
const Divider().defaultStyle(context),
...doctorDetails(context, snapshot.data!),
const Divider().defaultStyle(context),
...vendorDetails(context, snapshot.data!),
if (allAttachments.isNotEmpty) ...[
const Divider().defaultStyle(context),
Text(
"Attachments".addTranslation,
style: AppTextStyles.heading6.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50),
),
FilesList(images: allAttachments.map((e) => URLs.getFileUrl(e.attachmentName ?? '') ?? '').toList() ?? []),
],
],
).toShadowContainer(context, padding: 12),
],
).expanded,
// if (context.userProvider.isEngineer && (snapshot.data?.loanStatusValue == 5 || snapshot.data?.loanStatusValue == 8))
// FooterActionButton.footerContainer(
// context: context,
// child: AppFilledButton(
// onPressed: () async {
// if (snapshot.data?.loanStatusValue == 5) {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => PullOutDetailsPage(
// loanData: snapshot.data,
// )));
// return;
// }
// Navigator.push(context, MaterialPageRoute(builder: (context) => const InstallationPullOutFormView(isPullout: false)));
// },
// label: snapshot.data?.loanStatusValue == 5 ? 'Installation Report' : 'PullOut Report',
// ),
// )
).toShadowContainer(context, padding: 12),
],
).expanded,
// @todo ask backend to add loanTypeValue, so we can show or hide the buttons
if (snapshot.data?.loanTypeName == "Standard" &&
context.userProvider.isEngineer &&
(snapshot.data?.loanStatusValue == 4 || snapshot.data?.loanStatusValue == 5 || snapshot.data?.loanStatusValue == 8))
FooterActionButton.footerContainer(
context: context,
child: AppFilledButton(
onPressed: () async {
if (snapshot.data?.loanStatusValue == 4) {
String comment = "";
context.showBottomSheet(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
'Estimated Date: ${snapshot.data?.installationEDD?.toAssetDetailsFormat ?? "-"}'.bodyText(context),
16.height,
AppTextFormField(
labelText: context.translation.comments,
showSpeechToText: true,
textInputType: TextInputType.multiline,
labelStyle: AppTextStyles.textFieldLabelStyle,
showWithoutDecoration: true,
backgroundColor: context.isDarkNotListen ? AppColor.neutral20 : AppColor.neutral100,
alignLabelWithHint: true,
onChange: (text) {
comment = text;
},
),
16.height,
AppFilledButton(
onPressed: () async {
Utils.showLoading(context);
LoanProvider loanProvider = Provider.of<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) {

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

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

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