I would like to update my dashboard if there are any changes from backend as notification in Facebook.
I have two pages:
A page for the user sending a request message
A page for the user profile where the user can see all the request messages
If there is a new request message, the user needs to refresh the user profile in order to see the new message. I want the new message to be displayed without refreshing the page. Here is my code:
In a message page
state = {
team: {
message: 'Hi! I would like to join in your team! Please accept my request',
invitation_message: 'Hi! I would like to invite you to join in my team.',
email: '',
},
}
// Invite user to a team
handleInvite = event => {
event.preventDefault();
const userObject = JSON.parse(localStorage.getItem('user'));
const jwt = userObject.jwt;
const config = {
headers: { 'Authorization': `bearer ${jwt}` },
};
api
.post('/teammembers', {
team: this.state.teaminfo,
profile: responseData.data[0],
status: "invited",
message: this.state.team.invitation_message,
}, config)
.then(response => {
this.setState({
success_message: true,
})
console.log('Success', response);
})
.catch(err => {
console.log('An error occurred:', err);
});
}
In a user profile page
export class UserProfile extends React.Component {
import socketIOClient from "socket.io-client";
state = {
invited_teams:[],
endpoint: "myurl"
}
componentDidMount() {
const { endpoint } = this.state;
//Very simply connect to the socket
const socket = socketIOClient(endpoint);
socket.on('request', (data) => {
this.setState({ state: data.requests });
});
if (localStorage.getItem('userData')) {
const userObject = JSON.parse(localStorage.getItem('user'));
api
.get(`/profiles/?user=${userObject.user.id}`)
.then(responseData => {
this.setState({
invited_teams: responseData.data
})
}
}
}
Could anyone help me to solve this problem?
Use socket.IO library. You can set a listener on new request and then update the state.
socket.on('request' , (data) => {
this.setState({state: data.requests});
});
Related
I have a React application which allows the user to login via a form then navigates to the home page. I need the App component to provide the user down to its children.
App.js
function App() {
const [token, setToken] = useState(null)
const userQuery = useQuery(USER) // Gets user from GraphQL, using token in the request context
...
useEffect(() => {
setToken(localStorage.getItem("user-token"))
}, [])
return (
<UserContext.Provider value={userQuery.data}>
...
</UserContext.Provider>
)
}
LoginForm.js
const LoginForm = () => {
...
const [login, result] = useMutation(LOGIN, {
onError: (error) => {
console.log("error :>> ", error)
setError(error.graphQLErrors[0].message)
},
})
useEffect(() => {
if (result.data) {
const token = result.data.login.value
localStorage.setItem("user-token", token)
navigate("/")
}
}, [result.data])
...
}
index.js
const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem("user-token")
return {
headers: {
...headers,
authorization: token ? `bearer ${token}` : null,
},
}
})
When the login form submits the GraphQL login query is executed. Then when the result is received the token is set in local storage and it navigates back to the main page. The problem is that the app's user query receives a null user because the request wasn't sent with the new storage token. How can I get it to do this without refreshing the page?
i have a function called login that redirects the user to the main page if everything was ok. Then, on the main page, i want to fetch some user info with useEffect using the token the was stored when the user logged in, but nothing happens. Only when i refresh the page i get the data.
login function
export const login = ({ email, password, history }) => {
return async (dispatch) => {
try {
const response = await fetch("http://localhost:5000/api/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
}),
});
const data = await response.json();
if (data.status === 200) {
localStorage.setItem("userToken", data.user);
history.push("/");
} else {
dispatch(
setNotification({
variant: "error",
message: data.message,
})
);
}
} catch (e) {
console.log(e.message);
}
};
};
fetch user funtion
export const fetchUser = () => {
return async (dispatch) => {
try {
const response = await fetch("http://localhost:5000/userInfo", {
headers: {
"x-access-token": localStorage.getItem("userToken"),
},
});
const data = await response.json();
dispatch(setUser({
id: data.id,
fullname: data.fullname,
email: data.email
}))
} catch (error) {}
};
};
useEffect on my main page
useEffect(() => {
dispatch(fetchUser());
}, []);
backend function
module.exports.getCurrentUser = async (req, res) => {
const token = req.headers["x-access-token"];
try {
const verifyToken = jwt.verify(token, "123");
const user = await User.findOne({ email: verifyToken.email });
return res.json({
id: user._id,
fullname: user.fullname,
email: user.email
})
} catch (error) {}
};
The 2nd parameter to useEffect tells it when it needs to run. It only runs if one of the values in the array has changed. Since you pass an empty array, none of the values in it have changed.
This is presuming your app probably starts at '/', then detects there is no user so switches to the login screen. When it goes back to the root, it only executes useEffect if something in the array has changed from the previous render.
As it is, the isMounted doesn't make much sense. This could simply be:
useEffect(() => {
dispatch(fetchUser());
});
You're calling setUser, but what is calling your login function?
The notification options that I am passing to my notifications are not passing to the notification and I am getting a default notification. (Title is the website, body is "The site has been updated in the background").
Service worker is an adapted create-react-app service worker.
Also, the console.log statements in the push event handler are not passing to the browser. Why is this?
The push event listener is directly after the load event listener in the CRA Service Worker
Web-Push API Call to create a web-push notification:
router.post('/:userid', auth, async (req, res) => {
try {
const user = await User.findById(req.params.userid);
user.pushSubscriptions.forEach((sub) => {
if (sub === null) {
return;
}
webpush.setVapidDetails(
'mailto:contact#email.com',
config.get('vapidPublic'),
config.get('vapidSecret')
);
const options = {
endpoint: sub.endpoint,
expirationTime: sub.expirationTime,
keys: {
p256dh: sub.keys.p256dh,
auth: sub.keys.auth,
},
};
console.log(options.endpoint);
webpush
.sendNotification(
options,
JSON.stringify({
title: 'NotifTitle',
body: 'Body',
})
)
.catch((error) => console.log(error));
});
return res.status(200).json({ msg: 'Notification Sent' });
} catch (error) {
console.log(error);
return res.status(500);
}
});
Push listener in sw.js:
window.addEventListener('push', (event) => {
console.log('Notification Recieved', event);
//Fallback data
let data = {
title: 'TestABC',
body: '123456',
};
if (event.data) {
data = JSON.parse(event.data.text());
}
//Notification options
var options = {
body: data.body,
icon: '../public/logo192.png',
image: '../public/logo192.png',
};
event.waitUntil(
console.log(options),
navigator.serviceWorker.registration.showNotification(
data.title,
options
)
);
});
Thanks
try to convert data like this
data = event.data.json();
you can read more here
I'm setting a basic authentication on a Nuxt project with JWT token and cookies to be parsed by nuxtServerInit function.
On login with email/password, works as intended, setUser mutation is triggered and the appropriate user object is stored in state.auth.user.
On reload, nuxtServerInit will get the jwt token from req.headers.cookies, call the GET method and identify user.Works like a charm.
Problem starts when I hit the /logout endpoint. state.auth.user is set to false and Im effectively logged out... but If I refresh, I'm logged in again with the previous user data. Even if my cookies are properly empty (on below code, both user and cookie are undefined after logout and refresh, as expected)
So I really don't get why is my state.auth.user is back to its initial value...
store/index.js
import Vuex from "vuex";
import auth from "./modules/auth";
import axios from "~/plugins/axios";
const cookieparser = process.server ? require("cookieparser") : undefined;
const END_POINT = "api/users";
const createStore = () => {
return new Vuex.Store({
actions: {
async nuxtServerInit({ commit, dispatch}, { req }) {
let cookie = null;
console.log(req.headers.cookie)
if (req.headers.cookie) {
const parsed = cookieparser.parse(req.headers.cookie);
try {
cookie = JSON.parse(parsed.auth);
console.log("cookie", cookie)
const {accessToken} = cookie
const config = {
headers: {
Authorization: `Bearer ${accessToken}`
}
}
const response = await axios.get(`${END_POINT}/current`, config)
const user = response.data
console.log("user nuxt server init", user)
await commit('setUser', user)
} catch (err) {
// No valid cookie found
console.log(err);
}
}
}
},
modules: {
auth
}
});
};
export default createStore;
modules/auth.js
import axios from "~/plugins/axios";
const Cookie = process.client ? require("js-cookie") : undefined;
const END_POINT = "api/users";
export default {
state: {
user: null,
errors: {}
},
getters: {
isAuth: state => !!state.user
},
actions: {
login({ commit }, payload) {
axios
.post(`${END_POINT}/login`, payload)
.then(({ data }) => {
const { user, accessToken } = data;
const auth = { accessToken };
Cookie.set("auth", auth);
commit("setUser", user);
})
.catch(e => {
const error = e;
console.log(e);
commit("setError", error);
});
},
logout({ commit }) {
axios
.post(`${END_POINT}/logout`)
.then(({ data }) => {
Cookie.remove("auth");
commit("setUser", false);
})
.catch(e => console.log(e));
},
},
mutations: {
setUser(state, user) {
state.user = user;
},
setError(state, errors) {
state.errors = errors;
}
}
};
The way I logout my user is by creating a mutation called clearToken and commit to it in the action :
State :
token: null,
Mutations :
clearToken(state) {
state.token = null
},
Actions :
logout(context) {
context.commit('clearToken')
Cookie.remove('token')
}
This way, you token state revert back to null.
I have done authentication trigger, it's working fine. If someone delete their account I need to send to notification "this user deleted his account (email)" like that. Here is my code
const functions = require('firebase-functions')
//initialize the app
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
const ref = admin.database().ref()
//create user account function
exports.createUserAccount = functions.auth.user().onCreate(event => {
const uid = event.data.uid
const email = event.data.email
const newUserRef = ref.child(`/UserNotify/${uid}`)
return newUserRef.set({
email: email
})
})
//delete user account function
exports.cleanupUserData = functions.auth.user().onDelete(event => {
const uid = event.data.uid
const userRef = ref.child(`/UserNotify/${uid}`)
return userRef.update({isDeleted: true})
})
function sendNotification() {
console.log("Successfully sent");
var payload = {
notification: {
title: "User get deleted",
body: "sample#gmail.com"
}
};
admin.messaging().sendToDeveice(payload)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
})
}
You may have a typing error
admin.messaging().sendToDevice() and not sendToDeveice
check: https://firebase.google.com/docs/cloud-messaging/admin/send-messages