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
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,21 @@ 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.

* Tokens are used to provide proof that a user has been authenticated.

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

* use protected routes that will not allow a user access to data without correct authentication.

- [ ] Describe how web servers work.

* A series of computers that store data that are connected to the web that also contain software to 'serve' web pages that retrive the data based on a user's request.


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

* .post, .get, .put and .delete.

## Project Set Up

Expand Down
15,180 changes: 15,180 additions & 0 deletions client/package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"react": "16.8.6",
"react-dom": "16.8.6",
"react-router-dom": "^5.0.1",
"react-scripts": "3.0.1"
"react-scripts": "3.0.1",
"styled-components": "^5.0.0"
},
"devDependencies": {
"typescript": "3.3.3"
Expand Down
25 changes: 12 additions & 13 deletions client/src/App.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import React, { useState } from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";

import Login from "./components/Login";
import "./styles.scss";
import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Login from './components/Login';
import PrivateRoute from './components/PrivateRoute';
import BubblePage from './components/BubblePage';
import './styles.scss';

function App() {
return (
<Router>
<div className="App">
<Route exact path="/" component={Login} />
{/*
Build a PrivateRoute component that will
display BubblePage when you're authenticated
*/}
</div>
<div className='App'>
<Route exact path='/' component={Login} />
<PrivateRoute exact path='/bubbles' component={BubblePage} />
</div>
</Router>
);
);
}

export default App;

15 changes: 12 additions & 3 deletions client/src/components/BubblePage.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import React, { useState, useEffect } from "react";
import axios from "axios";

import Bubbles from "./Bubbles";
import ColorList from "./ColorList";
import Bubbles from './Bubbles';
import ColorList from './ColorList';
import { axiosWithAuth } from '../utils/axiosWithAuth';

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('http://localhost:5000/api/colors')
.then(res => {
setColorList(res.data)
})
.catch(err => console.log(err))
}, []);

