From 58cae444acab5a7764fc1d2a08ab9ed9e4305a35 Mon Sep 17 00:00:00 2001 From: Diego Lavayen Alarcon Date: Fri, 8 Apr 2022 20:17:05 +0100 Subject: [PATCH 1/7] feat: implement simple auth context with a mock login logic For this iteration, username && password should be either 1, 2, 3 or 4 (this logic in reality should live in the backend) --- src/providers/Auth.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/providers/Auth.js diff --git a/src/providers/Auth.js b/src/providers/Auth.js new file mode 100644 index 0000000..1c5147f --- /dev/null +++ b/src/providers/Auth.js @@ -0,0 +1,33 @@ +import { useState, createContext, useContext } from 'react'; + +const AuthContext = createContext(); + +export const useAuth = () => useContext(AuthContext); + +export const AuthProvider = ({ children }) => { + const [currentUser, setCurrentUser] = useState(); + + const signIn = (username, password) => { + // mock login logic + if ( + username && + username == password && + !isNaN(username) && + username > 0 && + username < 5 + ) { + setCurrentUser(username); + return true; + } + + return false; + }; + + const signOut = () => { + setCurrentUser(null); + }; + + const value = { currentUser, signIn, signOut }; + + return {children}; +}; From 6d68eee52b161e2e2a8692bf9490491dff781b44 Mon Sep 17 00:00:00 2001 From: Diego Lavayen Alarcon Date: Fri, 8 Apr 2022 20:17:22 +0100 Subject: [PATCH 2/7] feat: wrap our App component with our AuthProvider --- src/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index f452ad2..c45d471 100644 --- a/src/index.js +++ b/src/index.js @@ -2,10 +2,13 @@ import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; +import { AuthProvider } from './providers/Auth'; ReactDOM.render( - + + + , document.getElementById('root'), ); From 934f7ea57da04d92977d186a2860d45120e809e2 Mon Sep 17 00:00:00 2001 From: Diego Lavayen Alarcon Date: Fri, 8 Apr 2022 20:21:20 +0100 Subject: [PATCH 3/7] feat: includes Header component, which will display either the login form or a log out button based on the currentUser stored in the context --- src/App.js | 3 ++- src/components/Header.js | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/components/Header.js diff --git a/src/App.js b/src/App.js index 3940c2d..5f9db66 100644 --- a/src/App.js +++ b/src/App.js @@ -1,6 +1,7 @@ import Loading from './components/Loading'; import Error from './components/Error'; import TaskList from './components/TaskList'; +import Header from './components/Header'; import { useFetch } from './hooks/useFetch'; @@ -19,7 +20,7 @@ const App = () => { return ( <> -

TODO List

+
{state === 'PENDING' && } {state === 'SUCCESS' && ( diff --git a/src/components/Header.js b/src/components/Header.js new file mode 100644 index 0000000..373837e --- /dev/null +++ b/src/components/Header.js @@ -0,0 +1,16 @@ +import SignIn from './SignIn'; +import SignOut from './SignOut'; + +import { useAuth } from '../providers/Auth'; + +const Header = () => { + const { currentUser } = useAuth(); + return ( +
+

TODO List

+ {currentUser ? : } +
+ ); +}; + +export default Header; From 2f61601f62d072e1e74b1b78429fb9517562c88e Mon Sep 17 00:00:00 2001 From: Diego Lavayen Alarcon Date: Fri, 8 Apr 2022 20:21:46 +0100 Subject: [PATCH 4/7] feat: implements log out button, calling signOut function defined in the context --- src/components/SignOut.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/components/SignOut.js diff --git a/src/components/SignOut.js b/src/components/SignOut.js new file mode 100644 index 0000000..90617ff --- /dev/null +++ b/src/components/SignOut.js @@ -0,0 +1,13 @@ +import { useAuth } from '../providers/Auth'; + +const SignOut = () => { + const { signOut } = useAuth(); + + const handleButtonClick = () => { + signOut(); + }; + + return ; +}; + +export default SignOut; From f2eef20dc6d1ea860efe785062de770726015dbd Mon Sep 17 00:00:00 2001 From: Diego Lavayen Alarcon Date: Fri, 8 Apr 2022 20:23:16 +0100 Subject: [PATCH 5/7] feat: implements log in form, using the signIn function defined in the context and also using the custom hook `useInput` Also implements a simple error handling --- src/components/SignIn.js | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/components/SignIn.js diff --git a/src/components/SignIn.js b/src/components/SignIn.js new file mode 100644 index 0000000..759d334 --- /dev/null +++ b/src/components/SignIn.js @@ -0,0 +1,52 @@ +import { useState } from 'react'; + +import { useInput } from '../hooks/useInput'; +import { useAuth } from '../providers/Auth'; + +const SignIn = () => { + const { signIn } = useAuth(); + const [error, setError] = useState(); + const [{ username, password }, update, reset] = useInput({ + username: '', + password: '', + }); + + const handleInputChange = (event) => { + update(event); + }; + + const handleSubmit = (event) => { + event.preventDefault(); + const signedIn = signIn(username, password); + + if (signedIn) { + setError(undefined); + reset(); + } else { + setError('user or password incorrect'); + } + }; + + return ( +
+ + + + {error &&

{error}

} +
+ ); +}; + +export default SignIn; From 1fdd2db8cb1e577e4871d723194e5fb8bdd8832c Mon Sep 17 00:00:00 2001 From: Diego Lavayen Alarcon Date: Fri, 8 Apr 2022 20:23:49 +0100 Subject: [PATCH 6/7] feat: when url is not defined, requestState is set to INITIAL and requestResponse as undefined --- src/hooks/useFetch.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hooks/useFetch.js b/src/hooks/useFetch.js index 06010f0..cb79f5f 100644 --- a/src/hooks/useFetch.js +++ b/src/hooks/useFetch.js @@ -6,6 +6,8 @@ export const useFetch = (url) => { useEffect(() => { if (!url) { + setRequestState('INITIAL'); + setRequestResponse(undefined); return; } From 6e082ac2ff883361d18554e023c52a3fd7e88596 Mon Sep 17 00:00:00 2001 From: Diego Lavayen Alarcon Date: Fri, 8 Apr 2022 20:24:28 +0100 Subject: [PATCH 7/7] feat: construct request URL based on the authenticated user --- src/App.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/App.js b/src/App.js index 5f9db66..8de6da0 100644 --- a/src/App.js +++ b/src/App.js @@ -1,14 +1,26 @@ +import { useState, useEffect } from 'react'; + import Loading from './components/Loading'; import Error from './components/Error'; import TaskList from './components/TaskList'; import Header from './components/Header'; import { useFetch } from './hooks/useFetch'; +import { useAuth } from './providers/Auth'; const App = () => { - const [state, tasks, update, add] = useFetch( - process.env.REACT_APP_API_ENDPOINT, - ); + const { currentUser } = useAuth(); + const [url, setUrl] = useState(); + const [state, tasks, update, add] = useFetch(url); + + useEffect(() => { + if (!currentUser) { + setUrl(undefined); + return; + } + + setUrl(`${process.env.REACT_APP_API_ENDPOINT}?userId=${currentUser}`); + }, [currentUser]); const updateTask = (task) => { update(task.id, task);