How multi-tab logout can be managed in reactJS? - javascript

window.addEventListener('storage', e => {
if(e.key === 'access_token' && e.oldValue && !e.newValue) {
store.dispatch(userSignOut());
}
})
If this is a suitable solution, then where(lifecycle event) should i paste this?

The best way to do that is by using the BrodcastChannel feature in Javascript. The Broadcast Channel API allows simple communication between browsing contexts (that is windows, tabs, frames, or iframes) with the same origin (usually pages from the same site).
For example:
// Connecting to a broadcast channel
const userChannel = new BroadcastChannel('user');
function signOut() {
// and after that, we have to broadcast a message to the user channel which user has signed out from the application as below:
userChannel.postMessage({
userId: "", // If the user opened your app in multi-tabs and signed-in with multi accounts, you need to put the userId here to identify which account has signed out exactly
payload: {
type: "SIGN_OUT"
}
});
}
}
So we created the user's BrodcastChannel but we need to observe on sent messages by user's channel and do the right actions by payload type.
userChannel.onmessage = data => {
if(data.payload.type === "SIGN_OUT") {
// As I talked before about multi-accounts, we need to check the current user id with the sent userId by the userChannel and if they were the same, we have to dispatch the userSignOut action.
store.dispatch(userSignOut());
}
}

enter link description here
Try with focus Listener isFocused
Also check
React Navigation emits events to screen components that subscribe to them:
willFocus - the screen will focus
didFocus - the screen focused (if there was a transition, the transition
completed)
willBlur - the screen will be unfocused
didBlur - the screen unfocused (if there was a transition, the transition
completed)

I suppose you should create an action, something like CHECK_CREDENTIALS, and dispatch it on every API call. This way, if you are removing user credentials from localStorage, every tab will be logged out on 1st call.
However, this is something your server should be capable of. When the token is expired/deleted, it is logical that you should get some comprehensive error.

Related

How to logout a user when a new user logs in in the same browser?

I'm facing this problem where I have two dashboards for two users, one is admin and the other is a merchant. The problem is when admin logs in and in the new tab a merchant logs in too. If I refresh the admin page I get a navbar that is meant for merchant and the rest of the page is of admin... I'm storing the token in localStorage.
Can anyone tell me how I can logout the previously logged in user, If a new user logs in in the on the same browser?
If you need to log out in the other tabs it would help to pass the signal between multiple tabs you can use a local storage event.
Set a logout-event on the previous tabs
localStorage.setItem('logout-event', 'logout' + Math.random());
Every other tab will listen it with the the code below.
window.addEventListener('storage', function(event){
if (event.key == 'logout-event') {
// your code here
}
});
Simply put whenever a merchant logs in using a new tab follow the above procedure to logout any other user.
Instead using localStorage, you should use sessionStorage when you want the token to be unique to each tab/session and to be deleted when tab is closed for ex
U can use sessionStorage Instead of localStorage:
look at this:
https://hashnode.com/post/how-to-handle-multi-user-login-in-same-browser-cjbxct3yq06mk4cwty2bmpsn1
If you ignore IE, I prefer using Broadcast Channel API instead of localStorage event
Init your broadcast channel and listen the event
const bc = new BroadcastChannel("your_channel_name")
bc.onmessage = (e) => {
// Business logic here
// data sent through the channel is available at e.data
}
When you want to trigger the event
bc.postMessage("your logout message");

How to get data from notification, without clicking on notifications (firebase cloud messagin and react native)

