Module 3: Login / Logout

In this module, we will focus on logging in and out of our app.

Step 1. Login

The login will be very similar to our Signup module. Let's get started.

  1. Go into the Login.js file.

  2. Add the handleChange method below:

handleChange = (event) => {
    this.setState({
        [event.target.name]: event.target.value,
    });
}
  1. Then, we can throw handleChange on our inputs:

    onChange={this.handleChange}

Let's update our state:

this.state = {
    username: '',
    password: ''
};

Now we want to build our submit function, add in our submit handler, and also add in our button, so we can actually login. First head over to Auth.js so we can pass in our setToken prop. Where you are calling your <Login />component, just add on the same prop that we have added to our <Signup /> component:

<Login setToken={props.setToken} />

Okay, now we head back to our Login.js First, we build our handleSubmit function:

handleSubmit = (event) => {
    fetch("http://localhost:3000/api/login", {
        method: 'POST',
        body: JSON.stringify({user:this.state}),
        headers: new Headers({
            'Content-Type': 'application/json'
            })
    }).then(
        (response) => response.json()
    ).then((data) => {
        this.props.setToken(data.sessionToken)
    }) 
    event.preventDefault()
}

We have seen this all before, but it never hurts to refresh ourselves. Read each line and make sure that you understand what is actually going on here!

Okay let's add our button and submit handler, so that we can actually submit this form!

First, let's add our submit handler to our Form:

onSubmit={this.handleSubmit}

Next, we add our button:

            ...
        </FormGroup>
        <Button type="submit"> Submit </Button>
    </Form>
...

Don't forget to import your button. The final Login.js component should look like the following:

import React, { Component } from "react";
import { Button, Form, FormGroup, Label, Input } from 'reactstrap';

class Login extends Component {

    constructor(props) {
        super(props)
        this.state = {
            username: '',
            password: ''
        };
    }

    handleChange = (event) => {
        this.setState({
            [event.target.name]: event.target.value,
        });
    }

    handleSubmit = (event) => {
        fetch("http://localhost:3000/api/login", {
            method: 'POST',
            body: JSON.stringify({user:this.state}),
            headers: new Headers({
                'Content-Type': 'application/json'
              })
        }).then(
            (response) => response.json()
        ).then((data) => {
            this.props.setToken(data.sessionToken)
        }) 
        event.preventDefault()
    }

    render() {
        return (
            <div>
                <h1>Login</h1>
                <h6>Lorem ipsum dolor sit amet consectetur adipisicing elit. Minus repellat, atque nulla, soluta vero reprehenderit numquam incidunt, rem quaerat quos voluptatum perferendis. Distinctio culpa iste atque blanditiis placeat qui ipsa?</h6>
                <Form onSubmit={this.handleSubmit} >
                    <FormGroup>
                        <Label for="username">Username</Label>
                        <Input id="li_username" type="text" name="username" placeholder="enter username" onChange={this.handleChange} />
                    </FormGroup>
                    <FormGroup>
                        <Label for="password">Password</Label>
                        <Input id="li_password" type="password" name="password" placeholder="enter password" onChange={this.handleChange} />
                    </FormGroup>
                    <Button type="submit"> Submit </Button>
                </Form>
            </div>
        )
    }
}

export default Login;

Let's check and make sure it's correctly saving to the local storage on login! In Chrome, open up the inspector, go the Application tab, and then on the left click on local storage. Open that up and click on localhost:3001 (or wherever you're running your react application). You should be able to see your token in local storage. It'll look something like this:

Step 2. Logout

Now that we are able to successfully create a new user with a session token, we can now go ahead and create our ability to login and logout. First, let's start by adding in the ability to logout. Head over to your App.js and let's start there.

First, let's build our logout function:

  logout = () => {
    this.setState({ 
      sessionToken: '', 
    });
    localStorage.clear();
  }

This is pretty straightforward. We are resetting the state of our sessionToken to an empty string, and then we are also clearing our token from our local storage. So basically, we'll determine if a user is logged in, based on whether or not sessionToken exists in their local storage.

Then let's pass in our function to our SiteBar component:

<SiteBar clickLogout={this.logout} />

Awesome. Now we are able to logout, so let's add a cool logout button onto our navbar. Head over to your Navbar.js and let's go ahead and do that now, your render should look like this:

render() {
    return (
        <div>
            <Navbar color="faded"  light expand="md">
                <NavbarBrand href="/">Workout Log</NavbarBrand>
                <NavbarToggler onClick={this.toggle} />
                <Collapse isOpen={this.state.isOpen} navbar>
                    <Nav className="ml-auto" navbar>
                        <NavItem>
                            <Button onClick={() => this.props.clickLogout()}>Logout</Button>
                        </NavItem>
                    </Nav>
                </Collapse>
            </Navbar>
        </div>
    );
}

Okay, so we are adding a couple things here. This means we have a couple of things from reactstrap that we need to import:

import {
    Collapse,
    Navbar,
    NavbarToggler,
    NavbarBrand,
    Nav,
    NavItem,
    Button
} from 'reactstrap';

These imports from reactstrap help with styling, so that we can easily make decent looking components quickly.

You will also notice that we are using isOpen, which is just a boolean value, set in our state. Okay so in our state, we need to add the following :

isOpen: false

We also need to build out our toggle function, which is being used on our NavbarToggler:

toggle = () => {
    this.setState({
        isOpen: !this.state.isOpen
    });
}

We are starting to see the pattern here. If you are wondering what the NavbarToggler is doing, go ahead and inspect our site and click on Toggle device toolbar. We just want to see what our site would look like on a mobile device. You will see that we get a hamburger icon pop up. Click on that, and then you will see our logout button appear.

Okay, awesome. We can now logout. Here's what the code for your Sitebar should look like completed after the above:

import React from 'react';
import { Link } from 'react-router-dom';
import {
    Collapse,
    Navbar,
    NavbarToggler,
    NavbarBrand,
    Nav,
    NavItem,
    Button
} from 'reactstrap';

class SiteBar extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isOpen: false
        };
    }

    toggle = () => {
        this.setState({
            isOpen: !this.state.isOpen
        });
    }

    render() {
        return (
            <div>
                <Navbar color="faded"  light expand="md">
                    <NavbarBrand href="/">Workout Log</NavbarBrand>
                    <NavbarToggler onClick={this.toggle} />
                    <Collapse isOpen={this.state.isOpen} navbar>
                        <Nav className="ml-auto" navbar>
                            <NavItem>
                                <Button onClick={() => this.props.clickLogout()}>Logout</Button>
                            </NavItem>
                        </Nav>
                    </Collapse>
                </Navbar>
            </div>
        );
    }

}

export default SiteBar;

Now that we have our ability to logout, we need to setup login.

Step 3. CSS

And let's end our module with some nice CSS. Create an auth.css inside of your auth folder and then inside of your brand new auth.css let's add some cool stuff:

.auth-container { 
    margin-top: 5em;
    padding: 2em;
    border: 1px solid #e5e5e5;
    border-radius: 0.4em;
    box-shadow: 2px 4px 20px #f0f0f0;
}

.login-col {
    border-left: 1px solid black;
}

Awesome, now let's use it. Go into your auth.js and first import our new file:

import './auth.css'

Then add on your classNames. auth-container to the container and then login-col to your second Col:

<Container className="auth-container">
    <Row>
        <Col md="6">
            <Signup setToken={props.setToken}/>
        </Col>
        <Col md="6" className="login-col">
            <Login setToken={props.setToken}>
        </Col>
    </Row>
</Container>

This should make our app look a little nicer. Let's move on.

Last updated