From 8d0d38977a30bb769ce718a8b04b624eb10745c1 Mon Sep 17 00:00:00 2001 From: StephBerg86 Date: Thu, 27 Aug 2020 12:16:10 +0200 Subject: [PATCH 1/4] added authentication on homepage --- src/App.js | 5 +++-- src/components/Navigation/index.js | 2 -- src/components/Navigation/protectedRoute.js | 9 +++++++++ src/pages/Exercise/index.js | 4 +++- src/pages/Homepage/index.js | 3 ++- src/store/exercise/actions.js | 15 ++++++++------- 6 files changed, 25 insertions(+), 13 deletions(-) create mode 100644 src/components/Navigation/protectedRoute.js diff --git a/src/App.js b/src/App.js index 29e0892..7b7b3b6 100644 --- a/src/App.js +++ b/src/App.js @@ -10,6 +10,7 @@ import Login from "./pages/Login"; import Welcome from "./pages/Welcome"; import Homepage from "./pages/Homepage"; import Exercise from "./pages/Exercise"; +import ProtectedRoute from "./components/Navigation/protectedRoute"; import { useDispatch, useSelector } from "react-redux"; import { selectAppLoading } from "./store/appState/selectors"; @@ -30,10 +31,10 @@ function App() { {isLoading ? : null} - - + + ); diff --git a/src/components/Navigation/index.js b/src/components/Navigation/index.js index aa4780c..00799e7 100644 --- a/src/components/Navigation/index.js +++ b/src/components/Navigation/index.js @@ -10,7 +10,6 @@ import LoggedOut from "./LoggedOut"; export default function Navigation() { const token = useSelector(selectToken); - const loginLogoutControls = token ? : ; return ( @@ -25,7 +24,6 @@ export default function Navigation() { diff --git a/src/components/Navigation/protectedRoute.js b/src/components/Navigation/protectedRoute.js new file mode 100644 index 0000000..56a974a --- /dev/null +++ b/src/components/Navigation/protectedRoute.js @@ -0,0 +1,9 @@ +import React from "react"; +import { Redirect } from "react-router-dom"; + +export default function protectedRoute({ component }) { + const Component = component; + const isAuthenticated = localStorage.getItem("token"); + + return isAuthenticated ? : ; +} diff --git a/src/pages/Exercise/index.js b/src/pages/Exercise/index.js index 616bc96..357cfa7 100644 --- a/src/pages/Exercise/index.js +++ b/src/pages/Exercise/index.js @@ -15,6 +15,7 @@ export default function Exercise() { const allCurrentExercises = useSelector(selectExercise); const completedExercises = useSelector(selectCompletedExercises); const [currentExercise, setCurrentExercise] = useState(""); + console.log("all ex", allCurrentExercises); useEffect(() => { completedExercises.forEach((item) => { @@ -40,7 +41,7 @@ export default function Exercise() { dispatch(getCompletedExercises()); dispatch(getExerciseById(exerciseId)); }, [dispatch, exerciseId]); - // console.log("current exercise", currentExercise) + console.log("current exercise", currentExercise); const questionFormat = () => { if (currentExercise && currentExercise.level === "level 1") { @@ -49,6 +50,7 @@ export default function Exercise() { return ; } else { //return some loading indicator would be better + console.log("test"); return null; } }; diff --git a/src/pages/Homepage/index.js b/src/pages/Homepage/index.js index c733f91..54dda10 100644 --- a/src/pages/Homepage/index.js +++ b/src/pages/Homepage/index.js @@ -16,7 +16,7 @@ export default function Homepage() { useEffect(() => { dispatch(getExercises()); - }, [dispatch]); + }, []); useEffect(() => { if (!searchTerm) { @@ -26,6 +26,7 @@ export default function Homepage() { exercise.name.toLowerCase().includes(searchTerm.toLowerCase()) ); setSearchResults(results); + } }, [searchTerm]); const handleChange = (event) => { diff --git a/src/store/exercise/actions.js b/src/store/exercise/actions.js index b0502f1..fc1ec18 100644 --- a/src/store/exercise/actions.js +++ b/src/store/exercise/actions.js @@ -4,14 +4,15 @@ import { appLoading, appDoneLoading, setMessage } from "../appState/actions"; import { selectToken } from "../user/selectors"; export const GET_EXERCISE_SUCCESS = "GET_EXERCISE_SUCCESS"; + export const SET_QUIZ_QUESTIONS = "SET_QUIZ_QUESTIONS"; export const setQuizQuestions = (data) => { return { type: SET_QUIZ_QUESTIONS, - payload: data - } -} + payload: data, + }; +}; export const getExerciseSuccess = (exercise) => { return { @@ -22,11 +23,11 @@ export const getExerciseSuccess = (exercise) => { export const getExercises = () => { return async (dispatch, getState) => { - const tokenNeeded = getState().user.token - const response = await axios.get(`${apiUrl}/exercises/list`,{ + const tokenNeeded = getState().user.token; + const response = await axios.get(`${apiUrl}/exercises/list`, { headers: { - Authorization: `Bearer ${tokenNeeded}` - } + Authorization: `Bearer ${tokenNeeded}`, + }, }); // console.log("response.data", response.data); dispatch(getExerciseSuccess(response.data)); From 8a32441a1eca1454f54aa8a8e536400670b8fd1c Mon Sep 17 00:00:00 2001 From: StephBerg86 Date: Thu, 27 Aug 2020 12:35:17 +0200 Subject: [PATCH 2/4] changed the colors of the buttons and links --- src/components/Navigation/LoggedIn.js | 18 ++++++++++++++-- src/pages/Login/index.js | 26 +++++++++++++++++------ src/pages/SignUp/index.js | 30 ++++++++++++++++++++------- src/pages/Welcome/index.js | 16 +++++++------- 4 files changed, 67 insertions(+), 23 deletions(-) diff --git a/src/components/Navigation/LoggedIn.js b/src/components/Navigation/LoggedIn.js index 35410ea..8ceb58f 100644 --- a/src/components/Navigation/LoggedIn.js +++ b/src/components/Navigation/LoggedIn.js @@ -1,7 +1,6 @@ import React from "react"; import { useDispatch, useSelector } from "react-redux"; import { logOut } from "../../store/user/actions"; -import Button from "react-bootstrap/Button"; import { selectUser } from "../../store/user/selectors"; import Nav from "react-bootstrap/Nav"; @@ -11,7 +10,22 @@ export default function LoggedIn() { return ( <> {user.email} - + ); } diff --git a/src/pages/Login/index.js b/src/pages/Login/index.js index d35d780..3f9f97f 100644 --- a/src/pages/Login/index.js +++ b/src/pages/Login/index.js @@ -1,7 +1,6 @@ import React, { useState, useEffect } from "react"; import Form from "react-bootstrap/Form"; import Container from "react-bootstrap/Container"; -import Button from "react-bootstrap/Button"; import { login } from "../../store/user/actions"; import { selectToken } from "../../store/user/selectors"; import { useDispatch, useSelector } from "react-redux"; @@ -39,7 +38,7 @@ export default function SignUp() { Email address setEmail(event.target.value)} + onChange={(event) => setEmail(event.target.value)} type="email" placeholder="Enter email" required @@ -50,18 +49,33 @@ export default function SignUp() { Password setPassword(event.target.value)} + onChange={(event) => setPassword(event.target.value)} type="password" placeholder="Password" required /> - + - + Click here to sign up diff --git a/src/pages/SignUp/index.js b/src/pages/SignUp/index.js index 9e7b90f..888f583 100644 --- a/src/pages/SignUp/index.js +++ b/src/pages/SignUp/index.js @@ -1,7 +1,6 @@ import React, { useState, useEffect } from "react"; import Form from "react-bootstrap/Form"; import Container from "react-bootstrap/Container"; -import Button from "react-bootstrap/Button"; import { signUp } from "../../store/user/actions"; import { selectToken } from "../../store/user/selectors"; import { useDispatch, useSelector } from "react-redux"; @@ -40,7 +39,7 @@ export default function SignUp() { Name setName(event.target.value)} + onChange={(event) => setName(event.target.value)} type="text" placeholder="Enter name" required @@ -50,7 +49,7 @@ export default function SignUp() { Email address setEmail(event.target.value)} + onChange={(event) => setEmail(event.target.value)} type="email" placeholder="Enter email" required @@ -64,18 +63,35 @@ export default function SignUp() { Password setPassword(event.target.value)} + onChange={(event) => setPassword(event.target.value)} type="password" placeholder="Password" required /> - + - Click here to log in + + Click here to log in + ); diff --git a/src/pages/Welcome/index.js b/src/pages/Welcome/index.js index 2ab1c56..0bd3974 100644 --- a/src/pages/Welcome/index.js +++ b/src/pages/Welcome/index.js @@ -17,14 +17,14 @@ export default function Welcome() { You will start as a code monkey but if you complete all the exercises you can become the ultimate code master!

-

-
- - - - {" "} - for free and start your code challenge now! - +

+
+ + + + {" "} + for free and start your code challenge now! +

From 0f3f455757973c11f487fdf667cdff4c4229cb78 Mon Sep 17 00:00:00 2001 From: StephBerg86 Date: Thu, 27 Aug 2020 13:57:38 +0200 Subject: [PATCH 3/4] fixed the fetching issue of homepage --- src/pages/Homepage/index.js | 22 ++++++++++++---------- src/store/exercise/reducer.js | 6 +++--- src/store/user/actions.js | 33 ++++++++++++++++++--------------- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/pages/Homepage/index.js b/src/pages/Homepage/index.js index 54dda10..a9be66d 100644 --- a/src/pages/Homepage/index.js +++ b/src/pages/Homepage/index.js @@ -15,7 +15,9 @@ export default function Homepage() { const [searchResults, setSearchResults] = useState([]); useEffect(() => { - dispatch(getExercises()); + if (exercises.length === 0) { + dispatch(getExercises()); + } }, []); useEffect(() => { @@ -48,16 +50,16 @@ export default function Homepage() { {data.map((exercise) => { return ( - - - + + + {exercise.name} - -
- Exercises:
- MonkeyMaster: -
-
+
+ Exercises: 3
+ MonkeyMaster: +
+
+ ); })} diff --git a/src/store/exercise/reducer.js b/src/store/exercise/reducer.js index c8cfe07..b413d02 100644 --- a/src/store/exercise/reducer.js +++ b/src/store/exercise/reducer.js @@ -13,12 +13,12 @@ export default (state = initialState, action) => { case SET_QUIZ_QUESTIONS: return { ...state, - questions: [...state.questions, ...action.payload] - } + questions: [...state.questions, ...action.payload], + }; case GET_EXERCISE_SUCCESS: return { ...state, - exercises: [...state.exercises, ...action.payload], + exercises: [...action.payload], }; default: diff --git a/src/store/user/actions.js b/src/store/user/actions.js index 5f9bc1f..278ef14 100644 --- a/src/store/user/actions.js +++ b/src/store/user/actions.js @@ -169,22 +169,25 @@ export const updateCompletedExercise = (exerciseId, quizId, timeTaken, exp) => { }; }; -export function sendCompletedQuiz(exerciseId, quizId){ - return async(dispatch, getState) => { - const tokenNeeded = getState().user.token - try{ - const infoUpdated = await axios.patch(`${apiUrl}/exercises/${exerciseId}/quiz/completed/${quizId}`,{},{ - headers: { - Authorization: `Bearer ${tokenNeeded}` +export function sendCompletedQuiz(exerciseId, quizId) { + return async (dispatch, getState) => { + const tokenNeeded = getState().user.token; + try { + const infoUpdated = await axios.patch( + `${apiUrl}/exercises/${exerciseId}/quiz/completed/${quizId}`, + {}, + { + headers: { + Authorization: `Bearer ${tokenNeeded}`, + }, } - }) - console.log("updated info test", infoUpdated.data.user) - - dispatch(getCompletedExercisesSuccess(infoUpdated.data.completedQuiz)) - dispatch(tokenStillValid(infoUpdated.data.user)) + ); + console.log("updated info test", infoUpdated.data.user); - } catch(error){ - console.log(error.message) + dispatch(getCompletedExercisesSuccess(infoUpdated.data.completedQuiz)); + dispatch(tokenStillValid(infoUpdated.data.user)); + } catch (error) { + console.log(error.message); } - } + }; } From ed2905d6fb2ab142dad0ab8fcf4f4039c6d45074 Mon Sep 17 00:00:00 2001 From: StephBerg86 Date: Thu, 27 Aug 2020 15:30:46 +0200 Subject: [PATCH 4/4] first round of testing --- package-lock.json | 61 +++++++++++++++++---- package.json | 1 + src/App.js | 22 ++++++-- src/components/Navigation/LoggedIn.js | 8 ++- src/components/Navigation/protectedRoute.js | 9 --- src/pages/Exercise/index.js | 2 + src/pages/Homepage/index.js | 2 +- 7 files changed, 80 insertions(+), 25 deletions(-) delete mode 100644 src/components/Navigation/protectedRoute.js diff --git a/package-lock.json b/package-lock.json index e188120..89e1b34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8322,13 +8322,12 @@ "integrity": "sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=" }, "mini-create-react-context": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz", - "integrity": "sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz", + "integrity": "sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA==", "requires": { - "@babel/runtime": "^7.4.0", - "gud": "^1.0.0", - "tiny-warning": "^1.0.2" + "@babel/runtime": "^7.5.5", + "tiny-warning": "^1.0.3" } }, "mini-css-extract-plugin": { @@ -10787,15 +10786,15 @@ } }, "react-router": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.1.2.tgz", - "integrity": "sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", + "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", "requires": { "@babel/runtime": "^7.1.2", "history": "^4.9.0", "hoist-non-react-statics": "^3.1.0", "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.3.0", + "mini-create-react-context": "^0.4.0", "path-to-regexp": "^1.7.0", "prop-types": "^15.6.2", "react-is": "^16.6.0", @@ -10830,6 +10829,48 @@ "react-router": "5.1.2", "tiny-invariant": "^1.0.2", "tiny-warning": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "mini-create-react-context": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz", + "integrity": "sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw==", + "requires": { + "@babel/runtime": "^7.4.0", + "gud": "^1.0.0", + "tiny-warning": "^1.0.2" + } + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + } + }, + "react-router": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.1.2.tgz", + "integrity": "sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.3.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + } } }, "react-scripts": { diff --git a/package.json b/package.json index ada209b..0f8aeb7 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "react-dom": "^16.13.0", "react-motion": "^0.5.2", "react-redux": "^7.2.0", + "react-router": "^5.2.0", "react-router-dom": "^5.1.2", "react-scripts": "^3.4.3", "redux": "^4.0.5", diff --git a/src/App.js b/src/App.js index 7b7b3b6..b7d9f39 100644 --- a/src/App.js +++ b/src/App.js @@ -1,7 +1,7 @@ import React, { useEffect } from "react"; import "./App.css"; -import { Switch, Route } from "react-router-dom"; +import { Switch, Route, Redirect } from "react-router-dom"; import Navigation from "./components/Navigation"; import Loading from "./components/Loading"; import MessageBox from "./components/MessageBox"; @@ -10,7 +10,6 @@ import Login from "./pages/Login"; import Welcome from "./pages/Welcome"; import Homepage from "./pages/Homepage"; import Exercise from "./pages/Exercise"; -import ProtectedRoute from "./components/Navigation/protectedRoute"; import { useDispatch, useSelector } from "react-redux"; import { selectAppLoading } from "./store/appState/selectors"; @@ -24,6 +23,15 @@ function App() { dispatch(getUserWithStoredToken()); }, [dispatch]); + const protectedRoutes = (Component, routerProps) => { + const isAuthenticated = localStorage.getItem("token"); + return isAuthenticated ? ( + + ) : ( + + ); + }; + return (
@@ -33,8 +41,14 @@ function App() { - - + protectedRoutes(Homepage, routerProps)} + /> + protectedRoutes(Exercise, routerProps)} + />
); diff --git a/src/components/Navigation/LoggedIn.js b/src/components/Navigation/LoggedIn.js index 8ceb58f..2b2d016 100644 --- a/src/components/Navigation/LoggedIn.js +++ b/src/components/Navigation/LoggedIn.js @@ -1,11 +1,14 @@ import React from "react"; import { useDispatch, useSelector } from "react-redux"; +// import { useHistory } from "react-router"; import { logOut } from "../../store/user/actions"; import { selectUser } from "../../store/user/selectors"; import Nav from "react-bootstrap/Nav"; +import Homepage from "../../pages/Homepage"; export default function LoggedIn() { const dispatch = useDispatch(); + // const history = useHistory(); const user = useSelector(selectUser); return ( <> @@ -22,7 +25,10 @@ export default function LoggedIn() { fontSize: "16px", borderRadius: "8px", }} - onClick={() => dispatch(logOut())} + onClick={() => { + dispatch(logOut()); + // history.push(Homepage); + }} > Logout diff --git a/src/components/Navigation/protectedRoute.js b/src/components/Navigation/protectedRoute.js deleted file mode 100644 index 56a974a..0000000 --- a/src/components/Navigation/protectedRoute.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from "react"; -import { Redirect } from "react-router-dom"; - -export default function protectedRoute({ component }) { - const Component = component; - const isAuthenticated = localStorage.getItem("token"); - - return isAuthenticated ? : ; -} diff --git a/src/pages/Exercise/index.js b/src/pages/Exercise/index.js index 357cfa7..2799641 100644 --- a/src/pages/Exercise/index.js +++ b/src/pages/Exercise/index.js @@ -10,7 +10,9 @@ import QuizCode from "../../components/QuizCode"; export default function Exercise() { const param = useParams(); + console.log("param", param); const exerciseId = param.id; + console.log("ex id test", exerciseId); const dispatch = useDispatch(); const allCurrentExercises = useSelector(selectExercise); const completedExercises = useSelector(selectCompletedExercises); diff --git a/src/pages/Homepage/index.js b/src/pages/Homepage/index.js index a9be66d..32579d5 100644 --- a/src/pages/Homepage/index.js +++ b/src/pages/Homepage/index.js @@ -29,7 +29,7 @@ export default function Homepage() { ); setSearchResults(results); } - }, [searchTerm]); + }, [searchTerm, exercises]); const handleChange = (event) => { setSearchTerm(event.target.value);