Right now I can handle messages when the app is open, minimized, or closed, but when I click on the notification. How to process a message if a user logs into the application without notification?
useEffect(() => {
messaging().setBackgroundMessageHandler(async remoteMessage => {
handlerMessage(remoteMessage)
setInitialRoute('Messenger')
});
messaging().onMessage(async remoteMessage => {
handlerMessage(remoteMessage);
});
messaging()
.getInitialNotification()
.then(remoteMessage => {
if (remoteMessage) {
handlerMessage(remoteMessage);
setInitialRoute('Messenger')
}
});
}, []);
first of all, your "setBackgroundMessageHandler" should be located in your index.js like mentioned in the react-native-firebase docs. You should take another look at that. Now to your question: You want to process data from a fcmNotification that was sent while your app is in background or quit state. Your setBackgroundMessageHandler is not allowed to update any UI (e.g. via state , like mentioned in the docs). However it can perform network requests or update the localStorage. And this is what you should be doing. When a message arrives trough the backgroundHandler, update your LocalStorage. On the next start of your app, you can check if the LocalStorage contains data from a message the backgroundHander processed. If yes, do something with it and delete it after so the next App start wont trigger an action with the old data. If no, -well- do nothing.

Firebase user's details change listener in Javascript

so if a user logs into your app, you can check that by
firebase.auth().onAuthStateChanged((user)=>{});
but if the user is already logged in and his user has a property change, how do you see that?
in my case, I have the user verify his email address and when done, he should be able to see a change instantly on his app after verifying his email. So I am using react native, which is pretty much javascript with ES6 syntax in it and I am doing a firebase.auth().onAuthStateChanged(); but its not working, I even have a button on the screen that checks if verified like this:
if (!firebase.auth().currentUser.emailVerified) { firebase.auth().currentUser.sendEmailVerification(); }
else if (firebase.auth().currentUser.emailVerified) { this.setState({ showVerifier: false }); }
but even that isn't working, as if the firebase.auth().currentUser doesn't update if the email is verified, what can be done here?
As far as I understand your question, I would like to give you an idea.
I think onAuthStateChanged() gets triggered only when your Auth State Changes (login, logout) and not when the user properties change.
As they have mentioned in the documentation,
Adds an observer for changes to the user's sign-in state. Prior to
4.0.0, this triggered the observer when users were signed in, signed out, or when the user's ID token changed in situations such as token
expiry or password change. After 4.0.0, the observer is only triggered
on sign-in or sign-out.
function isVerified(){
var user = firebase.auth().currentUser;
if(user != null){
var status = user.emailVerified;
if(status)
{
// Verified
}else{
// Not Verified
}
}
else{
// User didn't login!
}
}
So, you have to manually check it by defining a function like above and you can call this function when the user clicks the button
If you are using react-native-firebase (highly recommended, since it is supports the latest firebase features), you can listen on user changes as stated in this doc
From the doc
Adds a listener to observe changes to the User object. This is a superset of everything from auth#onAuthStateChanged, auth#onIdTokenChanged and user changes. The goal of this method is to provide easier listening to all user changes, such as when credentials are linked and unlinked, without manually having to call User#reload.
onUserChanged(listener: AuthListenerCallback): () => void;

Event triggered when changing a user Firebase Authentication

Detect events from a user Firebase Authentication
In my application developed in Angular along with Node.js and Firebase I need to detect events occurring in users. As inclusion, change and exclusion.
Is there a way to detect when a user is deleted, changed, or inserted through a function created in Cloud Functions?
I know that you can detect database events with a function created in Cloud Functions. I would like to detect when a user is changed, deleted or entered when the operation is done through Firebase Console > Project > Authentication.
Something in that sense:
exports.userChanged = functions.user
.onCreate((snapshot, context) => {})
OnDelete()
OnCreate()
OnChange()
What is the best way to do this?
There is onCreate and onDelete, you can read it from the docs.
For the update case, you should rely on the RTD. Actually, you could rely completely on the RTD.
//Create a user on the rtd
functions.auth.user().onCreate((user) => {
return usersRef.child(user.uid).set(user);
});
//Update the user by listening to a change on the RTD
functions.database.ref('/users/{uid}')
.onWrite((change, context) => {
//If you needed it you can update the user
admin.auth().updateUser(uid, {
});
//if some condition, then delete it
admin.auth().deleteUser(uid)
//do more
});
Using the update user option you can even disable the account, take a look at this other answer
You can use the admin sdk inside of Functions directly, this is the doc

Inform user that message is still being typed

