How to notify other users that the a certain modal is open - javascript

Given the situation:
A user (customer agent) should know if the modal is currently open by other customer support to avoid conflicts on processing the data. So example I opened the modal, it should notify the other users that "hey this is being processed right now, go do other stuff"
Since the project is using meteor.js I considered to take advantage of its real-time feature. I was thinking of storing (MongoDB) a state on every modal if it is open or not (because every modal is a data), of course we can set the "close state" if the user closes the modal (in case he did not proceed processing the data), however what if the user accidentally closed the browser tab / browser window / power outage? then the data is set as "open" in the database forever.
I also considered the use of sockets. (i.e. socketIO) so it will publish to the other users the data of the current modal that is open every time a user opens a modal, so user opened a modal -> socket notify other users on what modal is open. but what if the user opened a modal -> socket notify other users -> then another user logged in to the system (which means he did not get the socket notification and might end up opening the same modal.
So any recomendations / ideas / tips you wanna share?
I'm using Meteor.js, React js, MongoDB as my DB.

You could achieve what your looking for with socket.io an example of how you would handle notifying other users is by simply creating a Map() within the server. This holds information about currently open modals and the users accessing them. I have outlined some code below that could give you and idea of how to do it:
//client side
function modals(socket) {
this.sendModalOpen = (modalIdentifier) => {
socket.emit('openedModal', {
modal: modalIdentifier
});
};
this.closeModal = () => {
socket.emit('closedModal', {
modal: modalIdentifier
});
};
}
socket.on('recModalInfo', (data) => {
for (let x = 0; x < data.info.length; x++) {
console.log(data.info[x][0] + " has open " + data.info[x][1]);
}
});
//server side
let modal = new Map();
io.on('connection', (socket) => {
//Here we are sending any new connections a list of all current modals being viewed with Identifiers.
//You could send all of the items inside the map() using map.entries
let currentInfo = [];
modal.forEach((value, key) => {
currentInfo.push([key, value]);
});
socket.emit('recModalInfo', {
info: currentInfo
});
socket.on('openedModal', (data) => {
modal.set(socket.id, data.modalIdentifier);
});
socket.on('closedModal', (data) => {
modal.delete(socket.id);
});
});
I have included client and serverside, but as your obviously not using vanilla JavaScript here the clientside code is more of a representation of what needs to happen that you can adapt.
but what if the user opened a modal -> socket notify other users ->
then another user logged in to the system (which means he did not get
the socket notification and might end up opening the same modal.
When a user connects to the server and a socket is created the io.on('connection', (socket)=>{ }); Is always ran which allows us to then send out an emit detailing all of the current modals open and a identifier.
A user (customer agent) should know if the modal is currently open by
other customer support to avoid conflicts on processing the data.
As your client will receive information about the modals currently open you can either choose to make them not available on the DOM by not rendering the code used to access the modal. You could also process a check on the map if it's a 1-1 scenario and build further functionality if say a manager or a special individual wants to view the modal for some reason or just not at all.

Related

odoo notification if the record data is out of date

when odoo 15 was released I have seen this record is not up to date (not sure of the actual words)
The issue is that I have a approval for a record but if the user that summered the record for approval is still on the page he don't see the updates to the record after the approval. I do send the notification but the user wants the page to refresh or show that the record view is not up to date like (what odoo was doing in the first week of the released)
sorry is there is no code but am not sure how go about doing this.
Not expecting a solution just ideas on what you thing and maybe in you have time why your idea may fail (drawbacks).
/**
* Displays one notification on user's screen when assets have changed
*/
function displayBundleChangedNotification() {
if (!isNotificationDisplayed) {
// Wrap the notification inside a delay.
// The server may be overwhelmed with recomputing assets
// We wait until things settle down
browser.clearTimeout(bundleNotifTimerID);
bundleNotifTimerID = browser.setTimeout(() => {
notification.add(
env._t("The page appears to be out of date."),
{
title: env._t("Refresh"),
type: "warning",
sticky: true,
buttons: [
{
name: env._t("Refresh"),
primary: true,
onClick: () => {
browser.location.reload();
},
},
],
onClose: () => {
isNotificationDisplayed = false;
},
}
);
isNotificationDisplayed = true;
}, getBundleNotificationDelay());
}
}
addons/bus/static/src/js/services/assets_watchdog_service.js
this maybe semlar to what I need but assets
The main question here Is how to know if a user is on the modified record and run a function
setup a web socket that listens for update events identified
by ID’s and prompt notifications if the documentId of the
notification matches the ID of document on page at that point in
time.
Poll every x seconds for the record corresponding to document on page and compare some unique value that would have changed like lastUpdated. If changed prompt notification and refresh.
Keep a metadata list of open pages. Can use heartbeat interval and onLoad onUnload events to keep list valid. Whenever two or more documents are open at the same time make it known on page that “document is being edited and cannot be currently edited will update accordingly” or something like that.
Use service workers and the push api to send updates to the main running app

React : Handle multiple browser(s), browser tabs to restrict duplicate operations

I have a button Submit when clicked performs some operation calling an API. Post click, the button is disabled or basically the initial state of the button and the operation is changed.
I have two or multiple browser tabs which shows same screen of Submit. If in any one of the tab, the Submit operation is performed, the other tabs should show the updated version. The other tabs should show the disabled version and should not show the initial state.
How do I achieve this? I am using React, JS
#1 Data duplication MUST be restricted at the server side.
I would recommend some cache like node-cache. Node-cache will having scalability issues, so better to go with redis. (The logic should be smt. like: If the form has submited with the user_id, or with form_id, you can create a cache for that, and if you proceed it, store it in the db, other case throws an error. On the other browser you must validate before the submit if the unique_id neither in the cache nor in the db. If exists, you can throws an error in the nr.2 browser.
#2 If you want to disable the button, you have to use websockets
If you're looking for a client-only solution, here is a great article about sharing state between browser tabs. The limitation is that it won't work on different browsers/machines.
The best way to handle this from a UI/UX perspective is to use validation. If User A clicks submit, then User B clicks submit from a different browser or tab, an error should be displayed to User B indicating that "This action has already taken place".
That being said, what you are trying to achieve is possible.
One way is by using a WebSocket. A WebSocket is a persistent connection between the client and server, that allows bi-directional communication.
The page with the submit button in your React app would be a "subscriber" to some websocket channel. When the submit button is clicked for the first time(it doesn't matter from where), a message can be "published" from a WebSocket server to ALL subscribers, regardless of the browser or tab being used.
Basically, you would add an onMessage handler in your React app where you can disable the submit button when a specific message is received.
I don't know what tech you are using on the server side, but for a WebSocket server, there are many options out there. For the React app, there is react-websocket which is straight-forward to use.
you can do it in client-side
const Form = () => {
const [buttonDisabled, setButtonDisable] = useState(false);
// first tab fire
const onSubmit = () => {
.
.
.
localStorage.setItem("formSubmited", "true");
};
useEffect(() => {
const disableButton = (e) => {
if (e.storageArea.formSubmited) {
setButtonDisable(true);
}
};
// second tab fire
window.addEventListener("storage", disableButton);
return () => {
window.removeEventListener("storage", disableButton);
};
}, []);
.
.
.
};

How to allow JavaScript to receive a message sent to a specific user (or self) using Signal R?

I previously asked this question but it was closed for duplication owing to this thread (SignalR - Sending a message to a specific user using (IUserIdProvider) *NEW 2.0.0*) - but this doesn't show the JavaScript as made clear in my title.
I have a WebForm application in ASP.Net that uses SignalR to push live data to the user logged in. The setup works perfectly, but realised I am broadcasting messages to all clients, which whilst it doesn't cause the wrong data to displayed to the logged in user, does cause the JavaScript function to get called for all users when just one has a data push.
I have amended the Hub code to broadcast to a specific user (User) and provided the User ID, and I have also tried Client with a Connection ID. Both fire off fine in the codebehind, but the javascript will not update the front end.
I believe it's because the JavaScript has not been modified to listen for a message sent to the user, but I'm not sure how I need to adapt the code to allow the message to be received.
The 2 tried lines in Hub here:
context.Clients.User(Me.Context.User.Identity.GetUserId()).ReceiveNotification(notifCount)
context.Clients.Client(Me.Context.ConnectionId).ReceiveNotification(notifCount)
JavaScript/jQuery function for the SignalR message here:
$(function () {
var nf = $.connection.notificationHub;
nf.client.receiveNotification = function (notifCount) {
// Update data
}
$.connection.hub.start().done(function () {
nf.server.sendNotifications();
}).fail(function (e) {
alert(e);
});
//$.connection.hub.start();
});
For calling back to the client (or self) you should use:
Clients.Caller.addContosoChatMessageToPage(name, message);
And for calling users you should use:
Clients.Client(Context.ConnectionId).addContosoChatMessageToPage(name, message);
Reference - docs

Getting Firebase Realtime Database Value By Child

I'm developing an application that has a chat page.
I'm using Firebase realtime database and my chat structure like this:
I'm getting new messages as below:
fireBuddyChats = firebase.database().ref('/buddychats');
this.fireBuddyChats.child(this.currentUserId)
.child(this.buddy.uid)
.orderByKey()
.limitToLast(topMsgCount)
.on('value', (snapshot) => {
this.buddyMessages = [];
let temp = snapshot.val();
for(var tempKey in temp) {
this.buddyMessages.push(temp[tempKey]);
}
this.events.publish('newmessage');
}
I'm listening 'newmessage' event to show new message in chat page.
The problem is: While i chatting somebody, if another friend sends any message, database trigger (I mentioned above) runs and chat page shows another friend's messages. I think it shouldn't be triggered because the "this.buddy.uid" is different. What i'm missing? Is there any suggestion?
Maybe to prevent this you can add a conditional statement above to check if the user (the current user is talking to) actually has the uid of "this.buddy.uid". So maybe for the code you could possibly include somewhere:
if (socket.uid == this.buddy.uid).then
This should prevent other users from joining/adding themselves onto the real-time database conversation as it is checking if the user constantly.
Hopefully this helps.

Removing someone from a user hash on navigating away from a page / page close

I'm building a Node.js / Socket.io project.
I have a hash of Users based on their websocket id. When a user makes the following request i'd like to add them to a group of users viewing that page.
app.get('/board/:id', function(req, res){}
I'd like to keep something like
Browsing = {
username : id,
username : id,
...
}
However i'm unsure how to remove a user lets say if they navigate off the page. Is there some kind of function that gets called upon page leave?
Partial Solution:The following seems to do the trick on Chrome:
$(window).unload(function(){
var username = $('#username').text();
var pid = currentProject;
var data = {
username: username,
id : pid
}
socket.emit('leaving-page', data);
})
... Is there some kind of function that gets called upon page
leave? ...
Yes, but it is not reliable.
The way the people keep track of who is online and who isn't, is usually like this:
Add the time when the user last refreshed/visited a page
set a limit to you consider them offline
You could intercept the event which corresponds to leaving a page. There are several ways to do it, have a look at the following links and let me know if any suits your needs and if I can answer any more explicit questions about them:
Intercept page exit event
Best way to detect when a user leaves a web page?
jquery unload
with the last link you could do something like this:
$(window).unload(function() {
//remove the user from your json object with delete json_object[key];
});
Hope this helps.
Since you're using Socket.io, the server will know when the user has left the page because the socket will be disconnected. Simply listen for the disconnect event.
io.sockets.on('connection', function (socket) {
...
socket.on('disconnect', function () {
// The user on `socket` has closed the page
});
});
Better yet, take advantage of namespaces and let Socket.io handle all of the connection/disconnection (it's doing it anyway -- no need to duplicate effort).
On the client,
socket = io.connect('http://example.com/pagename');
pagename need not point to a valid URL on your domain – it's just the namespace you'll use in the server code:
io.sockets.clients('pagename')
Gets you all of the clients currently connected to the pagename namespace.

Categories