return (
<>
<ColorList colors={colorList} updateColors={setColorList} />
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Bubbles.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const Bubbles = ({ colors }) => {

return (
<div className="bubble-wrap">
<p>bubbles</p>
<p>Bubbles</p>
<Svg width={400} height={400}>
<Pack
data={{
Expand Down
133 changes: 96 additions & 37 deletions client/src/components/ColorList.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React, { useState } from "react";
import axios from "axios";
import React, { useState } from 'react';
import { axiosWithAuth } from '../utils/axiosWithAuth';

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

const ColorList = ({ colors, updateColors }) => {
console.log(colors);
const [newColor, setNewColor] = useState(initialColor);
const [editing, setEditing] = useState(false);
const [colorToEdit, setColorToEdit] = useState(initialColor);

Expand All @@ -20,70 +20,129 @@ const ColorList = ({ colors, updateColors }) => {
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?
// where it is saved right now?

axiosWithAuth()
.put(`http://localhost:5000/api/colors/${colorToEdit.id}`, colorToEdit)
.then(res => {
const newColors = colors.map(color => {
if (color.id === colorToEdit.id) {
return res.data;
}
return color;
});
updateColors(newColors);
})
.catch(err => console.log(err));
};

const addColor = e => {
e.preventDefault();
axiosWithAuth()
.post(`http://localhost:5000/api/colors/`, newColor)
.then(res => {
updateColors(res.data);
})
.catch(error => console.log(error));
};

const deleteColor = color => {
// make a delete request to delete this color
axiosWithAuth()
.delete(`http://localhost:5000/api/colors/${color.id}`)
.then(res => {
const newColors = colors.filter(c => c.id !== color.id);
updateColors(newColors);
})
.catch(error => console.log(error));
};

return (
<div className="colors-wrap">
<p>colors</p>
<ul>
{colors.map(color => (
<li key={color.color} onClick={() => editColor(color)}>
<span>
<span className="delete" onClick={e => {
e.stopPropagation();
deleteColor(color)
}
}>
x
</span>{" "}
{color.color}
<div className='colors-wrap'>
<p>Colors</p>
<ul>
{colors.map(color => (
<li key={color.color}>
<span>
<span className='delete' onClick={() => deleteColor(color)}>
x
</span>{' '}
<span onClick={() => editColor(color)}>{color.color}</span>
</span>
<div
className="color-box"
style={{ backgroundColor: color.code.hex }}
/>
</li>
))}
</ul>
{editing && (
<form onSubmit={saveEdit}>
<legend>edit color</legend>
className='color-box'
style={{ backgroundColor: color.code.hex }}
/>
</li>
))}
</ul>
{editing && (
<form onSubmit={saveEdit}>
<legend>edit color</legend>
<label>
color name:
<input
onChange={e =>
setColorToEdit({ ...colorToEdit, color: e.target.value })
}
value={colorToEdit.color}
/>
</label>
<label>
hex code:
<input
onChange={e =>
setColorToEdit({
...colorToEdit,
code: { hex: e.target.value }
})
}
value={colorToEdit.code.hex}
/>
</label>
<div className='button-row'>
<button onClick={saveEdit} type='submit'>
save
</button>
<button onClick={() => setEditing(false)}>cancel</button>
</div>
</form>
)}
{!editing && (
<form onSubmit={addColor}>
<legend>add color</legend>
<label>
color name:
<input
onChange={e =>
setColorToEdit({ ...colorToEdit, color: e.target.value })
setNewColor({ ...newColor, color: e.target.value })
}
value={colorToEdit.color}
value={newColor.color}
/>
</label>
<label>
hex code:
<input
onChange={e =>
setColorToEdit({
...colorToEdit,
setNewColor({
...newColor,
code: { hex: e.target.value }
})
}
value={colorToEdit.code.hex}
value={newColor.code.hex}
/>
</label>
<div className="button-row">
<button type="submit">save</button>
<button onClick={() => setEditing(false)}>cancel</button>
<div className='button-row'>
<button onClick={addColor} type='submit'>
add
</button>
</div>
</form>
)}
<div className="spacer" />
<div className='spacer' />
{/* stretch - build another form here to add a color */}
</div>
);
};

export default ColorList;
export default ColorList;
83 changes: 78 additions & 5 deletions client/src/components/Login.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,87 @@
import React from "react";
import React, { useState } from 'react';
import axios from 'axios';
import styled from 'styled-components';

const Login = () => {
const Login = props => {
const [user, setUser] = useState({ username: '', password: '' });
// make a post request to retrieve a token from the api
// when you have handled the token, navigate to the BubblePage route
const login = e => {
e.preventDefault();
axios
.post('http://localhost:5000/api/login', user)
.then(res => {
localStorage.setItem('token', res.data.payload);
props.history.push('/bubbles');
})
.catch(error => console.log(error));
};

const handleChange = e => {
setUser({ ...user, [e.target.name]: e.target.value });
console.log(user);
};

return (
<>
<Wrapper>
<h1>Welcome to the Bubble App!</h1>
<p>Build a login page here</p>
</>
<Form onSubmit={login}>
<Input
type='text'
name='username'
value={user.username}
placeholder='Enter Username'
onChange={handleChange}
/>
<Input
type='password'
name='password'
value={user.password}
placeholder='Enter Password'
onChange={handleChange}
/>
<Button>Login</Button>
</Form>
</Wrapper>
);
};

export default Login;

// Adding styling

const Wrapper = styled.div`
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: gray;
`;

const Button = styled.button`
background: #ee9701;
border-radius: 20px;
padding: 10px;
margin: 5px;
font-weight: bold;
`;

const Input = styled.input`
padding: 10px;
margin: 10px;
border-radius: 20px;
border: 1px black;
`;

const Form = styled.form`
background: #89DCF5;
border-radius: 15px;
border: 7px ridge rgba(28,110,164,0.77);
padding: 40px;
margin: 0;
box-shadow: 10px 10px 8px #888888;
`;



18 changes: 18 additions & 0 deletions client/src/components/PrivateRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import { Route, Redirect } from 'react-router';

const PrivateRoute = ({ component: Component, ...rest }) => {
return (
<Route
{...rest}
render={props => {
if (localStorage.getItem('token')) {
return <Component {...props} />;
}
return <Redirect to='/' />;
}}
/>
);
};

export default PrivateRoute;
Loading