I am using Laravel 5.6.7, Socket.IO and vue.js. I am not using Pusher and redis. Below is my code to send message to user chatting with me one to one.
var url = "http://localhost:6001/apps/My_appId/events?auth_key=My_Key";
var socketId = Echo.socketId();
var request = {
"channel": "private-Send-Message-Channel.2",
"name": "MessengerEvent",
"data": {
"msg": message
},
"socket_id": socketId
};
axios.post(url, JSON.stringify(request)).then((response) => {
//Message Sent
});
I am trying to inform user who is chatting with me that I am still typing. Should I use the same above code which emits xhr on each char type? Is it the only way to inform user that the message typing is still in progress?
Update 1
Is there any better way to post xhr as mentioned above for each key press? I meant if user types 200 chars. will I post xhr 200 times?
or
Do we have an event called whisper and listenForWhisper as shown here https://laravel.com/docs/5.6/broadcasting#client-events ? I am using vue.js and laravel 5.6.7 without pusher and without redis
If you look at the broadcasting documentation you will see two code code snippets which you can use in your Vue.js application.
To broadcast client events, you may use Echo's whisper method:
Echo.private('chat')
.whisper('typing', {
name: this.user.name
});
To listen for client events, you may use the listenForWhisper method:
Echo.private('chat')
.listenForWhisper('typing', (e) => {
console.log(e.name);
});
While the user is typing, you can debounce the whisper method above.
If you don't wish to use another library like lodash, you can implement the debounce by simply wrapping whisper in a timeout. The following method would broadcast the whisper every 300ms:
isTyping() {
let channel = Echo.private('chat');
setTimeout(function() {
channel.whisper('typing', {
name: this.user.name,
typing: true
});
}, 300);
}
The app needs to trigger isTyping() when an onkeydown event occurs in the chat application's input field.
You also need to listen for the whisper once the app is created. The following method will set the typing variable to true for 600ms after the event has been received.
created() {
let _this = this;
Echo.private('chat')
.listenForWhisper('typing', (e) => {
this.user = e.name;
this.typing = e.typing;
// remove is typing indicator after 0.6s
setTimeout(function() {
_this.typing = false
}, 600);
});
},
I am no Laravel expert, but I've faced this problem before.
First, let's define what "typing" means. The simplest way to define it is to say that a user is typing if and only if the input field to send a message is not empty.
This is not perfect, because the user can go away from keyboard in the middle of typing a message then not returning to complete and/or send it, but it is good enough.
More importantly, we now don't need to care about key strokes to know if the user is typing. In fact, "user is typing" now becomes as easy as chat_input_box.length > 0 to represent in code.
This boolean value is what needs to be synced across users/servers, not the act of hitting a key on the keyboard by the user. However, to keep the value up to date, we need to catch input events on chat_input_box and if the boolean value has changed since before this current event has occurred, socket.io should be able send a signal signifying whether the user has stopped or started typing.
On the receiving side, this signal toggles appropriate views to appear or disappear to indicate the state of the app to the user in human terms.
For the shortcoming of a user typing something then leaving, a timeout can be set so that when it is finished the boolean value "is typing" resets to false, while the act of typing something resets the timeout then starts it again automatically.
You don't have to send an xhr request to your app. You can just
broadcast events directly to the chat users without hitting your app.
From the Laravel docs:
Sometimes you may wish to broadcast an event to other connected clients without hitting your Laravel application at all. This can be particularly useful for things like "typing" notifications, where you want to alert users of your application that another user is typing a message on a given screen. To broadcast client events, you may use Echo's whisper method:
Echo.private('chat')
.whisper('typing', {
name: this.user.name
});
To listen for client events, you may use the listenForWhisper method:
Echo.private('chat')
.listenForWhisper('typing', (e) => {
console.log(e.name);
});
Yes you are right, it should not be emitting on every character change instead you could use debouncing to wait for a small time and then fire the function.
I would recommend using lodash library's debounce method. It should be something like this.
Kindly have a look at the documentation: https://lodash.com/docs/4.17.5#debounce
Laravel's Echo also sounds good, as you'll be doing nothing with typing action on the back-end thus just emitting from client to client is better than involving the server.

Categories

Resources