I have pasted the code which is used for log in my application. Even though the login is successful, the page is not redirecting When login on the first time. After that its working properly. On the first time, the response is goes to catch block also even the response is 200. How to solve this issue.
export function login(loginForm){
return function(dispatch) {
axios.post(config.api.url + 'public/signin', { "email": loginForm.email, "password" : loginForm.password})
.then(response => {
dispatch({ type: 'AUTH_USER' });
localStorage.setItem('token', response.data.token);
hashHistory.push('/');
location.reload();
})
.catch(response => {
dispatch(authError(response.response.data.error));
});
}
}
Try using this -
static contextTypes = {
router: React.PropTypes.object
};
this.context.router.push('/');
Related
I've got a react front end that performs some actions. The relevant axios requests look like so:
const login = async () => {
await Axios.post('http://localhost:8000/login', {
username: username,
password: password,
}).then((response) => {
console.log("login response: ", response);
window.location.href = "http://localhost:3000/";
}).catch(err => {
alert(err.response.data);
});
};
// run on first render to see if user session is still active - remove console log later
useEffect(() => {
Axios.get("http://localhost:8000/isLoggedIn").then((response) => {
console.log("isLoggedIn resonse: ", response);
if (response.data.loggedIn === true) {
setLoginStatus(`Logged in as ${response.data.user}`);
}
})
}, [])
const Logout = async () => {
try {
await Axios.get('http://localhost:8000/logout').then((response) => {
console.log(response);
window.location.href = "http://localhost:3000/login";
}).catch(err => {
alert(err);
});
} catch (error) {
alert(error)
}
};
I keep having to press log out twice to actually log my user out. The logout route runs before the "isLoggedIn" route, according to my network tab. And it's successful, too. Here are the isLoggedIn and logout routes in my express backend:
export function isLoggedIn( req: any, res: any) {
if (req.session.user) {
// if our session already has a user, send true to the frontend
// frontend runs this get login on first render, so will have user data if cookie has not expired.
res.send({loggedIn: true, user: req.session.user})
} else {
res.send({loggedIn: false});
}
}
export function logout(req: any, res: any) {
if (req.session) {
req.session.destroy( (err: any) => {
if (err) {
res.status(400).send('Unable to log out');
} else {
res.send("Logout successful");
}
});
} else {
res.end();
}
}
I'm getting a successful logout. I just cannot figure out why I need to hit the logout button twice on the frontend to actually destroy the session and log the user out? Is there something timing related that I may be missing here?
I have a component GigRegister - one of it's functions is to get all the documents from a collection, and return only the documents created by the currently logged in user:
authListener() {
auth().onAuthStateChanged(user => {
if(user){
this.setState({
userDetails:user
},
() =>
firebase.firestore().collection('gig-listing').onSnapshot(querySnapshot => {
let filteredGigs = querySnapshot.docs.filter(snapshot => {
return snapshot.data().user === this.state.userDetails.uid
})
this.setState({
filterGigs: filteredGigs
})
})
) //end of set state
} else {
this.setState({
userDetails:null
})
console.log('no user signed in')
}
})
}
componentDidMount() {
this.authListener();
}
Another function of this component is to capture data from the user and then post it to firebase, after which it redirects to another component.
handleSubmit(e) {
let user = auth().currentUser.uid;
const gigData = {
name: this.state.name,
venue: this.state.venue,
time: this.state.time,
date: this.state.date,
genre: this.state.genre,
tickets: this.state.tickets,
price: this.state.price,
venueWebsite: this.state.venueWebsite,
bandWebsite: this.state.bandWebsite,
user: user
};
auth()
.currentUser.getIdToken()
.then(function (token) {
axios(
"https://us-central1-gig-fort.cloudfunctions.net/api/createGigListing",
{
method: "POST",
headers: {
"content-type": "application/json",
Authorization: "Bearer " + token,
},
data: gigData,
}
);
})
.then((res) => {
this.props.history.push("/Homepage");
})
.catch((err) => {
console.error(err);
});
}
So here's the issue. Sometimes this component works as it should, and the data submit and redirect work as intended. Occasionally though, I'll hit submit but trigger the message TypeError: Cannot read property 'uid' of null . Interestingly, the post request is still made.
I've been logged in both when it succeeds and fails, and I can only assume that this.state.userDetails.uid evaluating to null means that auth state has expired, or that the component is rendering before userDetails can be assigned a value?
The issue I have is that I can't tell if this is an async problem, or an auth state persistence problem, and I also can't figure why it's a sporadic failure.
This line of code might be causing you trouble:
let user = auth().currentUser.uid;
currentUser will be null if there is no user signed in at the time it was accessed (or it's not known for sure if that is the case). This is covered in the API documentation.
Ideally, you should never use currentUser, and instead rely on the state provided by onAuthStateChanged. I talk about this in detail in this blog post. If you do need to use currentUser, you should check it for null before referencing properties on it.
You should also know that getting an ID token is best done by using a listener as well. The call is onIdTokenChanged, and it works like the auth state listener.
Keep in mind also that setState is asynchronous and doesn't set the state immediately. It's possible that your Firestore query isn't getting the state it needs immediately.
When I call this function I get redirected to the page I request:
submit = () => {
if(!this.state.sell){
this.props.history.push({pathname: "/events"})
}
else {
this.props.history.push({pathname: "/stripeConnectSignUp"})
}
}
However, when I change the function to update data in the database before redirecting, using this code:
submit = () => {
if(!this.state.sell){
this.props.history.push({pathname: "/events"})
}
else {
let token = localStorage.getItem("token");
axios.patch(`${process.env.REACT_APP_API}/updateUser`, {name: this.state.name, token: token}).then(res => {
this.props.history.push({pathname: "/stripeConnectSignUp"})
}).catch(err => {
console.log('axios err', err)
})
}
}
It redirects to the page I want for a split second before redirected back to the original page. There are no errors at either the front end or back end.
For completeness, this is the backend controller that I am posting data to:
module.exports = (req, res) => {
let user = jwt.verify(req.body.token, process.env.SECRET)
User.findByIdAndUpdate(user._id, {name: req.body.name}).then(data=>{res.send({})})
}
This happens regardless of if I use
import { withRouter } from 'react-router-dom'
What am I missing?
I'm developing a react-relay-graphql app with authenticaton and I want to show new messages count in Header component (navigation).
Here is Login Component code:
...
LoginMutation(username, password)
.then((resp) => {
if (resp.token) {
this._saveUserData(resp.expiredAt, resp.token)
fetchQuery(environment, query, {})
.then(data => {
const me = data.user.me;
this.setState({
Auth: {
user: {
fullName: me.fullName,
username: me.username,
isSeniorUser: me.isSeniorUser
}
}
})
this.props.setUser(this.state.Auth.user) // Redux
this.props.history.replace('/dashboard')
});
}
})
_saveUserData = (expiredAt, token) => {
localStorage.setItem(GC_USER_EXPIRES_AT, expiredAt)
localStorage.setItem(GC_AUTH_TOKEN, token)
}
...
And here is Header Component (It is inside Dashboard Component)
class Header extends Component {
componentDidMount() {
this.getMessagesCount()
}
getMessagesCount() {
fetchQuery(environment, NewMessagesQuery, {})
.then(data => {
const newMessagesCount = data.message != null ? data.message.countNewMessages.newMessages : '';
this.props.setNewMessagesCount(newMessagesCount) // Redux
});
}
render() {
return (
<>
{this.props.newMessages}
</>
)
}
}
The problem is after History.push it shows dashboard BUT fetchQuery does not even run and it returns data = {messages: null}, but when page manually refreshes, It works and new messages count is returned.
I figured it out.
In case anyone came to this problem, My cache Config in Environment.js was wrong. So it was trying to read data from cache for each request.
I am following this video tutorial from Rem Zolotykh. I am having the problem that querying the LoopBack server within an onSubmit() from a Form works and using a Redux Action with the same query gives me a Cross-Origin error.
LoopBack Server running at localhost:3000
React Webpack Server
running at localhost:3001 (I used create-react-app)
This following onSubmit function works. Please don't mind the hardcoded stuff it is just for testing.
--------------SignupForm.js-----------------
...
onSubmit(e) {
const user_data = { "email": "foo#bar.com",
"password": "xxx" };
axios.post('http://localhost:3000/api/Users/login', user_data)
.then((response) => {
auth_token = { headers: { 'Authorization': response.data.id } };
return axios.get('http://localhost:3000/api/empsecure', auth_token)
})
.then((response) => {
console.log('Queried Data:', response);
return axios.post('http://localhost:3000/api/Users/logout',{},auth_token)
})
.then((response) => {
console.log("logged out", response);
});
}
...
Here is the changed onSubmit() and the Redux Action:
--------------SignupForm.js-----------------
...
onSubmit(e) {
this.props.userSignupRequest(this.state);
}
...
-------------signupActions.js---------------
import axios from 'axios';
export function userSignupRequest(userData) {
return dispatch => {
const auth_token = {
headers: {'Authorization': 'BgKeyYGVWxx5ybl649jhiPiHpZAyACmV6d9hfJ5UAJxs1McR4RaqANBgwP8vEqiH'}
};
axios.get('http://localhost:3000/api/empsecure', auth_token)
.then((response) => {
console.log('Queried Data:', response);
return response
});
}
}
The browser console gives me a Cross-Origin error, I understand that. But why does it work without redux then?
Ok, after researching, surfing internet and lot of code changes, I found its required in this case to prevent the default action for onSubmit().
I think it did not like the page reload. Works now.
onSubmit(e) {
e.preventDefault();
this.props.userSignupRequest(this.state);
}