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,115 changes: 15,115 additions & 0 deletions client/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"dependencies": {
"@potion/element": "1.0.0-next.0",
"@potion/layout": "1.0.0-next.0",
"axios": "^0.19.0",
"axios": "^0.19.2",
"node-sass": "^4.12.0",
"react": "16.8.6",
"react-dom": "16.8.6",
Expand Down
18 changes: 8 additions & 10 deletions client/src/App.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
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 BubblePage from './components/BubblePage';
import Login from './components/Login';
import './styles.scss';
import { PrivateRoute } from './utils/PrivateRoute';

function App() {
const [colorList, setColorList] = useState([]);
// Authenitcation routes (Protected Routes).
return (
<Router>
<div className="App">
<Route exact path="/" component={Login} />
{/*
Build a PrivateRoute component that will
display BubblePage when you're authenticated
*/}
<PrivateRoute exact path="/bubbles" component={BubblePage} />
</div>
</Router>
);
Expand Down
24 changes: 24 additions & 0 deletions client/src/api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import axios from '../utils/axios';

export const Authenticate = ({ username, password }) => {
return axios.post('login', {
username: username,
password: password,
});
};

export const FetchBubbleList = () => {
return axios.get('colors');
};

export const DeleteColor = (color) => {
return axios.delete(`colors/${color.id}`);
};

export const UpdateColor = (colorToEdit) => {
return axios.put(`colors/${colorToEdit.id}`, colorToEdit);
};

export const AddColor = (colorObject) => {
return axios.post('/api/colors', colorObject);
};
21 changes: 15 additions & 6 deletions client/src/components/BubblePage.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import React, { useState, useEffect } from 'react';

import Bubbles from "./Bubbles";
import ColorList from "./ColorList";
import Bubbles from './Bubbles';
import ColorList from './ColorList';
import { FetchBubbleList } from '../api';

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(() => {
FetchBubbleList()
.then(function ({ data }) {
console.log(data);
setColorList(data);
})
.catch(function (error) {
console.log(error);
});
}, []);

return (
<>
Expand Down
97 changes: 79 additions & 18 deletions client/src/components/ColorList.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,78 @@
import React, { useState } from "react";
import axios from "axios";
import React, { useState } from 'react';
import { AddColor, DeleteColor, UpdateColor } from '../api';

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

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

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

const saveEdit = e => {
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?
UpdateColor(colorToEdit)
.then((res) => {
console.log(res);
setEditing(false);
updateColors(
colors.map((item) => {
return item.id === colorToEdit.id ? colorToEdit : item;
})
);
})
.catch((err) => console.log(err));
};

const deleteColor = color => {
// make a delete request to delete this color
const deleteColor = (color) => {
DeleteColor(color).then((res) => {
console.log(res);
updateColors(colors.filter((item) => item.id !== color.id));
});
};

const addColor = () => {
const colorObject = {
color: newColor.color,
code: { hex: `#${newColor.hex}` },
};
updateColors([...colors, colorObject]);
console.log(colorObject);
AddColor(colorObject)
.then((res) => {
console.log(res);
})
.catch((err) => console.log(err));
};

return (
<div className="colors-wrap">
<p>colors</p>

<ul>
{colors.map(color => (
{colors.map((color) => (
<li key={color.color} onClick={() => editColor(color)}>
<span>
<span className="delete" onClick={() => deleteColor(color)}>
<span
className="delete"
onClick={(e) => {
e.stopPropagation();
deleteColor(color);
}}
>
x
</span>{" "}
</span>{' '}
{color.color}
</span>
<div
Expand All @@ -52,7 +88,7 @@ const ColorList = ({ colors, updateColors }) => {
<label>
color name:
<input
onChange={e =>
onChange={(e) =>
setColorToEdit({ ...colorToEdit, color: e.target.value })
}
value={colorToEdit.color}
Expand All @@ -61,10 +97,10 @@ const ColorList = ({ colors, updateColors }) => {
<label>
hex code:
<input
onChange={e =>
onChange={(e) =>
setColorToEdit({
...colorToEdit,
code: { hex: e.target.value }
code: { hex: e.target.value },
})
}
value={colorToEdit.code.hex}
Expand All @@ -77,7 +113,32 @@ const ColorList = ({ colors, updateColors }) => {
</form>
)}
<div className="spacer" />
{/* stretch - build another form here to add a color */}
<form
onSubmit={(e) => {
e.preventDefault();
addColor();
setNewColor({ color: '', hex: '' });
}}
>
<input
name="color"
placeholder="New Color Name"
value={newColor.color}
onChange={(e) => {
setNewColor({ ...newColor, [e.target.name]: e.target.value });
}}
/>
<input
name="hex"
placeholder="Hex Code"
maxLength="6"
value={newColor.hex}
onChange={(e) => {
setNewColor({ ...newColor, [e.target.name]: e.target.value });
}}
/>
<button type="submit">Add Color</button>
</form>
</div>
);
};
Expand Down
57 changes: 54 additions & 3 deletions client/src/components/Login.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,63 @@
import React from "react";
import React, { useEffect, useState } from 'react';
import { AUTH_TOKEN } from '../utils/constants';
import { useHistory } from 'react-router-dom';
import { Authenticate } from '../api';

const Login = () => {
// make a post request to retrieve a token from the api
// when you have handled the token, navigate to the BubblePage route
const history = useHistory();
// remove testing data before pushing.
const [form, setForm] = useState({
username: 'Lambda School',
password: 'i<3Lambd4',
});
// create a service for axios.
const handleSubmit = () => {
// .env file for base_url
Authenticate(form)
.then(function ({ data }) {
debugger;
localStorage.setItem(AUTH_TOKEN, data.payload);
setForm({ username: '', password: '' });
history.push('/bubbles');
})
.catch(function (error) {
console.log(error);
});
};

useEffect(() => {
if (localStorage.getItem(AUTH_TOKEN)) history.push('/bubbles');
}, []);

return (
<>
<h1>Welcome to the Bubble App!</h1>
<p>Build a login page here</p>
<form
onSubmit={(e) => {
e.preventDefault();
handleSubmit();
}}
>
<input
name="username"
placeholder="User Name"
value={form.username}
onChange={(e) => {
setForm({ ...form, [e.target.name]: e.target.value });
}}
/>
<input
name="password"
type="password"
placeholder="Password"
value={form.password}
onChange={(e) => {
setForm({ ...form, [e.target.name]: e.target.value });
}}
/>
<button type="submit">Login</button>
</form>
</>
);
};
Expand Down
8 changes: 4 additions & 4 deletions client/src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import ReactDOM from "react-dom";
import App from "./App";
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

const rootElement = document.getElementById("root");
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
21 changes: 16 additions & 5 deletions client/src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ body,
.App {
font-family: "Montserrat", sans-serif;
text-align: center;
display: flex;
// display: flex;

svg {
height: 100%;
Expand All @@ -25,15 +25,24 @@ body,
}

.bubble-wrap {
margin: 0 auto;
// height: 100%;
width: 500px;
display: flex;
flex-direction: column;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
padding: 20px;
margin: 20px auto;
align-items: center;
}

.colors-wrap {
height: 100%;
width: 300px;
// height: 100%;
width: 500px;
display: flex;
flex-direction: column;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
padding: 20px;
margin: 20px auto;

ul {
list-style: none;
Expand Down Expand Up @@ -64,6 +73,7 @@ form {
margin-top: 60px;
display: flex;
flex-direction: column;
align-items: center;

legend {
padding-left: 40px;
Expand All @@ -80,7 +90,8 @@ form {
}

input {
width: 100px;
width: 400px;
margin-bottom: 10px;
}
}

Expand Down
20 changes: 20 additions & 0 deletions client/src/utils/PrivateRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { AUTH_TOKEN } from './constants';

export const PrivateRoute = (props) => {
const { component: Component, ...rest } = props;

return (
<Route
{...rest}
render={(renderProps) => {
return localStorage.getItem(AUTH_TOKEN) ? (
<Component {...renderProps} />
) : (
<Redirect to="/" />
);
}}
/>
);
};
Loading