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
15 changes: 15 additions & 0 deletions ANSWERS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
- [ ] Explain what a token is used for.

A token is really used to authenticate if the credentials a user puts in to "log in" with are correct so then will take the user to the correct path. 

- [ ] What steps can you take in your web apps to keep your data secure?

You can add privateRoutes to protected components by using client-side or server-side authentication

- [ ] Describe how web servers work.

web servers are in the actual computer that stores the code/data. the code that tells the computer what to do is called the web server

- [ ] Which HTTP methods can be mapped to the CRUD acronym that we use when interfacing with APIs/Servers.

Post, Get, Put, Delete
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,16 @@ In this project you will create a login page and request a token from the server
Demonstrate your understanding of this Sprint's concepts by answering the following free-form questions. Edit this document to include your answers after each question. Make sure to leave a blank line above and below your answer so it is clear and easy to read by your project manager.

- [ ] Explain what a token is used for.

- [ ] What steps can you take in your web apps to keep your data secure?

- [ ] Describe how web servers work.

- [ ] Which HTTP methods can be mapped to the CRUD acronym that we use when interfacing with APIs/Servers.




## Project Set Up

Follow these steps to set up and work on your project:
Expand Down
2 changes: 1 addition & 1 deletion client/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<!-- <link rel="manifest" href="%PUBLIC_URL%/manifest.json"> -->
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
Expand Down
3 changes: 3 additions & 0 deletions client/src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { useState } from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import PrivateRoute from "./utils/PrivateRoute";
import BubblePage from "./components/BubblePage";

import Login from "./components/Login";
import "./styles.scss";
Expand All @@ -14,6 +16,7 @@ function App() {
Build a PrivateRoute component that will
display BubblePage when you're authenticated
*/}
<PrivateRoute path="/colors" component={BubblePage} />
</div>
</Router>
);
Expand Down
12 changes: 11 additions & 1 deletion client/src/components/BubblePage.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import axiosWithAuth from "../utils/axiosWithAuth";

