Merge remote-tracking branch 'origin/design_3.0_asset_delivery_module' into design_3.0_asset_delivery_module

design_3.0_asset_delivery_module
WaseemAbbasi22 1 month ago
commit bf4d2a3257

@ -1,12 +1,11 @@
class URLs { class URLs {
URLs._(); URLs._();
static const String appReleaseBuildNumber = "31"; static const String appReleaseBuildNumber = "32";
// static const host1 = "https://atomsm.hmg.com"; // production url // static const host1 = "https://atomsm.hmg.com"; // production url
// static const host1 = "https://atomsmdev.hmg.com"; // local DEV url // static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
static const host1 = "https://atomsmuat.hmg.com"; // local UAT url static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
// static const host1 = "http://10.201.111.125:9495"; // temporary Server UAT url
// static String _baseUrl = "$_host/mobile"; // static String _baseUrl = "$_host/mobile";
@ -20,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 chatApiKey = "f53a98286f82798d588f67a7f0db19f7aebc839e"; // new V2 apis static const String chatApiKey = "f53a98286f82798d588f67a7f0db19f7aebc839e"; // new V2 apis
static String _host = host1; static String _host = host1;

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
@ -13,6 +14,7 @@ import 'package:test_sa/modules/cx_module/survey/survey_page.dart';
import 'package:test_sa/modules/pm_module/ppm_wo/ppm_details_page.dart'; import 'package:test_sa/modules/pm_module/ppm_wo/ppm_details_page.dart';
import 'package:test_sa/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart'; import 'package:test_sa/modules/pm_module/recurrent_wo/recurrent_work_order_view.dart';
import 'package:test_sa/modules/tm_module/device_transfer/device_transfer_details.dart'; import 'package:test_sa/modules/tm_module/device_transfer/device_transfer_details.dart';
import 'package:test_sa/modules/tm_module/tasks/task_request_detail_view.dart';
import 'package:test_sa/modules/tm_module/gas_refill/gas_refill_details.dart'; import 'package:test_sa/modules/tm_module/gas_refill/gas_refill_details.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
@ -88,6 +90,44 @@ class FirebaseNotificationManger {
String? transactionType = messageData["transactionType"]?.toString(); String? transactionType = messageData["transactionType"]?.toString();
if (transactionType == null) {
return;
} else if (transactionType == "17" && messageData["requestType"] == "chat") {
int moduleId = int.parse(messageData["moduleId"].toString());
int requestNumber = int.parse(messageData["requestNumber"].toString());
switch (moduleId) {
case 1: // cm
serviceClass = CMDetailPage(requestId: requestNumber, moduleId: moduleId);
break;
case 2: // gas refill
serviceClass = GasRefillDetailsPage(
priority: messageData["priority"],
date: messageData["createdOn"],
moduleId: moduleId,
model: GasRefillModel(id: requestNumber),
);
break;
case 3: //transfer
serviceClass = DeviceTransferDetails(model: DeviceTransfer(id: requestNumber), moduleId: moduleId);
break;
case 6: // task
serviceClass = TaskRequestDetailsView(
taskId: requestNumber,
moduleId: moduleId,
// requestDetails: RequestsDetails(nameOfType: requestData?.nameOfType, status: requestData?.statusName, priority: requestData?.priorityName, date: requestData?.transactionDate, ),
);
// ServiceRequestDetailMain(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1);
break;
default:
serviceClass = const Scaffold(body: Center(child: NoDataFound()));
}
Navigator.of(context).push(MaterialPageRoute(builder: (_) => serviceClass!));
return;
}
// PPM=1, // PPM=1,
// ServiceRequestEngineer = 3, // ServiceRequestEngineer = 3,
// AssetTransfer=7, // AssetTransfer=7,
@ -101,13 +141,13 @@ class FirebaseNotificationManger {
break; break;
//these three request are same corrective maintenance.... //these three request are same corrective maintenance....
case "3": case "3":
serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString())); serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1);
break; break;
case "8": case "8":
serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString())); serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1);
break; break;
case "11": case "11":
serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString())); serviceClass = CMDetailPage(requestId: int.parse(messageData["requestNumber"].toString()), moduleId: 1);
break; break;
case "7": case "7":
serviceClass = DeviceTransferDetails(model: DeviceTransfer(id: int.parse(messageData["requestNumber"].toString())), moduleId: 3); serviceClass = DeviceTransferDetails(model: DeviceTransfer(id: int.parse(messageData["requestNumber"].toString())), moduleId: 3);

@ -73,14 +73,14 @@ class _DashboardViewState extends State<DashboardView> {
// await requestDetailProvider.engineerRejectWorkOrder(id: '3', feedBack: 'Abcdef'); // await requestDetailProvider.engineerRejectWorkOrder(id: '3', feedBack: 'Abcdef');
// await dashBoardProvider.getDashBoardCount(usersType: user.type!); // await dashBoardProvider.getDashBoardCount(usersType: user.type!);
// await getAllRequests(); // await getAllRequests();
if (isFCM) { // if (isFCM) {
FirebaseNotificationManger.initialized(context); // FirebaseNotificationManger.initialized(context);
NotificationManger.initialisation((notificationDetails) { // NotificationManger.initialisation((notificationDetails) {
FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!)); // FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!));
}, (id, title, body, payload) async {}); // }, (id, title, body, payload) async {});
//
isFCM = false; // isFCM = false;
} // }
}); });
} }

@ -136,6 +136,7 @@ import 'providers/service_request_providers/reject_reason_provider.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
// HttpOverrides.global = MyHttpOverrides(); // for later use. // HttpOverrides.global = MyHttpOverrides(); // for later use.
_configureLocalTimeZone(); _configureLocalTimeZone();
NotificationManger.initialisation((notificationDetails) {}, (id, title, body, payload) async {}); NotificationManger.initialisation((notificationDetails) {}, (id, title, body, payload) async {});

