From 8d0e3b55815883392f42e60ee2164775db348c7a Mon Sep 17 00:00:00 2001 From: Owen Damron Date: Sun, 12 Sep 2021 21:39:32 -0500 Subject: [PATCH] Finished MVP --- src/App.js | 13 +++++- src/components/BubblePage.js | 29 +++++++++++++ src/components/BubblePage.test.js | 16 ++++++- src/components/Color.test.js | 25 ++++++++++- src/components/ColorList.test.js | 14 ++++++ src/components/Login.js | 71 ++++++++++++++++++++++++++++--- src/components/PrivateRoute.js | 16 +++++++ src/helpers/axiosWithAuth.js | 15 ++++++- src/services/fetchColorService.js | 11 ++++- 9 files changed, 195 insertions(+), 15 deletions(-) diff --git a/src/App.js b/src/App.js index 4054971a97..2342b831f9 100644 --- a/src/App.js +++ b/src/App.js @@ -1,17 +1,26 @@ import React, { useState } from "react"; import { BrowserRouter as Router, Route } from "react-router-dom"; - import Login from "./components/Login"; +import BubblePage from "./components/BubblePage"; +import PrivateRoute from "./components/Login"; import "./styles.scss"; function App() { + + const logout = () => { + localStorage.removeItem("token"); + } + return (
Color Picker Sprint Challenge - logout + logout
+ + +
); diff --git a/src/components/BubblePage.js b/src/components/BubblePage.js index 47a88f2291..c4bc444198 100644 --- a/src/components/BubblePage.js +++ b/src/components/BubblePage.js @@ -3,6 +3,7 @@ import React, { useEffect, useState } from "react"; import Bubbles from "./Bubbles"; import ColorList from "./ColorList"; import fetchColorService from '../services/fetchColorService'; +import axiosWithAuth from "../helpers/axiosWithAuth"; const BubblePage = () => { const [colors, setColors] = useState([]); @@ -13,9 +14,37 @@ const BubblePage = () => { }; const saveEdit = (editColor) => { + axiosWithAuth() + .put(`/api/colors/${editColor.id}`, editColor) + .then((res) => { + console.log(res) + + const index = colors.findIndex((color) => color.id === editColor.id); + colors[index] = editColor + setColors([ + ...colors + ]) + }) + .catch((err) => { + console.log(err) + }) }; + useEffect(() => { + fetchColorService().then((res) => { + setColors(res) + }) + }, []); + const deleteColor = (colorToDelete) => { + axiosWithAuth() + .delete(`/api/colors/${colorToDelete.id}`) + .then((res) => { + setColors(colors.filter(color => color.id !== colorToDelete.id)) + }) + .catch((err) => { + console.log(err) + }) }; return ( diff --git a/src/components/BubblePage.test.js b/src/components/BubblePage.test.js index eeaef0c197..6651bceb0e 100644 --- a/src/components/BubblePage.test.js +++ b/src/components/BubblePage.test.js @@ -3,11 +3,23 @@ import MutationObserver from 'mutationobserver-shim'; import { render, screen} from "@testing-library/react"; import BubblePage from './BubblePage'; +jest.mock('../services/fetchColorService'); + +const testColor = { + color: "purple", + code: { hex: "#9345EE"}, + id: 1 +} test("Renders without errors", ()=> { - + render(); }); test("Renders appropriate number of colors passed in through mock", async ()=> { - //Keep in mind that our service is called on mount for this component. + fetchColorServices.mockResolvedValueOnce(testColor); + render(); + const colors = screen.getAllByTestId("color"); + await waitFor(() => { + expect(colors).toHaveLength(1); + }) }); \ No newline at end of file diff --git a/src/components/Color.test.js b/src/components/Color.test.js index def97c5555..12776eac11 100644 --- a/src/components/Color.test.js +++ b/src/components/Color.test.js @@ -5,15 +5,38 @@ import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import Color from './Color'; +const testColor = { + color: "purple", + code: { hex: "#9345EE"}, + id: 1 +} + test("Renders without errors with blank color passed into component", () => { + render(); }); test("Renders the color passed into component", () => { + render(); + const color = screen.queryAllByTestId("color"); + expect(color).toBeInTheDocument(); }); test("Executes handleDelete and toggleEdit property when the 'x' icon is clicked", () => { + const handleDelete = jest.fn(); + const toggleEdit = jest.fn(); + render(); + const deleteKey = screen.getByTestId("delete") + userEvent.click(deletekey) + expect(handleDelete).toBeCalled(); + expect(toggleEdit).toBeCalled(); }); test("Executes setEditColor and toggleEdit property when color div is clicked", () => { - + const setEditColor = jest.fn(); + const toggleEdit = jest.fn(); + render(); + const colorKey = screen.getByTestId("color") + userEvent.click(colorKey) + expect(setEditColor).tobeCalled(); + expect(toggleEdit).toBeCalled(); }); \ No newline at end of file diff --git a/src/components/ColorList.test.js b/src/components/ColorList.test.js index 115b169331..3da0f57f45 100644 --- a/src/components/ColorList.test.js +++ b/src/components/ColorList.test.js @@ -3,12 +3,26 @@ import MutationObserver from 'mutationobserver-shim'; import { render, screen} from "@testing-library/react"; import ColorList from './ColorList'; +import userEvent from '@testing-library/user-event'; + +const testColor = { + color: "purple", + code: { hex: "#9345EE"}, + id: 1 +} test("Renders an empty list of colors without errors", () => { + render(); }); test("Renders a list of colors without errors", () => { + render(); }); test("Renders the EditForm when editing = true and does not render EditForm when editing = false", () => { + const toggleEdit = jest.fn(); + render(); + const editing = screen.queryByTestId("color"); + userEvent.click(editing); + expect(toggleEdit).toBeCalled(); }); diff --git a/src/components/Login.js b/src/components/Login.js index 8df9390633..1a5e9912c5 100644 --- a/src/components/Login.js +++ b/src/components/Login.js @@ -1,17 +1,76 @@ -import React from "react"; +import React, {useState} from "react"; +import axiosWithAuth from "../helpers/axiosWithAuth"; +import {useHistory} from "react-router-dom"; + +const initialValues = { + username: '', + password: '' +} 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 [formValues, setFormValues] = useState(initialValues); + const {push} = useHistory(); + const [error, setError] = useState(); + + const handleChange = e => { + setFormValues({ + ...formValues, + [e.target.name]: e.target.value + }); + }; + + const handleSubmit = e => { + e.preventDefault(); + if (formValues.username !== 'Lambda' || formValues.password !== 'School') { + setError('Username or Password is not valid.') + } - const error = ""; - //replace with error state + axiosWithAuth() + .post('/api/login', formValues) + .then((res) => { + console.log("Axios Login Push", res) + localStorage.setItem('token', res.data.payload) + push('/bubblepage') + }) + .catch((err) => { + console.log({err}) + }) + } return (

Welcome to the Bubble App!

-

Build login form here

+
+ +
+ +
+ +
+ +
+ + + +

{error}

diff --git a/src/components/PrivateRoute.js b/src/components/PrivateRoute.js index e718313bdf..30d93be6c1 100644 --- a/src/components/PrivateRoute.js +++ b/src/components/PrivateRoute.js @@ -1,2 +1,18 @@ +import React, { Component } from 'react'; +import {Route, Redirect} from 'react-router-dom'; + +const PrivateRoute = ({component: Component, ...rest}) => { + return { + if (localStorage.getItem("token")) { + return() + } else { + return + } + }} /> +}; + +export default PrivateRoute; + + //Task List: //1. Build a PrivateRoute component that redirects if user is not logged in \ No newline at end of file diff --git a/src/helpers/axiosWithAuth.js b/src/helpers/axiosWithAuth.js index 1da418ff86..78dc31e1cb 100644 --- a/src/helpers/axiosWithAuth.js +++ b/src/helpers/axiosWithAuth.js @@ -1,4 +1,15 @@ import axios from "axios"; -//Task List: -//Build and export a function used to send in our authorization token \ No newline at end of file +const axiosWithAuth = () => { + const token = localStorage.getItem('token'); + + return axios.create({ + headers: { + Authorization: token + }, + baseURL: 'http://localhost:5000' + }) +}; + +export default axiosWithAuth; + diff --git a/src/services/fetchColorService.js b/src/services/fetchColorService.js index a914deb477..c65119585c 100644 --- a/src/services/fetchColorService.js +++ b/src/services/fetchColorService.js @@ -1,7 +1,14 @@ import axiosWithAuth from '../helpers/axiosWithAuth'; const fetchColorService = () => { - -} + return axiosWithAuth() + .get('/api/colors') + .then((res) => { + console.log("fetchColorService", res); + return(res.data) + }) + .catch((err) => {console.log(err); + }) +}; export default fetchColorService; \ No newline at end of file