notification in progress

design_3.0_sdk_upgrade
WaseemAbbasi22 2 days ago
parent dc9266a0da
commit 7aed41380b

1
.gitignore vendored

@ -50,3 +50,4 @@ android/gradle.properties
/android/app/debug
/android/app/profile
/android/app/release
/android/gradle/wrapper/gradle-wrapper.properties

@ -1,4 +1,4 @@
#Tue Oct 15 10:26:35 AST 2024
#Thu Oct 24 09:39:31 AST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip

@ -78,6 +78,7 @@ class FirebaseNotificationManger {
}
static void handleMessage(context, Map<String, dynamic> messageData) {
print('message data i got is ${messageData}');
if (messageData["requestType"] != null && messageData["requestNumber"] != null) {
Widget? serviceClass;
@ -110,6 +111,7 @@ class FirebaseNotificationManger {
static initialized(BuildContext context) async {
if (!(await isGoogleServicesAvailable())) {
var initialNotification = await h_push.Push.getInitialNotification();
if (initialNotification != null) {

@ -288,10 +288,9 @@ class CategoryTabs {
tabs.add(CategoryTabs('Completed', 3));
return tabs;
}
tabs.add(CategoryTabs('Upcoming', 3));
tabs.add(CategoryTabs('Open Request', 1));
tabs.add(CategoryTabs('In Progress', 2));
tabs.add(CategoryTabs('Upcoming', 3));
tabs.add(CategoryTabs('Canceled', 6));
return tabs;
}

@ -21,7 +21,7 @@ class RequestCategoryList extends StatelessWidget {
return ListView.builder(
itemCount: list.length < totalCount ? list.length + 1 : list.length,
shrinkWrap: true,
padding: EdgeInsets.all(16),
padding: const EdgeInsets.all(16),
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
if (index == list.length) {

@ -453,6 +453,8 @@
"waitingForQuotation" : "في انتظار السؤال",
"gasRequest" : "طلب غاز",
"createWorkOrder" : "إنشاء طلب عمل",
"confirmEngineerArrival": "تأكيد وصول المهندس",
"confirmingEngineerArrivalAction": "من خلال هذا الإجراء، أنت تؤكد وصول المهندس",
"commentHere" : "علق هنا",
"nurseSignature" : "توقيع الممرض",
"actualVisitDate": "تاريخ الزيارة الفعلي",

@ -466,6 +466,8 @@
"daily" : "Daily",
"weekly" : "Weekly",
"monthly" : "Monthly",
"confirmEngineerArrival": "Confirm Engineer Arrival",
"confirmingEngineerArrivalAction": "With this action you are confirming engineer arrival",
"myShift" : "My Shift",
"myTeamRequest" : "My Team Request",
"sunToThurs": "Sunday to Thursday",

@ -56,7 +56,6 @@ class FooterActionButton {
break;
// TODO: Handle this case.
case WorkOrderNextStepEnum.nTakeAction:
print('i am here take action ..');
// const SizedBox().flushBar(context: context, title: context.translation.youMarkedThisIssueAsFixedWaitingForTheRequesterToConfirm, message: '');
return footerContainer(
child: AppFilledButton(
@ -216,16 +215,18 @@ class FooterActionButton {
));
}
if (workOrderNextStepStatus == WorkOrderNextStepEnum.waitingForRequesterToConfirm) {
return footerContainer(
child: AppFilledButton(
label: context.translation.confirm,
// maxWidth: true,
buttonColor: AppColor.green70,
onPressed: () async {
int? status = await requestDetailProvider.nurseConfirmArrival(workOrderId: requestDetailProvider.currentWorkOrder?.data?.requestId ?? 0);
if (status == 200) {}
},
));
return SizedBox();
// return footerContainer(
// child: AppFilledButton(
// label: context.translation.confirm,
// // maxWidth: true,
// buttonColor: AppColor.green70,
// onPressed: () async {
// ServiceRequestBottomSheet.nurseVerifyArrivalBottomSheet(context: context);
// // int? status = await requestDetailProvider.nurseConfirmArrival(workOrderId: requestDetailProvider.currentWorkOrder?.data?.requestId ?? 0);
// // if (status == 200) {}
// },
// ));
}
}
return const SizedBox();

@ -45,6 +45,7 @@ class ServiceRequestBottomSheet {
static Future fixRemotelyBottomSheet({required BuildContext context}) {
TextEditingController _workingHoursController = TextEditingController();
TextEditingController _commentController = TextEditingController();
return buildBottomSheetParent(
context: context,
@ -162,6 +163,8 @@ class ServiceRequestBottomSheet {
8.height,
AppTextFormField(
labelText: context.translation.comments,
showSpeechToText: true,
controller: _commentController,
textInputType: TextInputType.multiline,
labelStyle: AppTextStyles.textFieldLabelStyle,
showWithoutDecoration: true,
@ -198,11 +201,14 @@ class ServiceRequestBottomSheet {
buttonColor: AppColor.green70,
loading: false,
onPressed: () async {
if(requestDetailProvider.fixRemotelyHelperModel?.startDate==null&&requestDetailProvider.fixRemotelyHelperModel?.endDate==null){
"Please Select start and end date".showToast;
return;
}
requestDetailProvider.fixRemotelyHelperModel?.workOrderId = requestDetailProvider.currentWorkOrder?.data?.requestId;
requestDetailProvider.engineerFixRemotely();
//TODO context issue to show message..
Navigator.pop(context);
// const SizedBox().flushBar(context: context, title: '', message: context.translation.youMarkedThisIssueAsFixedWaitingForTheRequesterToConfirm);
const SizedBox().flushBar(context: context, title: '', message: context.translation.youMarkedThisIssueAsFixedWaitingForTheRequesterToConfirm);
},
),
),
@ -267,6 +273,7 @@ class ServiceRequestBottomSheet {
backgroundColor: AppColor.neutral100,
labelStyle: AppTextStyles.textFieldLabelStyle,
showShadow: false,
showSpeechToText: true,
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
onChange: (text) {
@ -282,6 +289,10 @@ class ServiceRequestBottomSheet {
buttonColor: AppColor.primary10,
loading: false,
onPressed: () async {
if(requestDetailProvider.needVisitHelperModel?.visitDate==null){
"Please select visit date".showToast;
return;
}
if (requestDetailProvider.currentWorkOrder?.data?.nextStep!.workOrderNextStepEnum == WorkOrderNextStepEnum.eArrived) {
requestDetailProvider.updateNeedVisitHelperModel(NeedVisitHelperModel(
workOrderId: requestDetailProvider.needVisitHelperModel?.workOrderId,
@ -539,6 +550,7 @@ class ServiceRequestBottomSheet {
static Future rejectRequestBottomSheet({required BuildContext context}) {
TextEditingController _commentController = TextEditingController();
return buildBottomSheetParent(
context: context,
childWidget: Consumer<ServiceRequestDetailProvider>(builder: (context, requestDetailProvider, child) {
@ -567,8 +579,10 @@ class ServiceRequestBottomSheet {
AppTextFormField(
backgroundColor: AppColor.neutral100,
labelText: context.translation.comments,
controller: _commentController,
textInputType: TextInputType.multiline,
alignLabelWithHint: true,
showSpeechToText: true,
showShadow: false,
labelStyle: AppTextStyles.textFieldLabelStyle,
onChange: (text) {
@ -803,6 +817,7 @@ class ServiceRequestBottomSheet {
static Future feedBackBottomSheet({required BuildContext context}) {
String feedback = '';
TextEditingController _commentController = TextEditingController();
return buildBottomSheetParent(
context: context,
childWidget: Consumer<ServiceRequestDetailProvider>(builder: (context, ServiceRequestDetailProvider requestDetailProvider, child) {
@ -818,9 +833,11 @@ class ServiceRequestBottomSheet {
21.height,
AppTextFormField(
labelText: context.translation.comments,
controller: _commentController,
textInputType: TextInputType.multiline,
labelStyle: AppTextStyles.textFieldLabelStyle,
showWithoutDecoration: true,
showSpeechToText: true,
backgroundColor: context.isDark ? AppColor.neutral20 : AppColor.neutral100,
alignLabelWithHint: true,
onChange: (text) {
@ -836,6 +853,10 @@ class ServiceRequestBottomSheet {
buttonColor: AppColor.green70,
loading: false,
onPressed: () {
if(feedback.isEmpty){
"Please provide feedback".showToast;
return;
}
Navigator.pop(context);
requestDetailProvider.engineerMarkAsFixed(workOrderId: requestDetailProvider.currentWorkOrder!.data!.requestId!, feedback: feedback);
},
@ -847,6 +868,7 @@ class ServiceRequestBottomSheet {
static Future nurseRejectBackBottomSheet({required BuildContext context}) {
String feedback = '';
TextEditingController _feedBackController = TextEditingController();
return buildBottomSheetParent(
context: context,
childWidget: Consumer<ServiceRequestDetailProvider>(builder: (context, ServiceRequestDetailProvider requestDetailProvider, child) {
@ -862,6 +884,8 @@ class ServiceRequestBottomSheet {
21.height,
AppTextFormField(
labelText: context.translation.comments,
controller: _feedBackController,
showSpeechToText: true,
textInputType: TextInputType.multiline,
labelStyle: AppTextStyles.textFieldLabelStyle,
showWithoutDecoration: true,
@ -1141,12 +1165,17 @@ class ServiceRequestBottomSheet {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox().indicatorWidget(),
16.height,
Align(
alignment: AlignmentDirectional.centerStart,
child: context.translation.confirmEngineerArrival.bottomSheetHeadingTextStyle(context),
),
8.height,
Align(
alignment: AlignmentDirectional.centerStart,
child: context.translation.pleaseConfirmTheIssueHasBeenResolved.bottomSheetHeadingTextStyle(context),
child: context.translation.confirmingEngineerArrivalAction.bodyText(context),
),
10.height,
32.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
@ -1158,8 +1187,8 @@ class ServiceRequestBottomSheet {
textColor: AppColor.red30,
showBorder: true,
onPressed: () async {
//TODO call the api ..
Navigator.pop(context);
nurseRejectBackBottomSheet(context: context);
},
).expanded,
const SizedBox(
@ -1171,19 +1200,8 @@ class ServiceRequestBottomSheet {
loading: requestDetailProvider.isLoading,
buttonColor: AppColor.green70,
onPressed: () async {
if (newSignature != null) {
requestDetailProvider.nurseActionHelperModel = NurseActionHelperModel(
workOrderId: requestDetailProvider.currentWorkOrder!.data!.requestId!,
signatureNurse: nurseSignature,
);
await requestDetailProvider.nurseConfirm();
if (requestDetailProvider.currentWorkOrder!.data!.requestId != null) {
requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!);
}
Navigator.pop(context);
} else {
//show some toast...
}
// int? status = await requestDetailProvider.nurseConfirmArrival(workOrderId: requestDetailProvider.currentWorkOrder?.data?.requestId ?? 0);
// if (status == 200) {}
},
).expanded,
],

@ -60,7 +60,7 @@ class _VerifyArrivalViewState extends State<VerifyArrivalView> {
heading: item.verificationTypes!.name ?? '',
subHeading: item.description ?? '',
onTap: () {
onItemTap(requestDetailProvider: requestDetailProvider, index: index, context: context, verificationTypeId: item.verificationTypes?.value);
onItemTap(requestDetailProvider: requestDetailProvider, context: context, verificationTypeId: item.verificationTypes?.value);
});
},
).paddingOnly(start: 16, end: 16, top: 12, bottom: 12),
@ -111,9 +111,9 @@ class _VerifyArrivalViewState extends State<VerifyArrivalView> {
);
}
void onItemTap({required int index, required ServiceRequestDetailProvider requestDetailProvider, required BuildContext context, int? verificationTypeId}) async {
switch (index) {
case 0:
void onItemTap({required ServiceRequestDetailProvider requestDetailProvider, required BuildContext context, int? verificationTypeId}) async {
switch (verificationTypeId) {
case 1:
int? status;
String? result = await Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ScanQr()),
@ -139,34 +139,21 @@ class _VerifyArrivalViewState extends State<VerifyArrivalView> {
}
}
break;
case 1:
case 2:
try {
showWaitingBottomSheet();
// int? status;
// showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
// status = await requestDetailProvider.engineerConfirmArrival(
// workOrderId: requestDetailProvider.currentWorkOrder!.data!.requestId!, verificationTypeId: verificationTypeId ?? 1, photoInfo: '', otp: '');
// if (status == 200) {
// Navigator.pop(context);
// requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!);
// Navigator.pop(context);
// requestDetailProvider.startTimer();
// } else {
// Navigator.pop(context);
// }
showWaitingBottomSheet(requestDetailProvider: requestDetailProvider, verificationTypeId: verificationTypeId);
} catch (e) {
//Navigator.pop(context);
"Requester not confirmed you arrival".showToast;
}
break;
case 2:
case 3:
requestDetailProvider.sendOtp(workOrderId: requestDetailProvider.currentWorkOrder!.data!.requestId!);
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const VerifyOtpView()),
);
break;
case 3:
case 4:
File? pickedFile = await onFilePicker();
if (pickedFile != null) {
var fileObj = ("${pickedFile.path.split("/").last}|${base64Encode(File(pickedFile.path).readAsBytesSync())}");
@ -188,7 +175,7 @@ class _VerifyArrivalViewState extends State<VerifyArrivalView> {
}
}
break;
case 4:
case 5:
int? status;
String? result = await Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const ScanQr()),
@ -196,9 +183,9 @@ class _VerifyArrivalViewState extends State<VerifyArrivalView> {
if (result != null) {
try {
Map<String, dynamic> resultJson = jsonDecode(result);
print('result i got is ${resultJson}');
showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
status = await requestDetailProvider.engineerConfirmArrival(workOrderId: resultJson['WorkOrderId'], verificationTypeId: 5, workOrderCreatedById: resultJson['WorkOrderCreatedById']);
status = await requestDetailProvider.engineerConfirmArrival(
workOrderId: resultJson['WorkOrderId'], verificationTypeId: verificationTypeId ?? 5, workOrderCreatedById: resultJson['WorkOrderCreatedById']);
if (status == 200) {
requestDetailProvider.getWorkOrderById(id: resultJson['WorkOrderId']);
Navigator.pop(context);
@ -228,7 +215,9 @@ class _VerifyArrivalViewState extends State<VerifyArrivalView> {
return fileImage;
}
void showWaitingBottomSheet() async {
void showWaitingBottomSheet({required ServiceRequestDetailProvider requestDetailProvider, int? verificationTypeId}) async {
await requestDetailProvider.engineerConfirmArrival(
workOrderId: requestDetailProvider.currentWorkOrder!.data!.requestId!, verificationTypeId: verificationTypeId ?? 2, photoInfo: '', otp: '');
bool? isArrived = (await showModalBottomSheet(
context: context,
useSafeArea: true,
@ -236,14 +225,25 @@ class _VerifyArrivalViewState extends State<VerifyArrivalView> {
backgroundColor: Colors.transparent,
builder: (context) => RequestApprovalBottomSheet(),
));
if (isArrived==null) {
if (isArrived == null) {
//Requester not confirmed you arrival".showToast;
} else if(isArrived) {
try {
// todo @waseeem call api to confirm
} catch (ex) {}
}else {
} else if (isArrived) {
// try {
// // todo @waseeem call api to confirm
// int? status;
// showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
// status = await requestDetailProvider.engineerConfirmArrival(
// workOrderId: requestDetailProvider.currentWorkOrder!.data!.requestId!, verificationTypeId: verificationTypeId ?? 1, photoInfo: '', otp: '');
// if (status == 200) {
// Navigator.pop(context);
// requestDetailProvider.getWorkOrderById(id: requestDetailProvider.currentWorkOrder!.data!.requestId!);
// Navigator.pop(context);
// requestDetailProvider.startTimer();
// } else {
// Navigator.pop(context);
// }
// } catch (ex) {}
} else {
"Requester not confirmed you arrival".showToast;
}
}

@ -7,6 +7,7 @@ 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/models/enums/user_types.dart';
import 'package:test_sa/models/enums/work_order_next_step.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/service_request_latest/service_request_detail_provider.dart';
@ -33,7 +34,12 @@ class _ServiceRequestDetailMainState extends State<ServiceRequestDetailMain> {
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
bool isNurse = (Provider.of<UserProvider>(context, listen: false).user?.type) == UsersTypes.normal_user;
_requestProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
//workOrderNextStepStatus == WorkOrderNextStepEnum.waitingForRequesterToConfirm
if (isNurse && (_requestProvider.currentWorkOrder?.data?.nextStep?.workOrderNextStepEnum == WorkOrderNextStepEnum.waitingForRequesterToConfirm) && !_requestProvider.isLoading) {
ServiceRequestBottomSheet.nurseVerifyArrivalBottomSheet(context: context);
}
_requestProvider.getWorkOrderById(id: widget.requestId);
});
}
@ -42,7 +48,8 @@ class _ServiceRequestDetailMainState extends State<ServiceRequestDetailMain> {
void dispose() {
super.dispose();
}
Future<void> stopTimer()async{
Future<void> stopTimer() async {
ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context, listen: false);
if (requestDetailProvider.timer != null && requestDetailProvider.timer!.isActive) {
requestDetailProvider.stopTimer();
@ -64,13 +71,15 @@ class _ServiceRequestDetailMainState extends State<ServiceRequestDetailMain> {
},
child: Scaffold(
backgroundColor: AppColor.neutral100,
appBar: DefaultAppBar(title: context.translation.cmDetails,
onBackPress: (){
appBar: DefaultAppBar(
title: context.translation.cmDetails,
onBackPress: () {
stopTimer();
Navigator.pop(context);
},
actions: [
isNurse? IconButton(
isNurse
? IconButton(
icon: 'qr'.toSvgAsset(
height: 24,
width: 24,
@ -78,7 +87,8 @@ class _ServiceRequestDetailMainState extends State<ServiceRequestDetailMain> {
onPressed: () {
ServiceRequestBottomSheet.getQRCodeBottomSheet(context: context);
},
):IconButton(
)
: IconButton(
icon: const Icon(Icons.home),
onPressed: () {
stopTimer();
@ -125,6 +135,7 @@ class _ServiceRequestDetailMainState extends State<ServiceRequestDetailMain> {
],
),
),
),);
),
);
}
}

@ -4,10 +4,12 @@ import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:google_api_availability/google_api_availability.dart';
import 'package:huawei_push/huawei_push.dart' as h_push;
import 'package:provider/provider.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/new_views/app_style/app_color.dart';
import 'package:test_sa/service_request_latest/service_request_detail_provider.dart';
class RequestApprovalBottomSheet extends StatefulWidget {
RequestApprovalBottomSheet({Key? key}) : super(key: key);
@ -26,6 +28,7 @@ class _RequestApprovalBottomState extends State<RequestApprovalBottomSheet> {
}
void listenForApproval() async {
print('listen for approval called..');
if (Platform.isAndroid && !(await isGoogleServicesAvailable())) {
h_push.Push.onMessageReceivedStream.listen((h_push.RemoteMessage remoteMessage) {
print("onMessageReceivedStream:${remoteMessage.toMap()}");
@ -34,16 +37,29 @@ class _RequestApprovalBottomState extends State<RequestApprovalBottomSheet> {
});
} else {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
Map<String, dynamic> messageData = message.data;
if (messageData["notificaitonType"] != null && messageData["arrived"] != null) {
if (messageData["notificaitonType"] == "arrivalConfirmation") {
if ((messageData["arrived"].toString()) == "true") {
print('mesage ${message.data}');
ConfirmArrivalNotificationModel notificationModel = ConfirmArrivalNotificationModel.fromJson(message.data);
print('notification model i got is ${notificationModel.toJson()}');
if(notificationModel.requestId!=null&&notificationModel.accept!=null){
print('accept value is ${notificationModel.accept==false}');
if(notificationModel.accept!=null&&!notificationModel.accept!){
ServiceRequestDetailProvider requestDetailProvider = Provider.of<ServiceRequestDetailProvider>(context,listen: false);
requestDetailProvider.getWorkOrderById(id: notificationModel.requestId??0);
Navigator.pop(context, true);
Navigator.pop(context, true);
} else {
Navigator.pop(context, false);
}
}
}
// Map<String, dynamic> messageData = message.data;
// if (messageData["notificationType"] != null && messageData["accept"] != null) {
// if (messageData["notificationType"] == "arrivalConfirmation") {
// if ((messageData["accept"].toString()) == "False") {
// if(messageData["accept"])
// Navigator.pop(context, true);
// } else {
// Navigator.pop(context, false);
// }
// }
// }
});
}
}
@ -97,3 +113,41 @@ class _RequestApprovalBottomState extends State<RequestApprovalBottomSheet> {
;
}
}
class ConfirmArrivalNotificationModel {
final String? transactionType;
final int? requestId;
final String? notificationType;
final String? userId;
final bool? accept;
ConfirmArrivalNotificationModel({
this.transactionType,
this.requestId,
this.notificationType,
this.userId,
this.accept,
});
// Factory constructor to create an instance from a Map (e.g., JSON)
factory ConfirmArrivalNotificationModel.fromJson(Map<String, dynamic> json) {
return ConfirmArrivalNotificationModel(
transactionType: json['transactionType'],
requestId: json['requestId'],
notificationType: json['notificationType'],
userId: json['userId'],
accept: json['accept'],
);
}
// Convert an instance to a Map (e.g., for serialization)
Map<String, dynamic> toJson() {
return {
'transactionType': transactionType,
'requestId': requestId,
'notificationType': notificationType,
'userId': userId,
'accept': accept,
};
}
}

Loading…
Cancel
Save