@ -12,6 +12,7 @@ class User {
List<String>? departmentName; List<String>? departmentName;
String? message; String? message;
String? username; String? username;
String? employeeId;
String? userID; String? userID;
String? email; String? email;
String? password; String? password;
@ -53,6 +54,7 @@ class User {
this.departmentName, this.departmentName,
this.message, this.message,
this.username, this.username,
this.employeeId,
this.userID, this.userID,
this.email, this.email,
this.password, this.password,
@ -151,6 +153,7 @@ class User {
map['message'] = message; map['message'] = message;
map['username'] = username; map['username'] = username;
map['userID'] = userID; map['userID'] = userID;
map['employeeId'] = employeeId;
map['email'] = email; map['email'] = email;
map['password'] = password; map['password'] = password;
map['token'] = token; map['token'] = token;
@ -212,6 +215,7 @@ class User {
message = json['message']; message = json['message'];
username = json['username']; username = json['username'];
userID = json['userID']; userID = json['userID'];
employeeId = json['employeeId'];
email = json['email']; email = json['email'];
password = json['password']; password = json['password'];
token = json['token']; token = json['token'];

@ -13,6 +13,7 @@ import 'package:test_sa/modules/cm_module/cm_detail_provider.dart';
import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart'; import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart';
import 'package:test_sa/modules/cx_module/chat/chat_page.dart'; import 'package:test_sa/modules/cx_module/chat/chat_page.dart';
import 'package:test_sa/modules/cx_module/chat/chat_provider.dart'; import 'package:test_sa/modules/cx_module/chat/chat_provider.dart';
import 'package:test_sa/modules/cx_module/chat/chat_widget.dart';
import 'package:test_sa/modules/cx_module/survey/survey_page.dart'; import 'package:test_sa/modules/cx_module/survey/survey_page.dart';
import 'package:test_sa/modules/loan_module/pages/create_loan_request_page.dart'; import 'package:test_sa/modules/loan_module/pages/create_loan_request_page.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
@ -23,8 +24,9 @@ import 'views/components/service_request_detail_view.dart';
class CMDetailPage extends StatefulWidget { class CMDetailPage extends StatefulWidget {
final int requestId; final int requestId;
final int moduleId;
CMDetailPage({Key? key, required this.requestId}) : super(key: key); CMDetailPage({Key? key, required this.requestId, required this.moduleId}) : super(key: key);
@override @override
_CMDetailPageState createState() { _CMDetailPageState createState() {
@ -40,6 +42,7 @@ class _CMDetailPageState extends State<CMDetailPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_requestProvider = Provider.of<CMDetailProvider>(context, listen: false);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
Provider.of<ChatProvider>(context, listen: false).reset(); Provider.of<ChatProvider>(context, listen: false).reset();
getInitialData(); getInitialData();
@ -89,85 +92,46 @@ class _CMDetailPageState extends State<CMDetailPage> {
Navigator.pop(context); Navigator.pop(context);
}, },
actions: [ actions: [
if (context.userProvider.isEngineer || context.userProvider.isNurse) Selector<CMDetailProvider, bool>(
Selector<CMDetailProvider, bool>( selector: (_, myModel) => myModel.isLoading, // Selects only the userName
selector: (_, myModel) => myModel.isLoading, // Selects only the userName builder: (_, isLoading, __) {
builder: (_, isLoading, __) { if (isLoading) {
if (isLoading) { return const SizedBox();
return const SizedBox(); } else {
} else { CMDetailProvider provider = Provider.of<CMDetailProvider>(context, listen: false);
CMDetailProvider provider = Provider.of<CMDetailProvider>(context, listen: false); if ((context.userProvider.isEngineer || context.userProvider.isNurse) &&
int? statusValue = provider.currentWorkOrder?.data?.status?.value; provider.currentWorkOrder?.data?.assignedEmployee != null &&
if (statusValue == 2 || statusValue == 3 || statusValue == 5 || statusValue == 6) { (provider.currentWorkOrder?.data?.workOrderContactPerson?.isNotEmpty ?? false)) {
getChatToken(moduleId, provider.currentWorkOrder?.data?.workOrderNo ?? ""); return ChatWidget(
return Consumer<ChatProvider>(builder: (pContext, requestProvider, _) { moduleId: widget.moduleId,
return IconButton( isShow: context.settingProvider.isUserFlowMedical && (context.userProvider.isEngineer || context.userProvider.isNurse) && provider.currentWorkOrder?.data?.assignedEmployee != null,
icon: const Icon(Icons.chat_bubble), isReadOnly: _requestProvider.isReadOnlyRequest,
onPressed: () { requestId: widget.requestId.toInt(),
Navigator.push( assigneeEmployeeNumber: provider.currentWorkOrder?.data?.assignedEmployee!.employeeId!,
context, myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!,
CupertinoPageRoute( contactEmployeeINumber: provider.currentWorkOrder?.data?.workOrderContactPerson.first.employeeId,
builder: (context) => ChatPage( );
moduleId: moduleId,
requestId: widget.requestId,
title: _requestProvider.currentWorkOrder?.data?.workOrderNo ?? "",
readOnly: _requestProvider.isReadOnlyRequest,
)));
},
).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30);
});
}
return const SizedBox();
}
}),
if (isNurse)
IconButton(
icon: 'qr'.toSvgAsset(height: 24, width: 24),
onPressed: () {
ServiceRequestBottomSheet.getQRCodeBottomSheet(context: context);
},
)
else ...[
Selector<CMDetailProvider, bool>(
selector: (_, myModel) => myModel.isLoading, // Selects only the userName
builder: (_, isLoading, __) {
if (isLoading) {
return const SizedBox();
} else {
CMDetailProvider provider = Provider.of<CMDetailProvider>(context, listen: false);
int? statusValue = provider.currentWorkOrder?.data?.status?.value;
if (statusValue == 2) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
margin: const EdgeInsets.only(left: 2),
decoration: BoxDecoration(color: context.isDark ? AppColor.neutral50 : AppColor.neutral30, borderRadius: BorderRadius.circular(16)),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.add, size: 20, color: AppColor.black1E),
Text(
"Loan",
style: AppTextStyles.bodyText2.copyWith(color: AppColor.black1E),
),
4.width,
],
),
).onPress(() {
CMDetailProvider provider = Provider.of<CMDetailProvider>(context, listen: false);
Navigator.push(context, MaterialPageRoute(builder: (context) => CreateLoanRequestPage(workOrderId: widget.requestId, workOrder: provider.currentWorkOrder!.data)));
});
}
return const SizedBox();
} }
}), return const SizedBox();
IconButton( }
icon: const Icon(Icons.home), }),
onPressed: () { isNurse
// stopTimer(); ? IconButton(
Navigator.pop(context); icon: 'qr'.toSvgAsset(
}, height: 24,
) width: 24,
], ),
onPressed: () {
ServiceRequestBottomSheet.getQRCodeBottomSheet(context: context);
},
)
: IconButton(
icon: const Icon(Icons.home),
onPressed: () {
// stopTimer();
Navigator.pop(context);
},
),
], ],
), ),
body: DefaultTabController( body: DefaultTabController(

@ -300,7 +300,7 @@ class _CreateCMRequestState extends State<CreateCMRequest> with TickerProviderSt
bool checkPendingRequest = false; bool checkPendingRequest = false;
void showPendingRequests() { void showPendingRequests() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => PendingServiceRequestScreen(pendingAssetServiceRequest!))); Navigator.of(context).push(MaterialPageRoute(builder: (_) => PendingServiceRequestScreen(pendingAssetServiceRequest!, 1)));
} }
void showPendingRequestBottomSheet() async { void showPendingRequestBottomSheet() async {

@ -35,6 +35,7 @@ import 'model/user_chat_history_model.dart';
// import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as user; // import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as user;
// import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; // import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav;
//Need to refector this remove unused code.
class ChatApiClient { class ChatApiClient {
static final ChatApiClient _instance = ChatApiClient._internal(); static final ChatApiClient _instance = ChatApiClient._internal();
@ -81,8 +82,9 @@ class ChatApiClient {
} }
Future<ChatParticipantModel?> loadParticipants(int moduleId, int referenceId, String? assigneeEmployeeNumber) async { Future<ChatParticipantModel?> loadParticipants(int moduleId, int referenceId, String? assigneeEmployeeNumber) async {
Response response = Response response = await ApiClient().getJsonForResponse(
await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber", token: chatLoginResponse!.token); "${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber&requestType=chat&transactionType=17",
token: chatLoginResponse!.token);
if (!kReleaseMode) { if (!kReleaseMode) {
// logger.i("login-res: " + response.body); // logger.i("login-res: " + response.body);
@ -94,6 +96,20 @@ class ChatApiClient {
} }
} }
Future<bool> resetCountApi(int moduleCode, int referenceNumber, String? employeeNumber) async {
final Map<String, dynamic> payload = {
'moduleCode': "$moduleCode",
'ReferenceNumber': "$referenceNumber",
};
final Response response = await ApiClient().postJsonForResponse(
URLs.resetMessageCount,
payload,
token: chatLoginResponse!.token,
);
return response.statusCode == 200;
}
Future<List<ChatAttachment>> viewAllDocuments(int moduleId, int referenceId) async { Future<List<ChatAttachment>> viewAllDocuments(int moduleId, int referenceId) async {
Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/attachments/conversation?referenceId=$referenceId&moduleCode=$moduleId", token: chatLoginResponse!.token); Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/attachments/conversation?referenceId=$referenceId&moduleCode=$moduleId", token: chatLoginResponse!.token);

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:audio_waveforms/audio_waveforms.dart';
@ -29,6 +30,7 @@ import 'helper/chat_file_viewer.dart';
import 'model/get_single_user_chat_list_model.dart'; import 'model/get_single_user_chat_list_model.dart';
import 'model/user_chat_history_model.dart'; import 'model/user_chat_history_model.dart';
//Need to refactor this ...
enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted }
class ChatPage extends StatefulWidget { class ChatPage extends StatefulWidget {
@ -66,7 +68,10 @@ class _ChatPageState extends State<ChatPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
loadChatHistory(); WidgetsBinding.instance.addPostFrameCallback((_) {
loadChatHistory();
});
playerController.addListener(() async { playerController.addListener(() async {
// if (playerController.playerState == PlayerState.playing && playerController.maxDuration == await playerController.getDuration()) { // if (playerController.playerState == PlayerState.playing && playerController.maxDuration == await playerController.getDuration()) {
// await playerController.stopPlayer(); // await playerController.stopPlayer();
@ -75,7 +80,7 @@ class _ChatPageState extends State<ChatPage> {
}); });
} }
void loadChatHistory() { void loadChatHistory() async {
// // String assigneeEmployeeNumber = Provider.of<ServiceRequestDetailProvider>(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? ""; // // String assigneeEmployeeNumber = Provider.of<ServiceRequestDetailProvider>(context, listen: false).currentWorkOrder?.data?.assignedEmployee?.employeeId ?? "";
// // String myEmployeeId = context.userProvider.user!.username!; // // String myEmployeeId = context.userProvider.user!.username!;
// // // //
@ -99,7 +104,14 @@ class _ChatPageState extends State<ChatPage> {
? Provider.of<CMDetailProvider>(context, listen: false).currentWorkOrder!.data!.workOrderCreatedBy!.employeeId! ? Provider.of<CMDetailProvider>(context, listen: false).currentWorkOrder!.data!.workOrderCreatedBy!.employeeId!
: Provider.of<CMDetailProvider>(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!)) : Provider.of<CMDetailProvider>(context, listen: false).currentWorkOrder!.data!.workOrderContactPerson.first.employeeId!))
: ""); : "");
Provider.of<ChatProvider>(context, listen: false).connectToHub(widget.moduleId, widget.requestId, myEmployeeId, receiver, widget.readOnly, isMounted: mounted); final chatProvider = context.read<ChatProvider>();
// final chatProvider = Provider.of<C;
chatProvider.connectToHub(widget.moduleId, widget.requestId, myEmployeeId, receiver, widget.readOnly, isMounted: mounted);
bool readStatus = await chatProvider.resetCount(moduleId: widget.moduleId, referenceNo: widget.requestId, userId: context.userProvider.user?.id);
if (readStatus) {
chatProvider.chatParticipantModel?.unreadCount = 0;
}
} }
@override @override
@ -231,7 +243,9 @@ class _ChatPageState extends State<ChatPage> {
} }
return Column(mainAxisSize: MainAxisSize.min, children: [ return Column(mainAxisSize: MainAxisSize.min, children: [
if (showDateHeader) dateCard(currentMessage.createdDate?.toString().chatMsgDateWithYear ?? ""), if (showDateHeader) dateCard(currentMessage.createdDate?.toString().chatMsgDateWithYear ?? ""),
isSender ? senderMsgCard(showSenderName, chatProvider.chatResponseList[index]) : recipientMsgCard(showSenderName, chatProvider.chatResponseList[index]) isSender
? senderMsgCard(showSenderName, chatProvider.chatResponseList[index], index: index)
: recipientMsgCard(showSenderName, chatProvider.chatResponseList[index])
]); ]);
}, },
itemCount: chatProvider.chatResponseList.length)) itemCount: chatProvider.chatResponseList.length))
@ -607,7 +621,7 @@ class _ChatPageState extends State<ChatPage> {
.center; .center;
} }
Widget senderMsgCard(bool showHeader, SingleUserChatModel? chatResponse, {bool loading = false, String msg = ""}) { Widget senderMsgCard(bool showHeader, SingleUserChatModel? chatResponse, {bool loading = false, String msg = "", int index = 0}) {
Widget senderHeader = Row( Widget senderHeader = Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:audio_waveforms/audio_waveforms.dart';
@ -40,6 +41,7 @@ import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:signalr_netcore/hub_connection.dart'; import 'package:signalr_netcore/hub_connection.dart';
import 'package:signalr_netcore/signalr_client.dart'; import 'package:signalr_netcore/signalr_client.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart'; import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/modules/cx_module/chat/model/chat_login_response_model.dart'; import 'package:test_sa/modules/cx_module/chat/model/chat_login_response_model.dart';
@ -54,6 +56,8 @@ import 'model/get_single_user_chat_list_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';
//Need to refactor this remove unused code.
HubConnection? chatHubConnection; HubConnection? chatHubConnection;
class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin { class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
@ -248,6 +252,9 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
chatHubConnection!.on("OnSubmitChatAsync", OnSubmitChatAsync); chatHubConnection!.on("OnSubmitChatAsync", OnSubmitChatAsync);
chatHubConnection!.on("OnTypingAsync", OnTypingAsync); chatHubConnection!.on("OnTypingAsync", OnTypingAsync);
chatHubConnection!.on("OnStopTypingAsync", OnStopTypingAsync); chatHubConnection!.on("OnStopTypingAsync", OnStopTypingAsync);
//Need by Chat Backend for seen and un seen.
chatHubConnection!.on("OnSeenChatUserAsync", onSeenUserChatAsync);
chatHubConnection!.on("OnAckSeenAsync", onAckSeenAsync);
//group On message //group On message
@ -370,7 +377,19 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
// } // }
} }
} }
// notifyListeners(); }
Future<bool> resetCount({
required int moduleId,
required int referenceNo,
String? userId,
}) async {
try {
return await ChatApiClient().resetCountApi(moduleId, referenceNo, userId);
} catch (e, stack) {
debugPrint('resetCount error: $e');
rethrow;
}
} }
void updateUserChatHistoryStatusAsync(List data) { void updateUserChatHistoryStatusAsync(List data) {
@ -453,6 +472,15 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
print(args); print(args);
} }
Future<void> markMessageAsRead(int messageId) async {
final senderId = sender?.userId;
if (senderId == null) return;
chatHubConnection?.invoke(
"SendMessageReadAsync",
args: [messageId, senderId],
);
}
void onChatSeen(List<Object?>? args) { void onChatSeen(List<Object?>? args) {
dynamic items = args!.toList(); dynamic items = args!.toList();
// for (var user in searchedChats!) { // for (var user in searchedChats!) {
@ -559,6 +587,57 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
notifyListeners(); notifyListeners();
} }
Future<void> onSeenUserChatAsync(List<Object?>? parameters) async {
try {
if (parameters == null || parameters.isEmpty) {
log('onSeenUserChatAsync: parameters are null or empty');
return;
}
final parm = parameters.first;
if (parm is! List || parm.isEmpty) {
log('onSeenUserChatAsync: parm is not a valid list');
return;
}
final firstItem = parm.first;
if (firstItem is! Map<String, dynamic>) {
log('onSeenUserChatAsync: firstItem is not a Map');
return;
}
await chatHubConnection!.invoke(
"AckSeenAsync",
args: [
firstItem['currentUserId'],
[firstItem['userChatHistoryId']],
],
);
} catch (e, stackTrace) {
log('onSeenUserChatAsync error: $e');
log('StackTrace: $stackTrace');
}
}
Future<void> onAckSeenAsync(List<Object?>? parameters) async {
try {
if (parameters == null || parameters.isEmpty) {
log('onAckSeenAsync: parameters are null or empty');
return;
}
final parm = parameters.first;
log('parm onAckSeenAsync $parm');
if (chatResponseList.isEmpty) {
log('onAckSeenAsync: chatResponseList is empty');
return;
}
log('last list item id ${chatResponseList.first.toJson()}');
chatResponseList.first.isSeen = true;
notifyListeners();
} catch (e, stackTrace) {
log('onAckSeenAsync error: $e');
log('StackTrace: $stackTrace');
}
}
// Future<void> OnSubmitChatAsync(List<Object?>? parameters) async { // Future<void> OnSubmitChatAsync(List<Object?>? parameters) async {
// // List data = jsonDecode(parameters!.first!.toString()); // // List data = jsonDecode(parameters!.first!.toString());
// //

