Alaris
Alaris

Reputation: 103

Ternary operator not using the useState correctly

I'm trying to update the header component based on the state and the response I get from my API server but for some reason, my updated state is having some type of errors that I cannot understand.

When my API server responds back if the username and password are correct, I get the console.log(response.data) on my browser with the properties(username, password, token). I can login and the token gets saved in the local session... GREAT!! However, when I try to login with a blank username/password or any incorrect data, my state evaluates to true and therefore the HeaderLoggedIn component activates (not following the ternary operator ruleset) / my server responds with console.log('Incorrect username / password.'); but still the HeaderLoggedIn activates.

My useState(), initially is set to a Boolean(sessionStorage.getItem('movieappToken'). so if there's no token saved, its false and therefore it should be useState(false) - render the HeaderLoggedOut component.

What am I doing wrong? Thank you

main Header.js component:

import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import HeaderLoggedOut from './HeaderLoggedOut';
import HeaderLoggedIn from './HeaderLoggedIn';

function Header() {
    const [loggedIn, setLoggedIn] = useState(
        Boolean(sessionStorage.getItem('movieappToken'))
    );

    return (
        <header className="header-bar bg-primary mb-3">
            <div className="container d-flex flex-column flex-md-row align-items-center p-3">
                <h4 className="my-0 mr-md-auto font-weight-normal">
                    <Link to="/" className="text-white">
                        ComplexApp
                    </Link>
                </h4>


                   **//here's the problem**
                {loggedIn ? (
                    <HeaderLoggedIn setLoggedIn={setLoggedIn} />
                ) : (
                    <HeaderLoggedOut setLoggedIn={setLoggedIn} />
                )}
            </div>
        </header>
    );
}

export default Header;

HeaderLoggedIn.js Component:

import React, { useEffect } from 'react';

function HeaderLoggedIn(props) {
    function handleLogout() {
        props.setLoggedIn(false);
        sessionStorage.removeItem('movieappToken');
        sessionStorage.removeItem('movieappUsername');
    }

    return (
        <div className="flex-row my-3 my-md-0">
            <a href="#" className="text-white mr-2 header-search-icon">
                <i className="fas fa-search"></i>
            </a>
            <span className="mr-2 header-chat-icon text-white">
                <i className="fas fa-comment"></i>
                <span className="chat-count-badge text-white"> </span>
            </span>
            <a href="#" className="mr-2">
                <img
                    className="small-header-avatar"
                    src={sessionStorage.getItem('complexappAvatar')}
                />
            </a>
            <a className="btn btn-sm btn-success mr-2" href="/create-post">
                Create Post
            </a>
            <button onClick={handleLogout} className="btn btn-sm btn-secondary">
                Sign Out
            </button>
        </div>
    );
}

export default HeaderLoggedIn;

and HeaderLoggedOut.js Component - the one which gets data from the API server

import React, { useEffect, useState } from 'react';
import Axios from 'axios';

function HeaderLoggedOut(props) {
    const [username, setUsername] = useState();
    const [password, setPassword] = useState();

    async function handleSubmit(e) {
        e.preventDefault();
        try {
            const response = await Axios.post('http://localhost:4000/login', {
                username,
                password,
            });
            if (response.data) {
                console.log(response.data);
                sessionStorage.setItem('movieappToken', response.data.token);
                sessionStorage.setItem('movieappUsername', response.data.username);
                props.setLoggedIn(true);
            } else {
             
                console.log('Incorrect username / password.');
            }
        } catch (e) {
            console.log('There was a problem.');
        }
    }

    return (
        <form onSubmit={handleSubmit} className="mb-0 pt-2 pt-md-0">
            <div className="row align-items-center">
                <div className="col-md mr-0 pr-md-0 mb-3 mb-md-0">
                    <input
                        onChange={(e) => setUsername(e.target.value)}
                        name="username"
                        className="form-control form-control-sm input-dark"
                        type="text"
                        placeholder="Username"
                        autoComplete="off"
                    />
                </div>
                <div className="col-md mr-0 pr-md-0 mb-3 mb-md-0">
                    <input
                        onChange={(e) => setPassword(e.target.value)}
                        name="password"
                        className="form-control form-control-sm input-dark"
                        type="password"
                        placeholder="Password"
                    />
                </div>
                <div className="col-md-auto">
                    <button className="btn btn-success btn-sm">Sign In</button>
                </div>
            </div>
        </form>
    );
}

export default HeaderLoggedOut;

API Server userController.js

const User = require('../models/User');

//
exports.login = function (req, res) {
    let user = new User(req.body);
    user
        .login()
        .then(function (result) {
            
            res.send(result);
        })
        .catch(function (error) {
            res.send(error);
        });
};

API Server User.js

const usersCollection = require('../db').collection('users');
const bcrypt = require('bcryptjs');
const validator = require('validator');

let User = function (data) {
    this.data = data;
    this.errors = [];
};

User.prototype.cleanUp = function () {
    if (typeof this.data.username != 'string') {
        this.data.username = '';
    }
    if (typeof this.data.email != 'string') {
        this.data.email = '';
    }
    if (typeof this.data.password != 'string') {
        this.data.password = '';
    }

    // get rid of any bogus properties
    this.data = {
        username: this.data.username.trim().toLowerCase(),
        email: this.data.email.trim().toLowerCase(),
        password: this.data.password,
        token: `58158188ji4j1ij42jio4j1ji41oji14i${this.data.username}`,
    };
};

User.prototype.validate = function () {
    if (this.data.username == '') {
        this.errors.push('You must provide a username');
    }
    if (
        this.data.username != '' &&
        !validator.isAlphanumeric(this.data.username)
    ) {
        this.errors.push('Username can only contain letters and numbers');
    }
    if (!validator.isEmail(this.data.email)) {
        this.errors.push('You must provide a valid email address');
    }
    if (this.data.password == '') {
        this.errors.push('You must provide a password');
    }
    if (this.data.password.length > 0 && this.data.password.length < 7) {
        this.errors.push('Password must be at atleast 7 characters');
    }
    if (this.data.password.length > 25) {
        this.errors.push('Password cannot exceed 25 characters');
    }
    if (this.data.username.length > 0 && this.data.username.length < 3) {
        this.errors.push('Username must be at atleast 3 characters');
    }
    if (this.data.username.length > 15) {
        this.errors.push('Username cannot exceed 15 characters');
    }
};

User.prototype.register = function () {
    // Step #1: Validate user data
    this.cleanUp();
    this.validate();

    // Step #2: Only if there are no validation errors
    // then save the user data into a database
    if (!this.errors.length) {
        // hash user password
        let salt = bcrypt.genSaltSync(10);
        this.data.password = bcrypt.hashSync(this.data.password, salt);
        usersCollection.insertOne(this.data);
    }
};

User.prototype.login = function () {
    return new Promise((resolve, reject) => {
        this.cleanUp();
        usersCollection
            .findOne({ username: this.data.username })
            .then((attemptedUser) => {
                if (
                    attemptedUser &&
                    bcrypt.compareSync(this.data.password, attemptedUser.password)
                ) {
                    resolve(this.data);
                } else {
                    reject('invalid username/password');
                }
            })
            .catch(function () {
                reject('Please try again later!');
            });
    });
};

module.exports = User;

Upvotes: 1

Views: 393

Answers (2)

Dc.renegade
Dc.renegade

Reputation: 79

whatever your server response this.data, invalid username/password or Please try again later!, it just response a string or an object in nature. So it will always enter the first judgement

if (response.data) {
    console.log(response.data);
    sessionStorage.setItem('movieappToken', response.data.token);
    sessionStorage.setItem('movieappUsername', response.data.username);
    props.setLoggedIn(true);
}

I think you can add another property such as code to help you to judge.

if (response.data) {
    console.log(response.data);
    if (response.data.code === 200) {
      sessionStorage.setItem('movieappToken', response.data.token);
      sessionStorage.setItem('movieappUsername', response.data.username);
      props.setLoggedIn(true);
    } else {
      props.setLoggedIn(false);
    }
    
}

Upvotes: 2

Hanchen Jiang
Hanchen Jiang

Reputation: 2682

You are not setting loggedIn when getting the "incorrect username/password" response so loggedIn remains whatever it was initially. You can set it to false

if (response.data) {
  console.log(response.data);
  sessionStorage.setItem('movieappToken', response.data.token);
  sessionStorage.setItem('movieappUsername', response.data.username);
  props.setLoggedIn(true);
} else {
  props.setLoggedIn(false);
  console.log('Incorrect username / password.');
} catch (e) {
  props.setLoggedIn(false);
  console.log('There was a problem.');
}

Upvotes: 0

Related Questions