import Bubbles from "./Bubbles";
import ColorList from "./ColorList";
Expand All @@ -8,7 +9,16 @@ const BubblePage = () => {
const [colorList, setColorList] = useState([]);
// fetch your colors data from the server when the component mounts
// set that data to the colorList state property

useEffect(() => {
axiosWithAuth()
.get("colors")
.then(res => {
setColorList(res.data)
})
.catch(err => {
console.log(err);
});
}, []);
return (
<>
<ColorList colors={colorList} updateColors={setColorList} />
Expand Down
83 changes: 82 additions & 1 deletion client/src/components/ColorList.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,90 @@
import React, { useState } from "react";
import axios from "axios";
import axiosWithAuth from "../utils/axiosWithAuth";
// import { props } from "bluebird";

const initialColor = {
color: "",
code: { hex: "" }
};

const ColorList = ({ colors, updateColors }) => {
console.log(colors);

const [editing, setEditing] = useState(false);
const [colorToEdit, setColorToEdit] = useState(initialColor);
const [addColor, setAddColor] = useState(initialColor);

const editColor = color => {
setEditing(true);
setColorToEdit(color);
};

const renewColors = () => {
axiosWithAuth()
.get("colors")
.then(res => {
updateColors(res.data);
})
.catch(err => {
console.log("Error: ", err);
});
};

const saveEdit = e => {
e.preventDefault();
// Make a put request to save your updated color
// think about where will you get the id from...
// where is is saved right now?

axiosWithAuth()
.put(`colors/${colorToEdit.id}`, colorToEdit)
.then(res => {
const newColors = colors.map(cv => {
if (cv.id == colorToEdit.id) {
return colorToEdit;
} else {
return cv;
}
});
updateColors(newColors);
setEditing(false);

setColorToEdit({ initialColor });
})
.catch(err => {
console.log("Error: ", err);
});
};

const deleteColor = color => {
// make a delete request to delete this color
axiosWithAuth()
.delete(`colors/${color.id}`)
.then(res => {
setColorToEdit(initialColor);
setEditing(false);
renewColors();
})
.catch(err => {
console.log("Error: ", err);
});
};
const handleAddColor = e => {
e.preventDefault();
const newColor = {
...addColor,
id: Date.now()
};
axiosWithAuth()
.post("colors", newColor)
.then(res => {
renewColors();
setAddColor(initialColor);
})
.catch(err => {
console.log("Error: ", err);
});

};

return (
Expand Down Expand Up @@ -78,6 +138,27 @@ const ColorList = ({ colors, updateColors }) => {
)}
<div className="spacer" />
{/* stretch - build another form here to add a color */}
<h1>Add a new color!</h1>
<form onSubmit={handleAddColor}>
<label htmlFor="color">Color Name:</label>
<input
type="text"
name="color"
value={addColor.color}
onChange={e => setAddColor({ ...addColor, color: e.target.value })}
/>
<label htmlFor="code">Color Code:</label>
<input
type="text"
name="code"
value={addColor.code.hex}
onChange={e =>
setAddColor({ ...addColor, code: { hex: e.target.value } })
}
/>
<button type="submit">Add Color!</button>
</form>

</div>
);
};
Expand Down
35 changes: 31 additions & 4 deletions client/src/components/Login.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,40 @@
import React from "react";
import axiosWithAuth from "../utils/axiosWithAuth";

const Login = () => {
const Login = props=> {

const credentials ={ username: "Lambda School", password: "i<3Lambd4"};

// make a post request to retrieve a token from the api
// when you have handled the token, navigate to the BubblePage route
const handleSubmit = e => {
e.preventDefault();
axiosWithAuth()
.post("login", credentials)
.then(res => {
localStorage.setItem("token", res.data.payload);
props.history.push("/colors");
})
.catch(err => {
console.log("Error: ", err);
});
};



return (
<>
<div className ="login">
<h1>Welcome to the Bubble App!</h1>
<p>Build a login page here</p>
</>
<p>This is a super secure website, please enter your account information below, if you dare</p>
<form onSubmit={handleSubmit}>
<label htmlFor="username">Username:</label>
<input type="text" name="username" placeholder="Lambda School" />
<label htmlFor="password">Password:</label>
<input type="password" name="password" placeholder="i<3Lambd4" />
<button type="submit">Login</button>
</form>
</div>

);
};

Expand Down
37 changes: 34 additions & 3 deletions client/src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@ body,
height: 100%;
margin: 0;
padding: 0;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #282c34;
color: white;
}

.login {

display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 50px;
padding: 50px;
color: white;
}

form {
justify-content: center;
}

.App {
Expand All @@ -18,6 +38,7 @@ body,
svg {
height: 100%;
}

}

.spacer {
Expand All @@ -26,7 +47,7 @@ body,

.bubble-wrap {
margin: 0 auto;
display: flex;
// display: flex;
flex-direction: column;
}

Expand All @@ -53,6 +74,7 @@ body,
color: rgb(216, 87, 87);
}


.color-box {
height: 16px;
width: 16px;
Expand All @@ -62,8 +84,13 @@ body,

form {
margin-top: 60px;
align-items: center;
display: flex;
flex-direction: column;
padding: 30px;
padding-bottom: 50px;
border: 5px solid;
border-color: red green blue orange;

legend {
padding-left: 40px;
Expand All @@ -76,24 +103,28 @@ form {
label {
display: flex;
justify-content: space-between;
padding: 4px 36px 4px 40px;
padding: 25px;
font-size: 25px;
}

input {
width: 100px;
font-size: 14px;

}
}

.button-row {
display: flex;
justify-content: space-between;
padding: 0 36px 0 41px;

button {
border: none;
background-color: black;
color: white;
padding: 3px 8px;
margin-top: 16px;
font-size: 15psx;

}
}
19 changes: 19 additions & 0 deletions client/src/utils/PrivateRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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")) {
return <Component {...props} />;
} else {
return <Redirect to="/" />;
}
}}
/>
);
};

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

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

return axios.create({
baseURL: "http://localhost:5000/api/",
headers: {
Authorization: token
}
});
};

export default axiosWithAuth;
Loading