@ -1,9 +1,12 @@
import 'package:flutter/cupertino.dart'; 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/extensions/context_extension.dart'; import 'package:test_sa/extensions/context_extension.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_detail_provider.dart'; import 'package:test_sa/modules/cm_module/cm_detail_provider.dart';
import 'package:test_sa/new_views/common_widgets/custom_badge.dart';
import 'chat_page.dart'; import 'chat_page.dart';
import 'chat_provider.dart'; import 'chat_provider.dart';
@ -40,8 +43,10 @@ class _ChatWidgetState extends State<ChatWidget> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
Provider.of<ChatProvider>(context, listen: false).reset(); WidgetsBinding.instance.addPostFrameCallback((_) {
getChatToken(); Provider.of<ChatProvider>(context, listen: false).reset();
getChatToken();
});
} }
void getChatToken() { void getChatToken() {
@ -74,24 +79,31 @@ class _ChatWidgetState extends State<ChatWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return widget.isShow return widget.isShow
? Consumer<ChatProvider>(builder: (pContext, requestProvider, _) { ? Consumer<ChatProvider>(builder: (pContext, chatProvider, _) {
return IconButton( final int unreadCount = (!chatProvider.chatLoginTokenLoading && (chatProvider.chatParticipantModel?.unreadCount ?? 0) > 0) ? chatProvider.chatParticipantModel!.unreadCount! : 0;
icon: const Icon(Icons.chat_bubble), return CustomBadge2(
onPressed: () { value: unreadCount,
Navigator.push( top: 2,
context, right: 2,
CupertinoPageRoute( minSize: 18,
builder: (context) => ChatPage( child: IconButton(
moduleId: widget.moduleId, icon: const Icon(Icons.chat_bubble),
requestId: widget.requestId, onPressed: () {
title: widget.title, Navigator.push(
readOnly: widget.isReadOnly, context,
assigneeEmployeeNumber: widget.assigneeEmployeeNumber, CupertinoPageRoute(
contactEmployeeINumber: widget.contactEmployeeINumber, builder: (context) => ChatPage(
myLoginUserID: widget.myLoginUserID, moduleId: widget.moduleId,
))); requestId: widget.requestId,
}, title: widget.title,
).toShimmer(context: context, isShow: requestProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30); readOnly: widget.isReadOnly,
assigneeEmployeeNumber: widget.assigneeEmployeeNumber,
contactEmployeeINumber: widget.contactEmployeeINumber,
myLoginUserID: widget.myLoginUserID,
)));
},
).toShimmer(context: context, isShow: chatProvider.chatLoginTokenLoading, radius: 30, height: 30, width: 30),
);
}) })
: const SizedBox(); : const SizedBox();
} }

