I have an object array of users, which each object has 'username' and 'password'.
There is then a login page, where once the user enters in a username and a password, I want to pass that into the reducer and compare them with each object in the 'users' array, and if an object that matches both, 'password' and 'username', is found, I want it return 'true'.
Following is the reducer:
const usersReducer = function(users = [], action){
switch (action.type){
case 'VERIFY_USER':
return users.map((user)=> {
if(user.username === action.username && user.password === action.password){
return true
} else{
return false
}
})
}
default:
return users
}
}
But it seems to return true all the time. Am I using map correct? If not, is there such a method where it'll go through each object in an array? Any insight or guidance would be appreciated. Thank you in advance!
EDIT**
Calling it from the following:
verifyLoginUser(){
event.preventDefault()
if(this.props.actions.verifyUser(this.props.loginUser.username, this.props.loginUser.password)){
console.log('LOGGED IN')
} else {
console.log('NOT LOGGED IN')
}
}
With the following reducer:
case 'VERIFY_USER':
let isVerified = false;
users.forEach((user)=> {
if(user.username === action.username && user.password === action.password){
isVerified = true;
return false;
}
});
return isVerified;
Use Array.some
return users.some(user => user.username === action.username && user.password === action.password);
Map function would return you an array. I suggest using a different native array function: 'find'. To check if user object exists in the array of users, you can do
function findUser(user) {
return (user.username === action.username && user.password === action.password);
}
var isUser = users.find(findUser) ? true : false;
return isUser;
use a boolean variable and forEach to accomplish what you want
case 'VERIFY_USER':
let isVerified = false;
users.forEach((user)=> {
if(user.username === action.username && user.password === action.password){
isVerified = true;
return false;
}
});
return isVerified;
to take this a step further lets say you wanted to iterate on this and return the correct user so that way you can populate a currentUser with it or something.
case 'VERIFY_USER':
let currentUser = null;
users.forEach((user)=> {
if(user.username === action.username && user.password === action.password){
currentUser = user;
return false;
}
});
return currentUser;
EDIT: to what we were talking about in the comments
lets say you make a request to login a user somewhere. and the function lives on your props
this.props.loginUser({my params here});
now your actual action.
loginUser = (data) => {
// whatever method you are using to make the request goes here.
someRequestMethod('/login/, data).then( (response) => {
if(response.status === 200){
dispatch(type: USER_LOGIN, payload: response.data); // whatever the user is that comes back from the response. I just put data for an example
}
})
}
now in your reducer
const populateState = (user) => {
return {
id: user.id,
username: user.username,
email: user.email,
isAuthenticated: Object.keys(user).length > 0
};
}
let defaultState = {id: null, username: '', email: '', isAuthenticated: false};
const loginReducer = (currentUser = defaultState) => {
switch (action.type){
case 'USER_LOGIN':
return Object.assign({}, currentUser, populateState(action.payload));
return currentUser;
}
finally, everywhere else you just look for the current user.
if(this.props.currentUser.isAuthenticated){
// do stuff
}
Related
I wanted to retrieve an information from backend if some email address from input already exists. Based on this information I'm calling a function that make a post that inserts user into database. The problem is that user is inserted only after second click on my SignUp button (function registerUser is called on this button).
Component stuff:
registerUser(form: NgForm) {
let date: Date = new Date();
this.newUser.registrationDate = date;
this.checkEmailStatus(); //IMPLEMENTATION BELOW
if (this.signupForm.valid === true && this.emailStatus) {
this.portfolioAppService.registerUser(this.newUser).subscribe((data) => {
this.clearFields();
this.navigateToLogin();
},
error => console.error(error)
);
}
}
checkEmailStatus() {
this.portfolioAppService.checkEmailStatus(this.newUser.email).subscribe((data: string) => {
if (data != "") {
this.emailStatus = true;
}
else this.emailStatus = false;
},
error => console.error(error)
);
}
Here is my service:
checkEmailStatus(email: string): Observable<string> {
return this.http.get<string>(`/api/Users/CheckEmailStatus_${email}`, this.httpOptions);
}
Here is backend:
[HttpGet]
[Route("~/api/Users/CheckEmailStatus_{email}")]
public string CheckEmailStatus(string email)
{
try
{
User user = _context.Users.Where(u => u.Email == email).FirstOrDefault();
if (user != null)
{
return user.Email;
}
else
{
return "";
}
}
catch (Exception e)
{
throw new Exception("Error!");
}
}
Call to this.portfolioAppService.checkEmailStatus() is asynchronous. So when you check if (this.signupForm.valid === true && this.emailStatus) after the this.checkEmailStatus() call, the variable this.emailStatus is still undefined. To fix it, you could return an observable from the checkEmailStatus() in the component. Try the following
Component
registerUser(form: NgForm) {
let date: Date = new Date();
this.newUser.registrationDate = date;
this.checkEmailStatus().pipe(take(1)).subscribe(status => {
if (this.signupForm.valid === true && status) { // <-- check the status of email address
this.portfolioAppService.registerUser(this.newUser).subscribe((data) => {
this.clearFields();
this.navigateToLogin();
},
error => console.error(error)
);
}
});
}
checkEmailStatus() : Observable<boolean> {
const result = new Subject<boolean>();
this.portfolioAppService.checkEmailStatus(this.newUser.email).subscribe(
(data: string) => {
if (data !== '') {
result.next(true);
}
else result.next(false);
},
error => {
console.error(error);
result.next(false);
}
);
return result.asObservable();
}
I wrote a function in javascript expression to check if the result is true or false but i am always getting undefined error
var array = [{
email: 'usman#gmail.com',
password: '123'
},
{
email: 'ali#gmail.com',
password: '123'
}
];
let main = function(email, password) {
return array.forEach((row) => {
if (row.email === email && row.password === password) {
return true
} else {
return false
}
});
};
var checkLogin = main('usman#gmail.com', '123');
console.log(checkLogin)
checkLogin always return undefined
It's because forEach does not return anything. You can use simple for-loop, like this:
var array = [
{email: 'usman#gmail.com', password: '123'},
{email: 'ali#gmail.com', password: '123'}
];
let main = function(email, password) {
for (var i = 0; i < array.length; i++) {
var row = array[i];
if (row.email === email && row.password === password) {
return true
}
}
return false;
};
var checkLogin = main('usman#gmail.com', '123');
console.log(checkLogin)
Also, take a look at some(), includes(), find() and findIndex()
The forEach array function doesn't return anything. If you touch looped array inside it then you are able to modify existing array without copying it.
there's a problem with foreach. it doesn't return anything
var array = [
{email: 'mike#gmail.com', password: '123'},
];
let main = function(email, password) {
for (var i = 0; i < array.length; i++) {
if (array[i].email === email && array[i].password === password) {
return true
}
};
return false
};
var checkLogin = main('mike#gmail.com', '123');
console.log(checkLogin) // returns true
there is something wrong with this logic:
return array.forEach((row) => {
if (row.email === email && row.password === password) {
return true
} else {
return false
}
});
without this logic it returns anything you want
You could take Array#some and return the result of the check.
var array = [{ email: 'ali#gmail.com', password: '123' }, { email: 'usman#gmail.com', password: '123' }];
let main = (email, password) =>
array.some(row => row.email === email && row.password === password);
var checkLogin = main('usman#gmail.com', '123');
console.log(checkLogin)
const isName = req => {
return user
.find({ where: { name: req.body.name } })
.then(row => {
return row == null ? true : false;
});
};
Function isName() doesn't return a value. This simple code row == null ? true : false; doesn't return a value, but I'm sure that's working. What is the reason?
Querying is asynchronous, so make sure you await for the result and send it:
// I guess it's a route handler
const isName = async (req, res) => {
const result = await user
.find({ where: { name: req.body.name } })
.then(row => row === null); // same as row === null ? true : false;
res.send(result);
};
Issue :
return user.find({ // <------ This will return promise not true or false
So you can't make call like isName() and get expected result , promise
should be handled to get the expected result
Solution :
isName().then(isThere => { // <------- To get value you should handle like this
if(isThere) {
} else {
}
})
I'm currently developing my first "big" web app with ReactJS using Firebase as my DB. Everything was going well until I came across with this issue.
I'm trying to save the user info when they log in into the app with Facebook or Twitter, I'm using the methods provided by Firebase like this:
authenticate(option){
let provider;
switch (option) {
case 'facebook':
provider = new firebase.auth.FacebookAuthProvider();
break;
case 'twitter':
provider = new firebase.auth.TwitterAuthProvider();
break;
default:
provider = 'no-provider'
break;
}
if(provider !== 'no-provider'){
firebase.auth().signInWithPopup(provider).then((result) => {
console.log("Login with " + provider + " ok!");
console.log(result);
}).catch((error) => {
console.log("Error: there was an error trying to login.");
});
}
}
But when I try to save the user into the DB once they've logged in, nothing happens.
This is what I have on App.js
componentDidMount() {
base.auth().onAuthStateChanged((loggedUser) => {
if (loggedUser) {
this.setState({
userName: loggedUser.displayName,
userPhoto: loggedUser.photoURL,
userUID: loggedUser.uid
});
base.database().ref('users/' + loggedUser.uid).on('value',
(user) => {
if (user.val() !== null) {
if (user.val().votedAlbums !== undefined) {
this.setState({
votedAlbums: user.val().votedAlbums
});
}
} else {
console.log(loggedUser.uid);
let userInfo = {
lastActivityTime: new Date()
}
base.database().ref('users/' + loggedUser.uid).set(userInfo).then((ref) =>{
console.log(ref); // this logs 'undefined'
}).catch((error) => {
console.log(error);
});
}
},
(err) => {
this.props.history.push('/error');
}
);
}
});
}
I tried saving the user on another function and it works, both update() and set(). But when I call set() inside onAuthStateChanged() it doesn't.
My DB rules are:
{
"rules": {
".read": true,
".write": "auth != null"
}
}
Am I missing something?
Thanks
As #bennygenel suggested, I changed the value of lastActivityTime to a simple string like this:
componentDidMount() {
base.auth().onAuthStateChanged((loggedUser) => {
if (loggedUser) {
this.setState({
userName: loggedUser.displayName,
userPhoto: loggedUser.photoURL,
userUID: loggedUser.uid
});
base.database().ref('users/' + loggedUser.uid).once('value',
(user) => {
if (user.val() !== null) {
if (user.val().votedAlbums !== undefined) {
this.setState({
votedAlbums: user.val().votedAlbums
});
}
} else {
console.log(loggedUser.uid);
let userInfo = {
lastActivityTime: "whatever" // replaced new Date() with "whatever"
}
base.database().ref('users/' + loggedUser.uid).set(userInfo).then((ref) =>{
console.log(ref);
}).catch((error) => {
console.log(error);
});
}
},
(err) => {
this.props.history.push('/error');
}
);
}
});
}
And now when the user logs in its added to the DB. I also changed the on() method with once() because it was adding the user even if I deleted directly from the Firebase console.
Now to add the date to lastActivityItem I only have to add the toString() method to the generated date like this:
let d = new Date()
let userInfo = {
lastActivityTime: d.toString()
}
If someone knows why this happened, please share.
Thank you #bennygenel !!!
I'm very confusing because of 'this' property.
What does "delete this.user;" mean in AuthenticationFactory. I think function "check" is a method so it will be bind with 'auth' object. But, there is no 'user' property in 'auth' Object. Can you explain it?
Also, in 'UserAuthFactory' (delete AuthenticationFactory.user, delete AuthenticationFactory.userRole)
I can't figure out what are "user" and "userRole" properties. There are no such properties in AuthenticationFactory.
Here the my code from http://thejackalofjavascript.com/architecting-a-restful-node-js-app/
myApp.factory('AuthenticationFactory', function($window) {
var auth = {
isLogged: false,
check: function() {
if ($window.sessionStorage.token && $window.sessionStorage.user) {
this.isLogged = true;
} else {
this.isLogged = false;
delete this.user;
}
}
}
return auth;
});
myApp.factory('UserAuthFactory', function($window, $location, $http, AuthenticationFactory) {
return {
login: function(username, password) {
return $http.post('http://localhost:3000/login', {
username: username,
password: password
});
},
logout: function() {
if (AuthenticationFactory.isLogged) {
AuthenticationFactory.isLogged = false;
delete AuthenticationFactory.user;
delete AuthenticationFactory.userRole;
delete $window.sessionStorage.token;
delete $window.sessionStorage.user;
delete $window.sessionStorage.userRole;
$location.path("/login");
}
}
}
});
If you look further down, to the controller code:
$scope.login = function() {
var username = $scope.user.username,
password = $scope.user.password;
if (username !== undefined && password !== undefined) {
UserAuthFactory.login(username, password).success(function(data) {
AuthenticationFactory.isLogged = true;
AuthenticationFactory.user = data.user.username;
AuthenticationFactory.userRole = data.user.role;
$window.sessionStorage.token = data.token;
$window.sessionStorage.user = data.user.username; // to fetch the user details on refresh
$window.sessionStorage.userRole = data.user.role; // to fetch the user details on refresh
$location.path("/");
}).error(function(status) {
alert('Oops something went wrong!');
});
} else {
alert('Invalid credentials');
}
};
On a successfully login, the controller is adding the properties user and userRole to the AuthenticationFactory.