Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Auth Friends
# Auth Friends (Checklist)

Topics:

Expand All @@ -15,10 +15,10 @@ Topics:

#### Initialize Project

* Run `npm install` inside the root directory of this project to install dependencies for the API server.
* Run `npm start` to start the API server.
* `cd` into the _friends_ folder.
* Run `npm start` to start the client code.
[x] Run `npm install` inside the root directory of this project to install dependencies for the API server.
[x] Run `npm start` to start the API server.
[x] `cd` into the _friends_ folder.
[x] Run `npm start` to start the client code.

### Task 2: MVP

Expand All @@ -37,12 +37,17 @@ Topics:
* **[POST]** * to `/api/friends`: Adds in a new friend.

#### Build the App!
* Add a route for a login page and build out a simple login form with username and password inputs and a submit button (design this however you would like).
* The login function should save the returned token to localStorage. You can setup `isLoading` state in your Login component, and show a spinner on your form or in your button while the login request is happening.
* When the request returns, save the token to `localStorage`, then use the history object in your Login component to navigate your user to your FriendsList route
* Create a `<PrivateRoute />` component to protect your other routes. It should check localStorage for a token, and redirect the user to your login route if there is not a token.
* Create a protected route for your friends list. Remember, if the user isn't logged in, navigating to this protected route will redirect them to the login page.
* In your FriendsList component, rendered with `<PrivateRoute />`, you will create a list of your friends that you get from the API.
[x] Add a route for a login page and build out a simple login form with username and password inputs and a submit button (design this however you would like).

[x] The login function should save the returned token to localStorage. You can setup `isLoading` state in your Login component, and show a spinner on your form or in your button while the login request is happening.

[x] When the request returns, save the token to `localStorage`, then use the history object in your Login component to navigate your user to your FriendsList route

[x] Create a `<PrivateRoute />` component to protect your other routes. It should check localStorage for a token, and redirect the user to your login route if there is not a token.

[x] Create a protected route for your friends list. Remember, if the user isn't logged in, navigating to this protected route will redirect them to the login page.

[x] In your FriendsList component, rendered with `<PrivateRoute />`, you will create a list of your friends that you get from the API.

**Adding New Friends**
* Create a form to collects data for a new friend.
Expand All @@ -58,7 +63,8 @@ Topics:
}
```

* If you'd like, you can create multiple "view" components for your routes. You could have a component who's sole purpose is to render the login form; one for a form for updating a user; another component who's sole purpose is for creating users; and then another component who's sole purpose is to delete a user.
[x] If you'd like, you can create multiple "view" components for your routes. You could have a component who's sole purpose is to render the login form; one for a form for updating a user; another component who's sole purpose is for creating users; and then another component who's sole purpose is to delete a user.
Added Logout component and axiosWithAuth
* It really is up to you how you build this project. I suggest writing down the flow you want to follow, and then writing down each individual piece you need for each step in the flow so that this process doesn't feel as overwhelming.

### Task 3: Stretch Problems
Expand Down
44 changes: 44 additions & 0 deletions friends/src/components/Friends.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import axios from 'axios';
import React from 'react';
import { BrowserRouter as Router, Switch, Link } from 'react-router-dom';
import PrivateRoute from './PrivateRoute';
import axiosWithAuth from '../utils/axiosWithAuth';

class Friends extends React.Component {
state = {
friends: []
};

componentDidMount() {
axiosWithAuth().get('/api/friends', {

}).then(response => {
this.setState({
...this.state,
friends: response.data
})
}).catch(error => {
console.error(error);
})
}

render() {

const { friends } = this.state;
return(
<div>
{friends.map(friend => {
return(
<div key = {friend.id}>
<h3>Name: {friend.name}</h3>
<h3>Age: {friend.age}</h3>
<h3>Email: {friend.email}</h3>
</div>
)
})}
</div>
)
}
}

export default Friends;
74 changes: 74 additions & 0 deletions friends/src/components/Login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from 'react';
import axois from 'axios';
import axios from 'axios';

class Login extends React.Component {

// Initial state (values)
state = {
credentials: {
username: "",
password: ""
}
};

// handling change when clicking a button
handleChange = event => {
this.setState({
credentials: {
...this.state.credentials,
[event.target.name]: event.target.value
}
})
};

// Login axios call using Post
login = () => {
axios.post("http://localhost:5000/api/login", this.state.credentials)
.then(response => {
localStorage.setItem("token", response.data.payload);
localStorage.setItem("username", this.state.credentials.username);
this.props.history.push("/protected");

}).catch(error => {
console.error(error);
})
};


// render props
render() {
return(
<div>
<form onSubmit = {this.login}>
{/* Input fields for username and password */}
<label> Username
<input
type = "text"
name = "username"
value = {this.state.credentials.username}
onChange = {this.handleChange}
/>
</label>

<label> Password
<input
type = "password"
name = "password"
value = {this.state.credentials.password}
onChange = {this.handleChange}
/>
</label>

{/* Submit button */}
<button>Log In</button>
</form>
</div>

)
}


}

export default Login;
24 changes: 24 additions & 0 deletions friends/src/components/Logout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { useEffect } from 'react';
import axiosWithAuth from '../utils/axiosWithAuth';

const Logout = (props) => {
useEffect(() => {
axiosWithAuth().post("/api/logout", {

}).then(response => {
localStorage.removeItem("token");
localStorage.removeItem("username");
props.history.push("/login")

}).catch(error => {
console.error(error)
})
}, [])


return(
<div>
{/* empty? */}
</div>
)
}
14 changes: 14 additions & 0 deletions friends/src/components/PrivateRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { Route, Redirect } from 'react-router-dom';

const PrivateRoute = ({ component: Component, ...rest }) => {
return <Route { ...rest } render = { ( props ) => {
if(localStorage.getItem("token")){

} else {
return <Redirect to = "/login"/>
}
}}/>
}

export default PrivateRoute;
15 changes: 15 additions & 0 deletions friends/src/utils/axiosWithAuth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import axios from 'axios';

const axiosWithAuth = () => {
const token = localStorage.getItem("token");

return axios.create({
headers: {
authorization: token
},

baseURL: "http://localhost:5000"
})
}

export default axiosWithAuth;
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "",
"main": "server.js",
"dependencies": {
"axios": "^0.24.0",
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1"
Expand All @@ -18,4 +19,3 @@
"author": "Lambda School",
"license": "ISC"
}