@ -46,6 +46,7 @@ class ChatFilePicker extends StatelessWidget {
fromMediaPicker(BuildContext context, ImageSource imageSource) async { fromMediaPicker(BuildContext context, ImageSource imageSource) async {
XFile? pickedFile = await ImagePicker().pickImage(source: imageSource, imageQuality: 70, maxWidth: 800, maxHeight: 800); XFile? pickedFile = await ImagePicker().pickImage(source: imageSource, imageQuality: 70, maxWidth: 800, maxHeight: 800);
if (pickedFile != null) { if (pickedFile != null) {
//Has UI issues here top buttons not clickable smoothly
CroppedFile? croppedFile = await ImageCropper().cropImage( CroppedFile? croppedFile = await ImageCropper().cropImage(
sourcePath: pickedFile.path, sourcePath: pickedFile.path,
// aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1), // aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1),

@ -24,6 +24,7 @@ class ChatFileViewer extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FutureBuilder<File?>( return FutureBuilder<File?>(
future: checkFileInLocalStorage(), future: checkFileInLocalStorage(),
builder: (BuildContext context, AsyncSnapshot<File?> snapshot) { builder: (BuildContext context, AsyncSnapshot<File?> snapshot) {

@ -1,12 +1,15 @@
import 'dart:developer';
class ChatParticipantModel { class ChatParticipantModel {
int? id; int? id;
String? title; String? title;
String? conversationType; String? conversationType;
List<Participants>? participants; List<Participants>? participants;
String? lastMessage; dynamic lastMessage;
String? createdAt; String? createdAt;
int? unreadCount;
ChatParticipantModel({this.id, this.title, this.conversationType, this.participants, this.lastMessage, this.createdAt}); ChatParticipantModel({this.id, this.title, this.conversationType, this.participants, this.createdAt, this.unreadCount});
ChatParticipantModel.fromJson(Map<String, dynamic> json) { ChatParticipantModel.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
@ -20,18 +23,20 @@ class ChatParticipantModel {
} }
lastMessage = json['lastMessage']; lastMessage = json['lastMessage'];
createdAt = json['createdAt']; createdAt = json['createdAt'];
unreadCount = json['unreadCount'];
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>(); final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = this.id; data['id'] = id;
data['title'] = this.title; data['title'] = title;
data['conversationType'] = this.conversationType; data['conversationType'] = conversationType;
if (this.participants != null) { if (participants != null) {
data['participants'] = this.participants!.map((v) => v.toJson()).toList(); data['participants'] = participants!.map((v) => v.toJson()).toList();
} }
data['lastMessage'] = this.lastMessage; data['lastMessage'] = lastMessage;
data['createdAt'] = this.createdAt; data['createdAt'] = createdAt;
data['unreadCount'] = unreadCount;
return data; return data;
} }
} }
@ -54,12 +59,12 @@ class Participants {
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>(); final Map<String, dynamic> data = <String, dynamic>{};
data['userId'] = this.userId; data['userId'] = userId;
data['userName'] = this.userName; data['userName'] = userName;
data['employeeNumber'] = this.employeeNumber; data['employeeNumber'] = employeeNumber;
data['role'] = this.role; data['role'] = role;
data['userStatus'] = this.userStatus; data['userStatus'] = userStatus;
return data; return data;
} }
} }

@ -1,8 +1,7 @@
import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/new_models/building.dart'; import 'package:test_sa/models/new_models/mapped_sites.dart';
import 'package:test_sa/models/new_models/department.dart';
import 'package:test_sa/models/new_models/floor.dart';
import 'package:test_sa/models/new_models/site.dart'; import 'package:test_sa/models/new_models/site.dart';
import 'package:test_sa/models/new_models/traf_department.dart';
import 'package:test_sa/modules/loan_module/models/medical_department_model.dart'; import 'package:test_sa/modules/loan_module/models/medical_department_model.dart';
class LoanFormModel { class LoanFormModel {
@ -21,6 +20,8 @@ class LoanFormModel {
Site? site; Site? site;
MedicalDepartmentModel? department; MedicalDepartmentModel? department;
List<LoanAttachments>? loanAttachment; List<LoanAttachments>? loanAttachment;
MappedSite? mappedSite;
TrafDepartment? mappedDepartment;
LoanFormModel({ LoanFormModel({
this.docName, this.docName,
@ -38,6 +39,8 @@ class LoanFormModel {
this.loanAttachment, this.loanAttachment,
this.site, this.site,
this.department, this.department,
this.mappedSite,
this.mappedDepartment,
}); });
//{ //{
@ -91,8 +94,10 @@ class LoanFormModel {
"vendorNumber": vendorNumber, "vendorNumber": vendorNumber,
"vendorContact": vendorNumber, "vendorContact": vendorNumber,
"vendorEmail": vendorEmail, "vendorEmail": vendorEmail,
'siteId': site?.id, // 'siteId': site?.id,
'departmentId': department?.id, 'siteId': mappedSite?.id,
// 'departmentId': department?.id,
'departmentId': mappedDepartment?.id,
"loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [], "loanAttachments": loanAttachment != null ? loanAttachment!.map((v) => v.toJson()).toList() : [],
}; };
} }

@ -1,39 +1,33 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
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/providers/api/device_transfer_provider.dart';
import 'package:test_sa/controllers/validator/validator.dart'; import 'package:test_sa/controllers/validator/validator.dart';
import 'package:test_sa/dashboard_latest/dashboard_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/helper/utils.dart';
import 'package:test_sa/models/device/asset.dart';
import 'package:test_sa/models/enums/user_types.dart';
import 'package:test_sa/models/generic_attachment_model.dart'; import 'package:test_sa/models/generic_attachment_model.dart';
import 'package:test_sa/models/lookup.dart'; import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/new_models/site.dart'; import 'package:test_sa/models/new_models/mapped_sites.dart';
import 'package:test_sa/models/new_models/task_request/task_type_model.dart'; import 'package:test_sa/models/new_models/task_request/task_type_model.dart';
import 'package:test_sa/models/new_models/traf_department.dart';
import 'package:test_sa/models/new_models/work_order_detail_model.dart'; import 'package:test_sa/models/new_models/work_order_detail_model.dart';
import 'package:test_sa/modules/cm_module/cm_request_utils.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_form_model.dart';
import 'package:test_sa/modules/loan_module/models/medical_department_model.dart';
import 'package:test_sa/modules/loan_module/provider/loan_period_provider.dart'; import 'package:test_sa/modules/loan_module/provider/loan_period_provider.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/modules/loan_module/provider/loan_provider.dart';
import 'package:test_sa/modules/loan_module/provider/medical_department_provider.dart'; import 'package:test_sa/modules/loan_module/provider/medical_department_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';
import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart';
import 'package:test_sa/providers/department_provider.dart';
import 'package:test_sa/providers/gas_request_providers/site_provider.dart'; import 'package:test_sa/providers/gas_request_providers/site_provider.dart';
import 'package:test_sa/providers/loading_list_notifier.dart'; import 'package:test_sa/providers/loading_list_notifier.dart';
import 'package:test_sa/providers/lookups/department_lookup_provider.dart';
import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart';
import '../../../../../../new_views/common_widgets/default_app_bar.dart'; import '../../../../../../new_views/common_widgets/default_app_bar.dart';
@ -275,10 +269,10 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
return [ return [
'Item Details'.addTranslation.bodyText(context).custom(color: AppColor.black10), 'Item Details'.addTranslation.bodyText(context).custom(color: AppColor.black10),
8.height, 8.height,
SingleItemDropDownMenu<Site, SiteProvider>( SingleItemDropDownMenu<MappedSite, MappedSiteProvider>(
context: context, context: context,
title: context.translation.site, title: context.translation.site,
initialValue: _loanFormModel.site, initialValue: _loanFormModel.mappedSite,
showShadow: false, showShadow: false,
validator: (value) { validator: (value) {
if (value == null) return "Please select a site"; if (value == null) return "Please select a site";
@ -287,12 +281,17 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
showAsBottomSheet: true, showAsBottomSheet: true,
onSelect: (value) { onSelect: (value) {
_loanFormModel.site = value; if(value!=null){
setState(() {}); _loanFormModel.mappedSite = value;
_loanFormModel.mappedDepartment = null;
Provider.of<DepartmentLookupProvider>(context,listen:false).getData(id:_loanFormModel.mappedSite?.id);
setState(() {});
}
}, },
), ),
8.height, 8.height,
SingleItemDropDownMenu<MedicalDepartmentModel, MedicalDepartmentProvider>( SingleItemDropDownMenu<TrafDepartment, DepartmentLookupProvider>(
context: context, context: context,
title: context.translation.department, title: context.translation.department,
showShadow: false, showShadow: false,
@ -301,11 +300,11 @@ class _CreateLoanRequestPageState extends State<CreateLoanRequestPage> with Tick
return null; return null;
}, },
showAsBottomSheet: true, showAsBottomSheet: true,
initialValue: _loanFormModel.department, initialValue: _loanFormModel.mappedDepartment,
requestById: context.userProvider.user?.clientId, requestById: context.userProvider.user?.clientId,
backgroundColor: AppColor.fieldBgColor(context), backgroundColor: AppColor.fieldBgColor(context),
onSelect: (value) { onSelect: (value) {
_loanFormModel.department = value; _loanFormModel.mappedDepartment = value;
setState(() {}); setState(() {});
}, },
), ),

@ -62,10 +62,6 @@ class _CreateDeviceTransferRequestState extends State<CreateDeviceTransferReques
bool checkPendingRequest = false; bool checkPendingRequest = false;
void showPendingRequests() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => PendingServiceRequestScreen(pendingAssetServiceRequest!)));
}
void _onSubmit() async { void _onSubmit() async {
_transferModel.assetId = _pickedAsset?.id; _transferModel.assetId = _pickedAsset?.id;
_transferModel.destSiteId = _assetDestination.site?.id; _transferModel.destSiteId = _assetDestination.site?.id;

@ -223,11 +223,11 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
if (context.userProvider.isEngineer || context.userProvider.isNurse) if (context.userProvider.isEngineer || context.userProvider.isNurse)
ChatWidget( ChatWidget(
moduleId: widget.moduleId, moduleId: widget.moduleId,
isShow: _model!.senderMachineStatusValue! != 4, isShow: context.settingProvider.isUserFlowMedical && _model!.senderMachineStatusValue! != 4,
isReadOnly: _model!.senderMachineStatusValue! != 1, isReadOnly: _model!.senderMachineStatusValue! != 1,
requestId: widget.model.id!.toInt(), requestId: widget.model.id!.toInt(),
assigneeEmployeeNumber: _model!.senderAssignedEmployeeNumber, assigneeEmployeeNumber: _model!.senderAssignedEmployeeNumber,
myLoginUserID: context.userProvider.user!.username!, myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!,
contactEmployeeINumber: _model!.assetTransferContactPersons!.first.employeeNumber, contactEmployeeINumber: _model!.assetTransferContactPersons!.first.employeeNumber,
), ),
if ((_userProvider!.user?.type == UsersTypes.engineer)) if ((_userProvider!.user?.type == UsersTypes.engineer))
@ -284,11 +284,11 @@ class _DeviceTransferDetailsState extends State<DeviceTransferDetails> {
if (context.userProvider.isEngineer || context.userProvider.isNurse) if (context.userProvider.isEngineer || context.userProvider.isNurse)
ChatWidget( ChatWidget(
moduleId: widget.moduleId, moduleId: widget.moduleId,
isShow: (isSender ? _deviceTransfer.senderMachineStatusValue! : _deviceTransfer.receiverMachineStatusValue!) != 0, isShow: context.settingProvider.isUserFlowMedical && (isSender ? _deviceTransfer.senderMachineStatusValue! : _deviceTransfer.receiverMachineStatusValue!) != 0,
isReadOnly: (isSender ? _deviceTransfer.senderMachineStatusValue! : _deviceTransfer.receiverMachineStatusValue) != 1, isReadOnly: (isSender ? _deviceTransfer.senderMachineStatusValue! : _deviceTransfer.receiverMachineStatusValue) != 1,
requestId: widget.model.id!.toInt(), requestId: widget.model.id!.toInt(),
assigneeEmployeeNumber: isSender ? _deviceTransfer.senderAssignedEmployeeNumber! : _deviceTransfer.receiverAssignedEmployeeNumber!, assigneeEmployeeNumber: isSender ? _deviceTransfer.senderAssignedEmployeeNumber! : _deviceTransfer.receiverAssignedEmployeeNumber!,
myLoginUserID: context.userProvider.user!.username!, myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!,
contactEmployeeINumber: _deviceTransfer.assetTransferContactPersons!.first.employeeNumber, contactEmployeeINumber: _deviceTransfer.assetTransferContactPersons!.first.employeeNumber,
), ),
if ((_userProvider!.user?.type == UsersTypes.engineer)) if ((_userProvider!.user?.type == UsersTypes.engineer))

@ -68,11 +68,11 @@ class _GasRefillDetailsPageState extends State<GasRefillDetailsPage> {
return ChatWidget( return ChatWidget(
moduleId: widget.moduleId, moduleId: widget.moduleId,
isShow: _gasRefillModel.status!.value! != 0, isShow: context.settingProvider.isUserFlowMedical && _gasRefillModel.status!.value! != 0,
isReadOnly: _gasRefillModel.status!.value! != 1, isReadOnly: _gasRefillModel.status!.value! != 1,
requestId: widget.model.id!.toInt(), requestId: widget.model.id!.toInt(),
assigneeEmployeeNumber: _gasRefillModel.assignedEmployee?.employeeId!, assigneeEmployeeNumber: _gasRefillModel.assignedEmployee?.employeeId!,
myLoginUserID: context.userProvider.user!.username!, myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!,
contactEmployeeINumber: _gasRefillModel.gasRefillContactPerson!.first.employeeCode!, contactEmployeeINumber: _gasRefillModel.gasRefillContactPerson!.first.employeeCode!,
); );
}) })

@ -75,16 +75,20 @@ class _TaskRequestDetailsViewState extends State<TaskRequestDetailsView> {
selector: (_, myModel) => myModel.taskRequestModel, // Selects only the userName selector: (_, myModel) => myModel.taskRequestModel, // Selects only the userName
builder: (_, _taskReqModel, __) { builder: (_, _taskReqModel, __) {
if (_taskReqModel == null) return const SizedBox(); if (_taskReqModel == null) return const SizedBox();
if ((context.userProvider.isEngineer || context.userProvider.isNurse) &&
return ChatWidget( _taskReqModel.assignedEngineer?.employeeId != null &&
moduleId: widget.moduleId, (_taskReqModel.taskJobContactPersons?.isNotEmpty ?? false)) {
isShow: _taskReqModel.taskJobStatus!.value! != 1, return ChatWidget(
isReadOnly: _taskReqModel.taskJobStatus!.value! != 2, moduleId: widget.moduleId,
requestId: widget.taskId.toInt(), isShow: context.settingProvider.isUserFlowMedical && _taskReqModel.taskJobStatus!.value! != 1,
assigneeEmployeeNumber: _taskReqModel.assignedEngineer?.employeeId!, isReadOnly: _taskReqModel.taskJobStatus!.value! != 2,
myLoginUserID: context.userProvider.user!.username!, requestId: widget.taskId.toInt(),
contactEmployeeINumber: _taskReqModel.taskJobContactPersons!.first.user?.employeeId, assigneeEmployeeNumber: _taskReqModel.assignedEngineer?.employeeId!,
); myLoginUserID: context.userProvider.user!.employeeId ?? context.userProvider.user!.username!,
contactEmployeeINumber: _taskReqModel.taskJobContactPersons!.first.user?.employeeId,
);
} else
return const SizedBox();
}) })
], ],
), ),

@ -5,12 +5,20 @@ import 'package:test_sa/new_views/app_style/app_color.dart';
class CustomBadge extends StatelessWidget { class CustomBadge extends StatelessWidget {
final Widget child; // The widget that the badge will be overlaid on. final Widget child; // The widget that the badge will be overlaid on.
final int value; // The value or text to be displayed in the badge. final int value; // The value or text to be displayed in the badge.
final Color color; // The background color of the badge. final Color color;
final double? positionR;
final double? positionT;
final double? height;
final double? width;
const CustomBadge({ CustomBadge({
Key? key, Key? key,
required this.child, required this.child,
required this.value, required this.value,
this.height,
this.width,
this.positionR,
this.positionT,
this.color = AppColor.red30, // Default color is red this.color = AppColor.red30, // Default color is red
}) : super(key: key); }) : super(key: key);
@ -22,13 +30,14 @@ class CustomBadge extends StatelessWidget {
child, // The main widget child, // The main widget
// if (value > 0) // if (value > 0)
Positioned( Positioned(
right: -6, right: positionR ?? -6,
top: -6, top: positionT ?? -6,
//Need to check why opacity he used here this is not correct need to make this total dynamic and responsive
child: Opacity( child: Opacity(
opacity: value > 0 ? 1 : 0, opacity: value > 0 ? 1 : 0,
child: Container( child: Container(
height: 23, height: height ?? 23,
constraints: const BoxConstraints(minWidth: 23), constraints: BoxConstraints(minWidth: width ?? 23),
padding: const EdgeInsets.all(3), padding: const EdgeInsets.all(3),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(30)), decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(30)),
@ -43,3 +52,139 @@ class CustomBadge extends StatelessWidget {
); );
} }
} }
//Need to use this badge every where..
class CustomBadge2 extends StatelessWidget {
final Widget child;
final int value;
final double top;
final double right;
final double left;
final double bottom;
final double minSize;
final Color backgroundColor;
final Color textColor;
final TextStyle? textStyle;
final int maxValue;
final Duration animationDuration;
const CustomBadge2({
super.key,
required this.child,
required this.value,
this.top = -6,
this.right = -6,
this.left = double.nan,
this.bottom = double.nan,
this.minSize = 18,
this.backgroundColor = AppColor.red30,
this.textColor = AppColor.white10,
this.textStyle,
this.maxValue = 99,
this.animationDuration = const Duration(milliseconds: 200),
});
bool get _isVisible => value > 0;
@override
Widget build(BuildContext context) {
return Stack(
clipBehavior: Clip.none,
children: [
child,
if (_isVisible)
Positioned(
top: top.isNaN ? null : top,
right: right.isNaN ? null : right,
left: left.isNaN ? null : left,
bottom: bottom.isNaN ? null : bottom,
child: AnimatedScale(
scale: _isVisible ? 1 : 0,
duration: animationDuration,
curve: Curves.easeOutBack,
child: AnimatedOpacity(
opacity: _isVisible ? 1 : 0,
duration: animationDuration,
child: _Badge(
value: value,
maxValue: maxValue,
minSize: minSize,
backgroundColor: backgroundColor,
textColor: textColor,
textStyle: textStyle ??
Theme.of(context).textTheme.labelSmall?.copyWith(
fontWeight: FontWeight.w700,
),
),
),
),
),
],
);
}
}
class _Badge extends StatelessWidget {
final int value;
final int maxValue;
final double minSize;
final Color backgroundColor;
final Color textColor;
final TextStyle? textStyle;
const _Badge({
required this.value,
required this.maxValue,
required this.minSize,
required this.backgroundColor,
required this.textColor,
this.textStyle,
});
bool get _isOverflow => value > maxValue;
@override
Widget build(BuildContext context) {
final TextStyle baseStyle = (textStyle ?? Theme.of(context).textTheme.labelMedium)!.copyWith(
color: textColor,
fontWeight: FontWeight.w700,
);
final double badgeSize = minSize;
return IgnorePointer(
child: SizedBox(
width: badgeSize,
height: badgeSize,
child: DecoratedBox(
decoration: const BoxDecoration(
shape: BoxShape.circle,
),
child: DecoratedBox(
decoration: BoxDecoration(
color: backgroundColor,
shape: BoxShape.circle,
),
child: Center(
child: _isOverflow
? FittedBox(
child: Text(
'$maxValue+',
style: baseStyle.copyWith(
fontSize: badgeSize * 0.45,
),
),
)
: CounterAnimatedText(
value: value,
style: baseStyle.copyWith(
fontSize: badgeSize * 0.6,
),
),
),
),
),
),
);
}
}

@ -112,12 +112,14 @@ class CreateRequestModel {
// list.add(CreateRequestModel(module.module!.name!, "add_icon", CreateTaskView.id)); // list.add(CreateRequestModel(module.module!.name!, "add_icon", CreateTaskView.id));
// } // }
// }); // });
if (context.userProvider.isQualityUser) { if (context.userProvider.isQualityUser && context.settingProvider.isUserFlowMedical) {
list.add(CreateRequestModel("Equipment Internal Audit Checklist".addTranslation, "add_icon", CreateEquipmentInternalAuditForm.id)); list.add(CreateRequestModel("Equipment Internal Audit Checklist".addTranslation, "add_icon", CreateEquipmentInternalAuditForm.id));
list.add(CreateRequestModel("System Internal Audit Checklist".addTranslation, "add_icon", CreateSystemInternalAuditForm.id)); list.add(CreateRequestModel("System Internal Audit Checklist".addTranslation, "add_icon", CreateSystemInternalAuditForm.id));
} else if (context.userProvider.isAssessor) { }
list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id)); // else if (context.userProvider.isAssessor) {
} else if (context.userProvider.isEngineer) { // list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id));
// }
else if (context.userProvider.isEngineer) {
if (Provider.of<SettingProvider>(context, listen: false).engineerCanCreateCM) { if (Provider.of<SettingProvider>(context, listen: false).engineerCanCreateCM) {
list.add(CreateRequestModel(context.translation.correctiveMaintenance, "add_icon", CreateCMRequest.id)); list.add(CreateRequestModel(context.translation.correctiveMaintenance, "add_icon", CreateCMRequest.id));
} }
@ -129,7 +131,7 @@ class CreateRequestModel {
list.add(CreateRequestModel(context.translation.transferAsset, "add_icon", CreateDeviceTransferRequest.id)); list.add(CreateRequestModel(context.translation.transferAsset, "add_icon", CreateDeviceTransferRequest.id));
//TODO uncommit this to enable task. //TODO uncommit this to enable task.
list.add(CreateRequestModel(context.translation.task, "add_icon", CreateTaskView.id)); list.add(CreateRequestModel(context.translation.task, "add_icon", CreateTaskView.id));
list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id)); // list.add(CreateRequestModel("TRAF".addTranslation, "add_icon", CreateTRAFRequestPage.id));
list.add(CreateRequestModel('Loan Equipment Request'.addTranslation, "add_icon", CreateLoanRequestPage.id)); list.add(CreateRequestModel('Loan Equipment Request'.addTranslation, "add_icon", CreateLoanRequestPage.id));
} }
return list; return list;

@ -1,8 +1,11 @@
import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:test_sa/controllers/notification/firebase_notification_manger.dart';
import 'package:test_sa/controllers/notification/notification_manger.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart';
import 'package:test_sa/controllers/providers/settings/app_settings.dart'; import 'package:test_sa/controllers/providers/settings/app_settings.dart';
import 'package:test_sa/dashboard_latest/dashboard_view.dart'; import 'package:test_sa/dashboard_latest/dashboard_view.dart';
@ -42,7 +45,7 @@ class _LandPageState extends State<LandPage> {
bool showAppbar = true; bool showAppbar = true;
late List<Widget> _pages; late List<Widget> _pages;
UserProvider? _userProvider; UserProvider? _userProvider;
bool isFCM = true;
@override @override
void initState() { void initState() {
_pages = <Widget>[]; _pages = <Widget>[];
@ -123,7 +126,14 @@ class _LandPageState extends State<LandPage> {
// if (_userProvider!.user!.type != UsersTypes.engineer) const CalendarPage(), // if (_userProvider!.user!.type != UsersTypes.engineer) const CalendarPage(),
const MyAssetsPage(fromBottomBar: true), const MyAssetsPage(fromBottomBar: true),
]; ];
if (isFCM) {
FirebaseNotificationManger.initialized(context);
NotificationManger.initialisation((notificationDetails) {
FirebaseNotificationManger.handleMessage(context, json.decode(notificationDetails.payload!));
}, (id, title, body, payload) async {});
isFCM = false;
}
checkLocalAuth(); checkLocalAuth();
} }

@ -79,8 +79,8 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
if (isEngineer) { if (isEngineer) {
types[context.translation.recurrentWo] = 5; types[context.translation.recurrentWo] = 5;
types["Equipment Internal Audit".addTranslation] = 10; if (context.settingProvider.isUserFlowMedical) types["Equipment Internal Audit".addTranslation] = 10;
types["System Internal Audit".addTranslation] = 11; if (context.settingProvider.isUserFlowMedical) types["System Internal Audit".addTranslation] = 11;
} }
if (context.settingProvider.isUserFlowMedical && isEngineer) { if (context.settingProvider.isUserFlowMedical && isEngineer) {
@ -93,18 +93,18 @@ class _AllRequestsFilterPageState extends State<AllRequestsFilterPage> {
types[module.module!.name!] = module.module!.value!; types[module.module!.name!] = module.module!.value!;
} }
}); });
//Hide traf
// if (!isEngineer) {
// types['TRAF'] = 9;
// }
if (!isEngineer) { // if (context.userProvider.isAssessor) {
types['TRAF'] = 9; // types = {"TRAF": 9};
} // }
if (context.userProvider.isAssessor) {
types = {"TRAF": 9};
}
if (context.userProvider.isQualityUser) { if (context.userProvider.isQualityUser) {
if (context.settingProvider.isUserFlowMedical) types = {'Recall and Alert': 7}; if (context.settingProvider.isUserFlowMedical) types = {'Recall and Alert': 7};
types['Equipment Internal Audit'] = 10; if (context.settingProvider.isUserFlowMedical) types['Equipment Internal Audit'] = 10;
types['System Internal Audit'] = 11; if (context.settingProvider.isUserFlowMedical) types['System Internal Audit'] = 11;
} }
if (context.userProvider.isCommissioningEngineer) { if (context.userProvider.isCommissioningEngineer) {
///TODO need to check what other requests type needed here. ///TODO need to check what other requests type needed here.

@ -62,10 +62,11 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
requestsList.add(Request(module.module!.value!, module.module!.name!.addTranslation)); requestsList.add(Request(module.module!.value!, module.module!.name!.addTranslation));
} }
}); });
if (context.userProvider.user!.type == UsersTypes.normal_user) { //Hide TRAF.
requestsList.add(Request(9, 'TRAF')); // if (context.userProvider.user!.type == UsersTypes.normal_user) {
} // requestsList.add(Request(9, 'TRAF'));
if (context.userProvider.isEngineer) { // }
if (context.userProvider.isEngineer &&context.settingProvider.isUserFlowMedical) {
requestsList.add(Request(10, 'Equipment Internal Audit')); requestsList.add(Request(10, 'Equipment Internal Audit'));
requestsList.add(Request(11, 'System Internal Audit')); requestsList.add(Request(11, 'System Internal Audit'));
//Need to be added for new user role commissioning engineer //Need to be added for new user role commissioning engineer
@ -77,7 +78,7 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
if (context.userProvider.isAssessor) { if (context.userProvider.isAssessor) {
requestsList = [ requestsList = [
Request(null, context.translation.allWorkOrder), Request(null, context.translation.allWorkOrder),
Request(9, 'TRAF'), // Request(9, 'TRAF'),
]; ];
} }
if (context.userProvider.isCommissioningEngineer) { if (context.userProvider.isCommissioningEngineer) {
@ -91,8 +92,8 @@ class _MyRequestsPageState extends State<MyRequestsPage> {
requestsList = [ requestsList = [
Request(null, context.translation.allWorkOrder), Request(null, context.translation.allWorkOrder),
if (context.settingProvider.isUserFlowMedical) Request(7, 'Recall and Alert'), if (context.settingProvider.isUserFlowMedical) Request(7, 'Recall and Alert'),
Request(10, 'Equipment Internal Audit'), if (context.settingProvider.isUserFlowMedical) Request(10, 'Equipment Internal Audit'),
Request(11, 'System Internal Audit'), if (context.settingProvider.isUserFlowMedical) Request(11, 'System Internal Audit'),
]; ];
} }

@ -81,7 +81,7 @@ class ServiceRequestItemView extends StatelessWidget {
), ),
], ],
).toShadowContainer(context, withShadow: showShadow).onPress(() async { ).toShadowContainer(context, withShadow: showShadow).onPress(() async {
await Navigator.of(context).push(MaterialPageRoute(builder: (_) => CMDetailPage(requestId: requestData!.id!))); await Navigator.of(context).push(MaterialPageRoute(builder: (_) => CMDetailPage(requestId: requestData!.id!, moduleId: requestData!.transactionNo!)));
if (refreshData) { if (refreshData) {
Provider.of<DashBoardProvider>(context, listen: false).refreshDashboard(userType: Provider.of<SettingProvider>(context, listen: false).user!.type!, context: context); Provider.of<DashBoardProvider>(context, listen: false).refreshDashboard(userType: Provider.of<SettingProvider>(context, listen: false).user!.type!, context: context);
} }
@ -140,7 +140,7 @@ class ServiceRequestItemView extends StatelessWidget {
), ),
], ],
).toShadowContainer(context, withShadow: showShadow).onPress(() { ).toShadowContainer(context, withShadow: showShadow).onPress(() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CMDetailPage(requestId: requestDetails!.id!))); Navigator.of(context).push(MaterialPageRoute(builder: (_) => CMDetailPage(requestId: requestDetails!.id!, moduleId: requestDetails!.transactionType!)));
}); });
} }

@ -9,9 +9,10 @@ import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/sound/sound_player.dart'; import 'package:test_sa/views/widgets/sound/sound_player.dart';
class PendingServiceRequestScreen extends StatelessWidget { class PendingServiceRequestScreen extends StatelessWidget {
final int moduleId;
final PendingAssetServiceRequest pendingAssetServiceRequest; final PendingAssetServiceRequest pendingAssetServiceRequest;
const PendingServiceRequestScreen(this.pendingAssetServiceRequest, {Key? key}) : super(key: key); const PendingServiceRequestScreen(this.pendingAssetServiceRequest, this.moduleId, {Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -63,7 +64,7 @@ class PendingServiceRequestScreen extends StatelessWidget {
], ],
), ),
).onPress(() { ).onPress(() {
Navigator.of(context).push(MaterialPageRoute(builder: (_) => CMDetailPage(requestId: pendingAssetServiceRequest.details![index].id ?? 0))); Navigator.of(context).push(MaterialPageRoute(builder: (_) => CMDetailPage(requestId: pendingAssetServiceRequest.details![index].id ?? 0, moduleId: moduleId)));
}))); })));
} }
} }

@ -122,7 +122,7 @@ class _AssetDetailPageState extends State<AssetDetailPage> {
"${context.translation.building}: ${assetModel.building?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context), "${context.translation.building}: ${assetModel.building?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context),
"${context.translation.floor}: ${assetModel.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context), "${context.translation.floor}: ${assetModel.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context),
"${context.translation.md}: ${assetModel.department?.departmentName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context), "${context.translation.md}: ${assetModel.department?.departmentName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context),
"${context.translation.room}: ${assetModel.room?.value ?? "-"}".bodyText(context), "${context.translation.room}: ${assetModel.room?.name?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"}".bodyText(context),
], ],
).expanded, ).expanded,
], ],

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.4.0+31 version: 1.5.0+32
environment: environment:
sdk: ">=3.5.0 <4.0.0" sdk: ">=3.5.0 <4.0.0"

Loading…
Cancel
Save