From 9001fa56d47582f4e76785d0ac6965c6afda9b84 Mon Sep 17 00:00:00 2001 From: Nathan King Date: Fri, 12 Jul 2024 10:08:18 +0100 Subject: [PATCH 01/78] update readme --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 60494ec4..bd6a39c5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,3 @@ -### Team Dev Client - -Client repository for team dev project. - ### Set up 1. Copy the `.env.example` file to a new file named `.env` (NOTE: Make sure to copy the file, don't remove the original .env.example) @@ -11,8 +7,8 @@ Client repository for team dev project. ### Project Management -https://github.com/orgs/boolean-uk/projects/10/views/1 +https://github.com/orgs/boolean-uk/projects/13/views/1 ### Contributing -- Pull requests should be made from branches following the naming convention: `--`, e.g. `vherus-#1-user_registration` +- Pull requests MUST be made from branches following the naming convention: `--`, e.g. `vherus-#1-user_registration` \ No newline at end of file From 5387d5a52a43806ce826a51dd34376460b891643 Mon Sep 17 00:00:00 2001 From: Hamada Abdelaal Date: Tue, 16 Jul 2024 14:13:48 +0200 Subject: [PATCH 02/78] add line space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd6a39c5..dba8de8b 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,4 @@ https://github.com/orgs/boolean-uk/projects/13/views/1 ### Contributing -- Pull requests MUST be made from branches following the naming convention: `--`, e.g. `vherus-#1-user_registration` \ No newline at end of file +- Pull requests MUST be made from branches following the naming convention: `--`, e.g. `vherus-#1-user_registration` From 89585e7114d2d4fd83740dc21535981406504b42 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Wed, 17 Jul 2024 11:36:03 +0200 Subject: [PATCH 03/78] change step 2 to step 4 --- src/pages/welcome/index.js | 2 ++ src/pages/welcome/stepFour/index.js | 19 +++++++++++++++++++ src/pages/welcome/stepTwo/index.js | 10 +--------- 3 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 src/pages/welcome/stepFour/index.js diff --git a/src/pages/welcome/index.js b/src/pages/welcome/index.js index 8df35b81..58c8dca6 100644 --- a/src/pages/welcome/index.js +++ b/src/pages/welcome/index.js @@ -3,6 +3,7 @@ import Stepper from "../../components/stepper"; import useAuth from "../../hooks/useAuth"; import StepOne from "./stepOne"; import StepTwo from "./stepTwo"; +import StepFour from "./stepFour"; import "./style.css"; const Welcome = () => { @@ -38,6 +39,7 @@ const Welcome = () => { } onComplete={onComplete}> + ); diff --git a/src/pages/welcome/stepFour/index.js b/src/pages/welcome/stepFour/index.js new file mode 100644 index 00000000..331a55de --- /dev/null +++ b/src/pages/welcome/stepFour/index.js @@ -0,0 +1,19 @@ +import Form from "../../../components/form" + +const StepFour = ({ data, setData }) => { + return ( + <> +
+

Bio

+
+
+
+ +

*Required

+
+
+ + ) +} + +export default StepFour \ No newline at end of file diff --git a/src/pages/welcome/stepTwo/index.js b/src/pages/welcome/stepTwo/index.js index ad695688..967785af 100644 --- a/src/pages/welcome/stepTwo/index.js +++ b/src/pages/welcome/stepTwo/index.js @@ -3,15 +3,7 @@ import Form from "../../../components/form" const StepTwo = ({ data, setData }) => { return ( <> -
-

Bio

-
-
-
- -

*Required

-
-
+ ) } From 5fd78501a32bc833493d89d00512ae83440ec895 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Wed, 17 Jul 2024 11:52:48 +0200 Subject: [PATCH 04/78] add step 2 form --- src/components/form/textInput/index.js | 2 +- src/pages/welcome/index.js | 5 ++++- src/pages/welcome/stepTwo/index.js | 18 +++++++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/components/form/textInput/index.js b/src/components/form/textInput/index.js index 4d8507d5..bfce4ce5 100644 --- a/src/components/form/textInput/index.js +++ b/src/components/form/textInput/index.js @@ -1,6 +1,6 @@ import { useState } from "react"; -const TextInput = ({ value, onChange, name, label, icon, type = "text" }) => { +const TextInput = ({ value, onChange, name, label, icon, type = "text"}) => { const [input, setInput] = useState(""); const [showpassword, setShowpassword] = useState(false); if (type === "password") { diff --git a/src/pages/welcome/index.js b/src/pages/welcome/index.js index 58c8dca6..9f1c998d 100644 --- a/src/pages/welcome/index.js +++ b/src/pages/welcome/index.js @@ -14,6 +14,9 @@ const Welcome = () => { lastName: "", githubUsername: "", bio: "", + email: "", + mobile: "", + password: "" }); const onChange = (event) => { @@ -26,7 +29,7 @@ const Welcome = () => { }; const onComplete = () => { - onCreateProfile(profile.firstName, profile.lastName, profile.githubUsername, profile.bio); + onCreateProfile(profile.firstName, profile.lastName, profile.githubUsername, profile.bio, profile.email, profile.mobile, profile.password); }; return ( diff --git a/src/pages/welcome/stepTwo/index.js b/src/pages/welcome/stepTwo/index.js index 967785af..fc907c1b 100644 --- a/src/pages/welcome/stepTwo/index.js +++ b/src/pages/welcome/stepTwo/index.js @@ -1,9 +1,25 @@ import Form from "../../../components/form" +import TextInput from "../../../components/form/textInput" const StepTwo = ({ data, setData }) => { return ( <> - +
+

Contact info

+
+
+
+ + + +

*Required

+
+
) } From 6cc68c8574f8f31b904078f61142140c96e1d943 Mon Sep 17 00:00:00 2001 From: Hamada Abdelaal Date: Wed, 17 Jul 2024 14:16:06 +0200 Subject: [PATCH 05/78] handle login error messages --- src/components/form/textInput/index.js | 125 +++++++++++++----------- src/context/auth.js | 129 +++++++++++++------------ src/pages/login/index.js | 81 ++++++++-------- src/service/apiClient.js | 60 ++++++------ src/styles/_form.css | 69 +++++++------ 5 files changed, 241 insertions(+), 223 deletions(-) diff --git a/src/components/form/textInput/index.js b/src/components/form/textInput/index.js index 4d8507d5..7298b648 100644 --- a/src/components/form/textInput/index.js +++ b/src/components/form/textInput/index.js @@ -1,68 +1,75 @@ import { useState } from "react"; const TextInput = ({ value, onChange, name, label, icon, type = "text" }) => { - const [input, setInput] = useState(""); - const [showpassword, setShowpassword] = useState(false); - if (type === "password") { - return ( -
- - { - onChange(e); - setInput(e.target.value); - }} - /> - {showpassword && ( - - )} - -
- ); - } else { - return ( -
- {label && } - - {icon && {icon}} -
- ); - } + const [input, setInput] = useState(""); + const [showpassword, setShowpassword] = useState(false); + if (type === "password") { + return ( +
+ + { + onChange(e); + setInput(e.target.value); + }} + /> + {showpassword && ( + + )} + + +
+ ); + } else { + return ( +
+ {label && } + + {icon && {icon}} +
+ ); + } }; const EyeLogo = () => { - return ( - - - - ); + return ( + + + + ); }; export default TextInput; diff --git a/src/context/auth.js b/src/context/auth.js index a7b9462d..b44630dd 100644 --- a/src/context/auth.js +++ b/src/context/auth.js @@ -5,85 +5,90 @@ import Modal from "../components/modal"; import Navigation from "../components/navigation"; import useAuth from "../hooks/useAuth"; import { createProfile, login, register } from "../service/apiClient"; -import jwt_decode from "jwt-decode" +import jwt_decode from "jwt-decode"; -const AuthContext = createContext() +const AuthContext = createContext(); const AuthProvider = ({ children }) => { - const navigate = useNavigate() - const location = useLocation() - const [token, setToken] = useState(null) + const navigate = useNavigate(); + const location = useLocation(); + const [token, setToken] = useState(null); + const [error, setError] = useState(""); - useEffect(() => { - const storedToken = localStorage.getItem('token') + useEffect(() => { + const storedToken = localStorage.getItem("token"); - if (storedToken) { - setToken(storedToken) - navigate(location.state?.from?.pathname || "/") - } - }, [location.state?.from?.pathname, navigate]) + if (storedToken) { + setToken(storedToken); + navigate(location.state?.from?.pathname || "/"); + } + }, [location.state?.from?.pathname, navigate]); - const handleLogin = async (email, password) => { - const res = await login(email, password) + const handleLogin = async (email, password) => { + const res = await login(email, password); - if (!res.data.token) { - return navigate("/login") - } + if (res.data.error) { + setError(res.data.error); + } - localStorage.setItem('token', res.data.token) + if (!res.data.token) { + return navigate("/login"); + } - setToken(res.token) - navigate(location.state?.from?.pathname || "/") - }; + localStorage.setItem("token", res.data.token); - const handleLogout = () => { - localStorage.removeItem('token') - setToken(null) - }; + setToken(res.data.token); + navigate(location.state?.from?.pathname || "/"); + }; - const handleRegister = async (email, password) => { - const res = await register(email, password) - setToken(res.data.token) + const handleLogout = () => { + localStorage.removeItem("token"); + setToken(null); + }; - navigate("/verification") - } + const handleRegister = async (email, password) => { + const res = await register(email, password); + setToken(res.data.token); + navigate("/verification"); + }; - const handleCreateProfile = async (firstName, lastName, githubUrl, bio) => { - const { userId } = jwt_decode(token) + const handleCreateProfile = async (firstName, lastName, githubUrl, bio) => { + const { userId } = jwt_decode(token); - await createProfile(userId, firstName, lastName, githubUrl, bio) + await createProfile(userId, firstName, lastName, githubUrl, bio); - localStorage.setItem('token', token) - navigate('/') - } + localStorage.setItem("token", token); // Isn't it redundant, as the token is already stored in localStorage during login or registration? + navigate("/"); + }; - const value = { - token, - onLogin: handleLogin, - onLogout: handleLogout, - onRegister: handleRegister, - onCreateProfile: handleCreateProfile - }; + const value = { + token, + onLogin: handleLogin, + onLogout: handleLogout, + onRegister: handleRegister, + onCreateProfile: handleCreateProfile, + error: error, + }; - return {children} + return {children}; }; const ProtectedRoute = ({ children }) => { - const { token } = useAuth() - const location = useLocation() - - if (!token) { - return - } - - return ( -
-
- - - {children} -
- ) -} - -export { AuthContext, AuthProvider, ProtectedRoute } + const { token } = useAuth(); + const location = useLocation(); + + if (!token) { + return ; + } + + return ( +
+
+ + + {children} +
+ ); +}; + +export { AuthContext, AuthProvider, ProtectedRoute }; diff --git a/src/pages/login/index.js b/src/pages/login/index.js index 60566866..a0214822 100644 --- a/src/pages/login/index.js +++ b/src/pages/login/index.js @@ -6,48 +6,49 @@ import CredentialsCard from "../../components/credentials"; import "./login.css"; const Login = () => { - const { onLogin } = useAuth(); - const [formData, setFormData] = useState({ email: "", password: "" }); + const { onLogin, error } = useAuth(); + const [formData, setFormData] = useState({ email: "", password: "" }); - const onChange = (e) => { - const { name, value } = e.target; - setFormData({ ...formData, [name]: value }); - }; + const onChange = (e) => { + const { name, value } = e.target; + setFormData({ ...formData, [name]: value }); + }; - return ( -
- -
-
- - - -
-
-
- ); + return ( +
+ +
+
+ + + +

{error}

+
+
+
+ ); }; export default Login; diff --git a/src/service/apiClient.js b/src/service/apiClient.js index ae4d87cf..50c7e0be 100644 --- a/src/service/apiClient.js +++ b/src/service/apiClient.js @@ -1,59 +1,59 @@ -import { API_URL } from "./constants" +import { API_URL } from "./constants"; async function login(email, password) { - return await post('login', { email, password }, false) + return await post("login", { email, password }, false); } async function register(email, password) { - await post('users', { email, password }, false) - return await login(email, password) + await post("users", { email, password }, false); + return await login(email, password); } async function createProfile(userId, firstName, lastName, githubUrl, bio) { - return await patch(`users/${userId}`, { firstName, lastName, githubUrl, bio }) + return await patch(`users/${userId}`, { + firstName, + lastName, + githubUrl, + bio, + }); } async function getPosts() { - const res = await get('posts') - return res.data.posts + const res = await get("posts"); + return res.data.posts; } async function post(endpoint, data, auth = true) { - return await request('POST', endpoint, data, auth) + return await request("POST", endpoint, data, auth); } async function patch(endpoint, data, auth = true) { - return await request('PATCH', endpoint, data, auth) + return await request("PATCH", endpoint, data, auth); } async function get(endpoint, auth = true) { - return await request('GET', endpoint, null, auth) + return await request("GET", endpoint, null, auth); } async function request(method, endpoint, data, auth = true) { - const opts = { - headers: { - 'Content-Type': 'application/json' - }, - method - } + const opts = { + headers: { + "Content-Type": "application/json", + }, + method, + }; - if (method.toUpperCase() !== 'GET') { - opts.body = JSON.stringify(data) - } + if (method.toUpperCase() !== "GET") { + opts.body = JSON.stringify(data); + } - if (auth) { - opts.headers['Authorization'] = `Bearer ${localStorage.getItem('token')}` - } + if (auth) { + opts.headers["Authorization"] = `Bearer ${localStorage.getItem("token")}`; + } - const response = await fetch(`${API_URL}/${endpoint}`, opts) + const response = await fetch(`${API_URL}/${endpoint}`, opts); - return response.json() + return response.json(); } -export { - login, - getPosts, - register, - createProfile -} \ No newline at end of file +export { login, getPosts, register, createProfile }; diff --git a/src/styles/_form.css b/src/styles/_form.css index 40fc45d7..2a888c30 100644 --- a/src/styles/_form.css +++ b/src/styles/_form.css @@ -1,56 +1,61 @@ form input { - background: var(--color-blue5); - border: 1px solid transparent; - border-radius: 8px; - padding: 16px; - font-size: 18px; - line-height: 1.33; - width: 100%; + background: var(--color-blue5); + border: 1px solid transparent; + border-radius: 8px; + padding: 16px; + font-size: 18px; + line-height: 1.33; + width: 100%; } form input:focus { - border: 1px solid var(--color-blue2); + border: 1px solid var(--color-blue2); } form label { - color: var(--color-blue1); - line-height: 1.5; - margin-bottom: 2px; - padding-left: 15px; + color: var(--color-blue1); + line-height: 1.5; + margin-bottom: 2px; + padding-left: 15px; } .inputwrapper { - position: relative; + position: relative; } .input-icon { - position: absolute; - left: 16px; - padding-top: 15px; + position: absolute; + left: 16px; + padding-top: 15px; } .input-has-icon { - padding-left: 56px; - padding-right: 10px; + padding-left: 56px; + padding-right: 10px; } .showpasswordbutton { - position: absolute; - bottom: 28px; - right: 16px; - z-index: 2; - background: none; - transform: translateY(19px); - transition: all 0.2s ease; + position: absolute; + bottom: 28px; + right: 16px; + z-index: 2; + background: none; + transform: translateY(19px); + transition: all 0.2s ease; } .showpasswordbutton:hover { - opacity: 0.7; + opacity: 0.7; } .showpasswordbutton.__faded { - opacity: 0.4; + opacity: 0.4; } .passwordreveal { - position: absolute; - bottom: 0; - right: 0; - width: 100%; - z-index: 1; + position: absolute; + bottom: 0; + right: 0; + width: 100%; + z-index: 1; +} + +.error-message { + color: red; + margin-bottom: 10px; } From dd8d7c5371c2ba6024397119d83eaced8f9de325 Mon Sep 17 00:00:00 2001 From: Leonardo Lodi Date: Wed, 17 Jul 2024 13:28:09 +0100 Subject: [PATCH 06/78] add step 3 for create profile form --- src/App.css | 9 ++-- src/assets/icons/lockIcon.js | 12 +++++ src/components/form/textInput/index.js | 4 +- src/components/stepper/index.js | 2 +- src/pages/welcome/index.js | 2 + src/pages/welcome/stepThree/index.js | 61 ++++++++++++++++++++++++++ src/styles/_form.css | 4 +- 7 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 src/assets/icons/lockIcon.js create mode 100644 src/pages/welcome/stepThree/index.js diff --git a/src/App.css b/src/App.css index d8dd9fc4..800c59d8 100644 --- a/src/App.css +++ b/src/App.css @@ -3,11 +3,10 @@ } .container { - display: grid; - grid-template-columns: 151px 2fr 1fr; - grid-template-rows: 96px auto; - background-color: #F0F5FA; - height: 100vh; + display: grid; + grid-template-columns: 151px 2fr 1fr; + grid-template-rows: 96px auto; + background-color: #F0F5FA; } .ReactModal__Body--open, diff --git a/src/assets/icons/lockIcon.js b/src/assets/icons/lockIcon.js new file mode 100644 index 00000000..4ff58b63 --- /dev/null +++ b/src/assets/icons/lockIcon.js @@ -0,0 +1,12 @@ +const LockIcon = () => { + return ( + + + + ) +} + +export default LockIcon \ No newline at end of file diff --git a/src/components/form/textInput/index.js b/src/components/form/textInput/index.js index 4d8507d5..a405abb4 100644 --- a/src/components/form/textInput/index.js +++ b/src/components/form/textInput/index.js @@ -1,6 +1,6 @@ import { useState } from "react"; -const TextInput = ({ value, onChange, name, label, icon, type = "text" }) => { +const TextInput = ({ value, onChange, name, label, icon, type = "text", readOnly }) => { const [input, setInput] = useState(""); const [showpassword, setShowpassword] = useState(false); if (type === "password") { @@ -41,7 +41,7 @@ const TextInput = ({ value, onChange, name, label, icon, type = "text" }) => { return (
{label && } - + {icon && {icon}}
); diff --git a/src/components/stepper/index.js b/src/components/stepper/index.js index 36091af8..2a90c142 100644 --- a/src/components/stepper/index.js +++ b/src/components/stepper/index.js @@ -33,7 +33,7 @@ const Stepper = ({ header, children, onComplete }) => {
); diff --git a/src/pages/welcome/index.js b/src/pages/welcome/index.js index 8df35b81..452990ee 100644 --- a/src/pages/welcome/index.js +++ b/src/pages/welcome/index.js @@ -4,6 +4,7 @@ import useAuth from "../../hooks/useAuth"; import StepOne from "./stepOne"; import StepTwo from "./stepTwo"; import "./style.css"; +import StepThree from "./stepThree"; const Welcome = () => { const { onCreateProfile } = useAuth(); @@ -38,6 +39,7 @@ const Welcome = () => { } onComplete={onComplete}> + ); diff --git a/src/pages/welcome/stepThree/index.js b/src/pages/welcome/stepThree/index.js new file mode 100644 index 00000000..c0e270d9 --- /dev/null +++ b/src/pages/welcome/stepThree/index.js @@ -0,0 +1,61 @@ +import Form from "../../../components/form"; +import TextInput from "../../../components/form/textInput"; +import LockIcon from "../../../assets/icons/lockIcon"; + +const StepThree = ({ data }) => { + return ( + <> +
+

Training info

+
+ +
+
+ } + /> + + } + /> + + } + /> + + } + /> + + } + /> + +

*Required

+
+
+ + ); +}; + +export default StepThree; diff --git a/src/styles/_form.css b/src/styles/_form.css index 40fc45d7..071fae9d 100644 --- a/src/styles/_form.css +++ b/src/styles/_form.css @@ -23,8 +23,8 @@ form label { .input-icon { position: absolute; - left: 16px; - padding-top: 15px; + right: 16px; + padding-top: 8px; } .input-has-icon { padding-left: 56px; From 0f85b67bd95b9db95a02da92fd5214386b5ee187 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Wed, 17 Jul 2024 15:49:25 +0200 Subject: [PATCH 07/78] add * for required fields --- src/pages/welcome/stepTwo/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/welcome/stepTwo/index.js b/src/pages/welcome/stepTwo/index.js index fc907c1b..4fe8ed54 100644 --- a/src/pages/welcome/stepTwo/index.js +++ b/src/pages/welcome/stepTwo/index.js @@ -9,13 +9,13 @@ const StepTwo = ({ data, setData }) => {
- +

*Required

From d2b7307566d7150b03a468ea85bd2a4e8186c5e6 Mon Sep 17 00:00:00 2001 From: Leonardo Lodi Date: Wed, 17 Jul 2024 15:26:53 +0100 Subject: [PATCH 08/78] fix: add default value to readOnly and variable for the ternary Button component text --- src/components/form/textInput/index.js | 4 ++-- src/components/stepper/index.js | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/form/textInput/index.js b/src/components/form/textInput/index.js index a405abb4..74bd1e83 100644 --- a/src/components/form/textInput/index.js +++ b/src/components/form/textInput/index.js @@ -1,6 +1,6 @@ import { useState } from "react"; -const TextInput = ({ value, onChange, name, label, icon, type = "text", readOnly }) => { +const TextInput = ({ value, onChange, name, label, icon, type = "text", readOnly = false }) => { const [input, setInput] = useState(""); const [showpassword, setShowpassword] = useState(false); if (type === "password") { @@ -41,7 +41,7 @@ const TextInput = ({ value, onChange, name, label, icon, type = "text", readOnly return (
{label && } - + {icon && {icon}}
); diff --git a/src/components/stepper/index.js b/src/components/stepper/index.js index 2a90c142..b13256a5 100644 --- a/src/components/stepper/index.js +++ b/src/components/stepper/index.js @@ -22,6 +22,8 @@ const Stepper = ({ header, children, onComplete }) => { setCurrentStep(currentStep+1) } + const btnText = currentStep === children.length-1 ? 'Create profile' : 'Next' + return ( {header} @@ -33,7 +35,7 @@ const Stepper = ({ header, children, onComplete }) => {
); From 4e704b4460b55aa31370014f2ce8c9609433ddba Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Wed, 17 Jul 2024 16:47:50 +0200 Subject: [PATCH 09/78] edit stepper order --- src/pages/welcome/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/welcome/index.js b/src/pages/welcome/index.js index 7d6cddda..0143affd 100644 --- a/src/pages/welcome/index.js +++ b/src/pages/welcome/index.js @@ -43,8 +43,8 @@ const Welcome = () => { } onComplete={onComplete}> - + ); From 2f933f47839c0d6142d662c5903afdef2a5e3254 Mon Sep 17 00:00:00 2001 From: Hamada Abdelaal Date: Wed, 17 Jul 2024 19:06:16 +0200 Subject: [PATCH 10/78] handle registration error messages-c --- src/components/credentials/index.js | 63 +++++++++++---------- src/context/auth.js | 12 +++- src/pages/login/index.js | 5 +- src/pages/register/index.js | 85 +++++++++++++++-------------- src/service/apiClient.js | 4 +- 5 files changed, 94 insertions(+), 75 deletions(-) diff --git a/src/components/credentials/index.js b/src/components/credentials/index.js index 0e43e202..8197b325 100644 --- a/src/components/credentials/index.js +++ b/src/components/credentials/index.js @@ -5,36 +5,41 @@ import "./credentials.css"; import Card from "../card"; const CredentialsCard = ({ - title, - socialLinksTitle, - altButtonTitle, - altButtonLink, - altButtonText, - children, + title, + socialLinksTitle, + altButtonTitle, + altButtonLink, + altButtonText, + setError, + children, }) => { - return ( -
- -
- -
-

{title && title}

- {children} -
-

{socialLinksTitle && socialLinksTitle}

-
- -
-
-
-

{altButtonTitle && altButtonTitle}

- - {altButtonText} - -
-
-
- ); + return ( +
+ +
+ +
+

{title && title}

+ {children} +
+

{socialLinksTitle && socialLinksTitle}

+
+ +
+
+
+

{altButtonTitle && altButtonTitle}

+ setError("")} + > + {altButtonText} + +
+
+
+ ); }; export default CredentialsCard; diff --git a/src/context/auth.js b/src/context/auth.js index b44630dd..44f05373 100644 --- a/src/context/auth.js +++ b/src/context/auth.js @@ -39,17 +39,24 @@ const AuthProvider = ({ children }) => { setToken(res.data.token); navigate(location.state?.from?.pathname || "/"); + setError(""); }; const handleLogout = () => { localStorage.removeItem("token"); setToken(null); + setError(""); }; const handleRegister = async (email, password) => { const res = await register(email, password); - setToken(res.data.token); - navigate("/verification"); + if (res.data.error) { + setError(res.data.error); + } else { + setToken(res.data.token); + navigate("/verification"); + setError(""); + } }; const handleCreateProfile = async (firstName, lastName, githubUrl, bio) => { @@ -68,6 +75,7 @@ const AuthProvider = ({ children }) => { onRegister: handleRegister, onCreateProfile: handleCreateProfile, error: error, + setError: setError, }; return {children}; diff --git a/src/pages/login/index.js b/src/pages/login/index.js index a0214822..31bbcad8 100644 --- a/src/pages/login/index.js +++ b/src/pages/login/index.js @@ -6,7 +6,7 @@ import CredentialsCard from "../../components/credentials"; import "./login.css"; const Login = () => { - const { onLogin, error } = useAuth(); + const { onLogin, error, setError } = useAuth(); const [formData, setFormData] = useState({ email: "", password: "" }); const onChange = (e) => { @@ -22,6 +22,7 @@ const Login = () => { altButtonTitle="Need an account?" altButtonLink="/register" altButtonText="Sign up" + setError={setError} >
@@ -39,7 +40,7 @@ const Login = () => { type={"password"} /> -

{error}

+ {error &&

{error}

}
- - - ); + return ( +
+ +
+
+ + + +

{error}

+
+
+
+ ); }; export default Register; diff --git a/src/service/apiClient.js b/src/service/apiClient.js index 50c7e0be..ba9b6a98 100644 --- a/src/service/apiClient.js +++ b/src/service/apiClient.js @@ -5,7 +5,9 @@ async function login(email, password) { } async function register(email, password) { - await post("users", { email, password }, false); + const res = await post("users", { email, password }, false); + + if (res.data.error) return res; return await login(email, password); } From f7a4251e6883df03e842cf57fb1c23f4ccb72960 Mon Sep 17 00:00:00 2001 From: Hamada Abdelaal Date: Thu, 18 Jul 2024 13:06:49 +0200 Subject: [PATCH 11/78] remove comments/ use {} --- src/context/auth.js | 2 +- src/service/apiClient.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/context/auth.js b/src/context/auth.js index 44f05373..f8b3857a 100644 --- a/src/context/auth.js +++ b/src/context/auth.js @@ -64,7 +64,7 @@ const AuthProvider = ({ children }) => { await createProfile(userId, firstName, lastName, githubUrl, bio); - localStorage.setItem("token", token); // Isn't it redundant, as the token is already stored in localStorage during login or registration? + localStorage.setItem("token", token); navigate("/"); }; diff --git a/src/service/apiClient.js b/src/service/apiClient.js index ba9b6a98..8f9f6c50 100644 --- a/src/service/apiClient.js +++ b/src/service/apiClient.js @@ -7,7 +7,9 @@ async function login(email, password) { async function register(email, password) { const res = await post("users", { email, password }, false); - if (res.data.error) return res; + if (res.data.error) { + return res; + } return await login(email, password); } From 803e730c201c77166f607662d0f53b59124a2f14 Mon Sep 17 00:00:00 2001 From: Hamada Abdelaal Date: Thu, 18 Jul 2024 14:21:39 +0200 Subject: [PATCH 12/78] resolve conflict --- src/components/form/textInput/index.js | 61 +++++--------------------- src/styles/_form.css | 9 +--- 2 files changed, 12 insertions(+), 58 deletions(-) diff --git a/src/components/form/textInput/index.js b/src/components/form/textInput/index.js index a31e80f6..92780b33 100644 --- a/src/components/form/textInput/index.js +++ b/src/components/form/textInput/index.js @@ -1,7 +1,14 @@ import { useState } from "react"; -<<<<<<< HEAD -const TextInput = ({ value, onChange, name, label, icon, type = "text" }) => { +const TextInput = ({ + value, + onChange, + name, + label, + icon, + type = "text", + readOnly = false, +}) => { const [input, setInput] = useState(""); const [showpassword, setShowpassword] = useState(false); if (type === "password") { @@ -25,7 +32,6 @@ const TextInput = ({ value, onChange, name, label, icon, type = "text" }) => { className="passwordreveal" /> )} - - - ); - } else { - return ( -
- {label && } - - {icon && {icon}} -
- ); - } ->>>>>>> main }; const EyeLogo = () => { diff --git a/src/styles/_form.css b/src/styles/_form.css index 5bc054c2..d0e3af1a 100644 --- a/src/styles/_form.css +++ b/src/styles/_form.css @@ -22,16 +22,11 @@ form label { } .input-icon { -<<<<<<< HEAD position: absolute; left: 16px; - padding-top: 15px; -======= - position: absolute; - right: 16px; - padding-top: 8px; ->>>>>>> main + padding-top: 8px; } + .input-has-icon { padding-left: 56px; padding-right: 10px; From 8ea78d4ea1eafc5994ff9a5c589e44a6b762a396 Mon Sep 17 00:00:00 2001 From: Leonardo Lodi Date: Thu, 18 Jul 2024 14:07:12 +0100 Subject: [PATCH 13/78] fix: step 2 from create profile and improve token logic --- src/context/auth.js | 7 ++++--- src/pages/welcome/index.js | 7 +++---- src/pages/welcome/stepOne/index.js | 5 +++-- src/pages/welcome/stepTwo/index.js | 8 -------- src/service/apiClient.js | 4 ++-- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/context/auth.js b/src/context/auth.js index a7b9462d..b2593696 100644 --- a/src/context/auth.js +++ b/src/context/auth.js @@ -48,12 +48,13 @@ const AuthProvider = ({ children }) => { navigate("/verification") } - const handleCreateProfile = async (firstName, lastName, githubUrl, bio) => { + const handleCreateProfile = async (firstName, lastName, username, githubUrl, mobile, bio) => { const { userId } = jwt_decode(token) - await createProfile(userId, firstName, lastName, githubUrl, bio) + localStorage.setItem('token', token) + + await createProfile(userId, firstName, lastName, username, githubUrl, mobile, bio) - localStorage.setItem('token', token) navigate('/') } diff --git a/src/pages/welcome/index.js b/src/pages/welcome/index.js index 0143affd..fe0fd4a9 100644 --- a/src/pages/welcome/index.js +++ b/src/pages/welcome/index.js @@ -13,11 +13,10 @@ const Welcome = () => { const [profile, setProfile] = useState({ firstName: "", lastName: "", + username: "", githubUsername: "", bio: "", - email: "", - mobile: "", - password: "" + mobile: "" }); const onChange = (event) => { @@ -30,7 +29,7 @@ const Welcome = () => { }; const onComplete = () => { - onCreateProfile(profile.firstName, profile.lastName, profile.githubUsername, profile.bio, profile.email, profile.mobile, profile.password); + onCreateProfile(profile.firstName, profile.lastName, profile.username, profile.githubUsername, profile.bio, profile.mobile); }; return ( diff --git a/src/pages/welcome/stepOne/index.js b/src/pages/welcome/stepOne/index.js index edf11e95..3e488a8a 100644 --- a/src/pages/welcome/stepOne/index.js +++ b/src/pages/welcome/stepOne/index.js @@ -20,8 +20,9 @@ const StepOne = ({ data, setData }) => {

- - + + + {
- - -

*Required

diff --git a/src/service/apiClient.js b/src/service/apiClient.js index ae4d87cf..59f8ce9e 100644 --- a/src/service/apiClient.js +++ b/src/service/apiClient.js @@ -9,8 +9,8 @@ async function register(email, password) { return await login(email, password) } -async function createProfile(userId, firstName, lastName, githubUrl, bio) { - return await patch(`users/${userId}`, { firstName, lastName, githubUrl, bio }) +async function createProfile(userId, firstName, lastName, username, githubUrl, mobile, bio) { + return await patch(`users/${userId}`, { firstName, lastName, username, githubUrl, mobile, bio }) } async function getPosts() { From 2d64fa72bfa40d8f2032b755d02096d902820e30 Mon Sep 17 00:00:00 2001 From: Leonardo Lodi Date: Thu, 18 Jul 2024 14:23:22 +0100 Subject: [PATCH 14/78] style: formatting changes --- src/context/auth.js | 161 ++++++++++++++++++++++++-------------------- 1 file changed, 88 insertions(+), 73 deletions(-) diff --git a/src/context/auth.js b/src/context/auth.js index b2593696..a5241b4b 100644 --- a/src/context/auth.js +++ b/src/context/auth.js @@ -1,90 +1,105 @@ -import { createContext, useEffect, useState } from "react"; -import { useNavigate, useLocation, Navigate } from "react-router-dom"; -import Header from "../components/header"; -import Modal from "../components/modal"; -import Navigation from "../components/navigation"; -import useAuth from "../hooks/useAuth"; -import { createProfile, login, register } from "../service/apiClient"; +import { createContext, useEffect, useState } from "react" +import { useNavigate, useLocation, Navigate } from "react-router-dom" +import Header from "../components/header" +import Modal from "../components/modal" +import Navigation from "../components/navigation" +import useAuth from "../hooks/useAuth" +import { createProfile, login, register } from "../service/apiClient" import jwt_decode from "jwt-decode" const AuthContext = createContext() const AuthProvider = ({ children }) => { - const navigate = useNavigate() - const location = useLocation() - const [token, setToken] = useState(null) + const navigate = useNavigate() + const location = useLocation() + const [token, setToken] = useState(null) - useEffect(() => { - const storedToken = localStorage.getItem('token') + useEffect(() => { + const storedToken = localStorage.getItem("token") - if (storedToken) { - setToken(storedToken) - navigate(location.state?.from?.pathname || "/") - } - }, [location.state?.from?.pathname, navigate]) - - const handleLogin = async (email, password) => { - const res = await login(email, password) - - if (!res.data.token) { - return navigate("/login") - } - - localStorage.setItem('token', res.data.token) - - setToken(res.token) - navigate(location.state?.from?.pathname || "/") - }; - - const handleLogout = () => { - localStorage.removeItem('token') - setToken(null) - }; - - const handleRegister = async (email, password) => { - const res = await register(email, password) - setToken(res.data.token) - - navigate("/verification") + if (storedToken) { + setToken(storedToken) + navigate(location.state?.from?.pathname || "/") } + }, [location.state?.from?.pathname, navigate]) - const handleCreateProfile = async (firstName, lastName, username, githubUrl, mobile, bio) => { - const { userId } = jwt_decode(token) - - localStorage.setItem('token', token) - - await createProfile(userId, firstName, lastName, username, githubUrl, mobile, bio) + const handleLogin = async (email, password) => { + const res = await login(email, password) - navigate('/') + if (!res.data.token) { + return navigate("/login") } - const value = { - token, - onLogin: handleLogin, - onLogout: handleLogout, - onRegister: handleRegister, - onCreateProfile: handleCreateProfile - }; - - return {children} -}; + localStorage.setItem("token", res.data.token) + + setToken(res.token) + navigate(location.state?.from?.pathname || "/") + } + + const handleLogout = () => { + localStorage.removeItem("token") + setToken(null) + } + + const handleRegister = async (email, password) => { + const res = await register(email, password) + setToken(res.data.token) + + navigate("/verification") + } + + const handleCreateProfile = async ( + firstName, + lastName, + username, + githubUrl, + mobile, + bio + ) => { + const { userId } = jwt_decode(token) + + localStorage.setItem("token", token) + + await createProfile( + userId, + firstName, + lastName, + username, + githubUrl, + mobile, + bio + ) + + navigate("/") + } + + const value = { + token, + onLogin: handleLogin, + onLogout: handleLogout, + onRegister: handleRegister, + onCreateProfile: handleCreateProfile, + } + + return {children} +} const ProtectedRoute = ({ children }) => { - const { token } = useAuth() - const location = useLocation() - - if (!token) { - return - } - - return ( -
-
- - - {children} -
- ) + const { token } = useAuth() + const location = useLocation() + + if (!token) { + return + } + + return ( +
+
+ + + {children} +
+ ) } export { AuthContext, AuthProvider, ProtectedRoute } From 2c19a248020c454706792f18bd292e9810e126fa Mon Sep 17 00:00:00 2001 From: Leonardo Lodi Date: Thu, 18 Jul 2024 17:04:08 +0100 Subject: [PATCH 15/78] fix: required first and last names at create profile and remove back btn from step one --- src/components/form/textInput/index.js | 6 ++++-- src/components/stepper/index.js | 14 +++++++++++--- src/components/stepper/style.css | 21 ++++++++++++++++----- src/pages/welcome/index.js | 2 +- src/pages/welcome/stepOne/index.js | 4 ++-- 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/components/form/textInput/index.js b/src/components/form/textInput/index.js index 74bd1e83..c7f484f9 100644 --- a/src/components/form/textInput/index.js +++ b/src/components/form/textInput/index.js @@ -1,8 +1,10 @@ import { useState } from "react"; -const TextInput = ({ value, onChange, name, label, icon, type = "text", readOnly = false }) => { +const TextInput = ({ value, onChange, name, label, icon, type = "text", readOnly = false, required = false }) => { const [input, setInput] = useState(""); const [showpassword, setShowpassword] = useState(false); + const inputHasIcon = icon ? "input-has-icon" : "" + if (type === "password") { return (
@@ -41,7 +43,7 @@ const TextInput = ({ value, onChange, name, label, icon, type = "text", readOnly return (
{label && } - + {icon && {icon}}
); diff --git a/src/components/stepper/index.js b/src/components/stepper/index.js index b13256a5..398030c4 100644 --- a/src/components/stepper/index.js +++ b/src/components/stepper/index.js @@ -4,7 +4,7 @@ import Button from "../button"; import "./style.css"; import { useState } from "react"; -const Stepper = ({ header, children, onComplete }) => { +const Stepper = ({ header, children, onComplete, data }) => { const [currentStep, setCurrentStep] = useState(0) const onBackClick = () => { @@ -14,6 +14,10 @@ const Stepper = ({ header, children, onComplete }) => { } const onNextClick = () => { + if (data.firstName.length === 0 || data.lastName.length === 0) { + return + } + if (currentStep === children.length-1) { onComplete() return @@ -34,8 +38,12 @@ const Stepper = ({ header, children, onComplete }) => { {children[currentStep]}
-
); diff --git a/src/components/stepper/style.css b/src/components/stepper/style.css index ab403c21..df119c64 100644 --- a/src/components/stepper/style.css +++ b/src/components/stepper/style.css @@ -1,9 +1,20 @@ .stepper-buttons { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 20px; - justify-content: space-between; + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-areas: "back next"; + gap: 20px; + justify-content: space-between; } .stepper-buttons button:nth-of-type(2) { - justify-self: end; + justify-self: end; } + +.back { + grid-area: back; +} + +.next { + grid-area: next; + display: grid; + justify-items: right; +} \ No newline at end of file diff --git a/src/pages/welcome/index.js b/src/pages/welcome/index.js index fe0fd4a9..888e42f7 100644 --- a/src/pages/welcome/index.js +++ b/src/pages/welcome/index.js @@ -39,7 +39,7 @@ const Welcome = () => {

Create your profile to get started

- } onComplete={onComplete}> + } onComplete={onComplete} data={profile}> diff --git a/src/pages/welcome/stepOne/index.js b/src/pages/welcome/stepOne/index.js index 3e488a8a..c63480bc 100644 --- a/src/pages/welcome/stepOne/index.js +++ b/src/pages/welcome/stepOne/index.js @@ -20,8 +20,8 @@ const StepOne = ({ data, setData }) => {

- - + + Date: Fri, 19 Jul 2024 10:40:33 +0100 Subject: [PATCH 16/78] fix: remove data from stepper --- src/components/stepper/index.js | 6 +++--- src/pages/welcome/index.js | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/stepper/index.js b/src/components/stepper/index.js index 398030c4..c4156a4f 100644 --- a/src/components/stepper/index.js +++ b/src/components/stepper/index.js @@ -4,7 +4,7 @@ import Button from "../button"; import "./style.css"; import { useState } from "react"; -const Stepper = ({ header, children, onComplete, data }) => { +const Stepper = ({ header, children, onComplete, missingFields }) => { const [currentStep, setCurrentStep] = useState(0) const onBackClick = () => { @@ -14,10 +14,10 @@ const Stepper = ({ header, children, onComplete, data }) => { } const onNextClick = () => { - if (data.firstName.length === 0 || data.lastName.length === 0) { + if (missingFields()) { return } - + if (currentStep === children.length-1) { onComplete() return diff --git a/src/pages/welcome/index.js b/src/pages/welcome/index.js index 888e42f7..a1e82c9e 100644 --- a/src/pages/welcome/index.js +++ b/src/pages/welcome/index.js @@ -32,6 +32,12 @@ const Welcome = () => { onCreateProfile(profile.firstName, profile.lastName, profile.username, profile.githubUsername, profile.bio, profile.mobile); }; + const missingFields = () => { + if (profile.firstName.length === 0 || profile.lastName.length === 0) { + return true + } + } + return (
@@ -39,7 +45,7 @@ const Welcome = () => {

Create your profile to get started

- } onComplete={onComplete} data={profile}> + } onComplete={onComplete} missingFields={missingFields}> From 8cb81173d0eb972bdedef5adb45e1f35171988fc Mon Sep 17 00:00:00 2001 From: Leonardo Lodi Date: Fri, 19 Jul 2024 10:55:09 +0100 Subject: [PATCH 17/78] fix: adjust can progress at step one --- src/components/stepper/index.js | 4 ++-- src/pages/welcome/index.js | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/components/stepper/index.js b/src/components/stepper/index.js index c4156a4f..346408d5 100644 --- a/src/components/stepper/index.js +++ b/src/components/stepper/index.js @@ -4,7 +4,7 @@ import Button from "../button"; import "./style.css"; import { useState } from "react"; -const Stepper = ({ header, children, onComplete, missingFields }) => { +const Stepper = ({ header, children, onComplete, canProgress }) => { const [currentStep, setCurrentStep] = useState(0) const onBackClick = () => { @@ -14,7 +14,7 @@ const Stepper = ({ header, children, onComplete, missingFields }) => { } const onNextClick = () => { - if (missingFields()) { + if (!canProgress) { return } diff --git a/src/pages/welcome/index.js b/src/pages/welcome/index.js index a1e82c9e..0422b438 100644 --- a/src/pages/welcome/index.js +++ b/src/pages/welcome/index.js @@ -32,11 +32,7 @@ const Welcome = () => { onCreateProfile(profile.firstName, profile.lastName, profile.username, profile.githubUsername, profile.bio, profile.mobile); }; - const missingFields = () => { - if (profile.firstName.length === 0 || profile.lastName.length === 0) { - return true - } - } + const canProgress = profile.firstName.length !== 0 && profile.lastName.length !== 0 return (
@@ -45,7 +41,7 @@ const Welcome = () => {

Create your profile to get started

- } onComplete={onComplete} missingFields={missingFields}> + } onComplete={onComplete} canProgress={canProgress}> From c2c50e5ab625ee3a54593c4ccc7dfe2c3e730f97 Mon Sep 17 00:00:00 2001 From: Hamada Abdelaal Date: Fri, 19 Jul 2024 12:06:59 +0200 Subject: [PATCH 18/78] merge main --- src/service/apiClient.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/service/apiClient.js b/src/service/apiClient.js index 8269397b..9b446600 100644 --- a/src/service/apiClient.js +++ b/src/service/apiClient.js @@ -13,18 +13,23 @@ async function register(email, password) { return await login(email, password); } -<<<<<<< HEAD -async function createProfile(userId, firstName, lastName, githubUrl, bio) { +async function createProfile( + userId, + firstName, + lastName, + username, + githubUrl, + mobile, + bio +) { return await patch(`users/${userId}`, { firstName, lastName, + username, githubUrl, + mobile, bio, }); -======= -async function createProfile(userId, firstName, lastName, username, githubUrl, mobile, bio) { - return await patch(`users/${userId}`, { firstName, lastName, username, githubUrl, mobile, bio }) ->>>>>>> main } async function getPosts() { From 2a8968802137a9da79cfcb1c5dafe271a7fc2517 Mon Sep 17 00:00:00 2001 From: Leonardo Lodi Date: Fri, 19 Jul 2024 11:13:59 +0100 Subject: [PATCH 19/78] fix: set can progress boolean to true --- src/components/stepper/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/stepper/index.js b/src/components/stepper/index.js index 346408d5..d39e63dc 100644 --- a/src/components/stepper/index.js +++ b/src/components/stepper/index.js @@ -4,7 +4,7 @@ import Button from "../button"; import "./style.css"; import { useState } from "react"; -const Stepper = ({ header, children, onComplete, canProgress }) => { +const Stepper = ({ header, children, onComplete, canProgress = true }) => { const [currentStep, setCurrentStep] = useState(0) const onBackClick = () => { From 8c7616556d535e877c2e43e95582238f8f39ecb7 Mon Sep 17 00:00:00 2001 From: Hamada Abdelaal Date: Fri, 19 Jul 2024 12:15:39 +0200 Subject: [PATCH 20/78] remove the debug log --- src/components/posts/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/posts/index.js b/src/components/posts/index.js index afd0d6e7..9c843fd8 100644 --- a/src/components/posts/index.js +++ b/src/components/posts/index.js @@ -4,7 +4,6 @@ import { getPosts } from "../../service/apiClient"; const Posts = () => { const [posts, setPosts] = useState([]); - console.log(posts); useEffect(() => { getPosts().then(setPosts); }, []); From b4188a35765758ebf74d8f07f55a908731987aca Mon Sep 17 00:00:00 2001 From: Leonardo Lodi Date: Fri, 19 Jul 2024 11:44:26 +0100 Subject: [PATCH 21/78] style: adjust position of icon --- src/styles/_form.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/_form.css b/src/styles/_form.css index d0e3af1a..c4af0ea6 100644 --- a/src/styles/_form.css +++ b/src/styles/_form.css @@ -23,7 +23,7 @@ form label { .input-icon { position: absolute; - left: 16px; + right: 16px; padding-top: 8px; } From 15cf7324fa3de9a37ad684c9c73e8467bf005a72 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Fri, 19 Jul 2024 14:27:36 +0200 Subject: [PATCH 22/78] fix navigation on create profile --- src/context/auth.js | 11 +++++++---- src/service/apiClient.js | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/context/auth.js b/src/context/auth.js index f8b3857a..3266ee39 100644 --- a/src/context/auth.js +++ b/src/context/auth.js @@ -59,13 +59,16 @@ const AuthProvider = ({ children }) => { } }; - const handleCreateProfile = async (firstName, lastName, githubUrl, bio) => { + const handleCreateProfile = async (firstName, lastName, username, githubUsername, mobile, bio) => { const { userId } = jwt_decode(token); - await createProfile(userId, firstName, lastName, githubUrl, bio); - localStorage.setItem("token", token); - navigate("/"); + + const res= await createProfile(userId, firstName, lastName, username, githubUsername, mobile, bio); + + if (res.status === "succes") { + navigate("/") + } }; const value = { diff --git a/src/service/apiClient.js b/src/service/apiClient.js index 9b446600..ab9183cc 100644 --- a/src/service/apiClient.js +++ b/src/service/apiClient.js @@ -18,7 +18,7 @@ async function createProfile( firstName, lastName, username, - githubUrl, + githubUsername, mobile, bio ) { @@ -26,7 +26,7 @@ async function createProfile( firstName, lastName, username, - githubUrl, + githubUsername, mobile, bio, }); From 10d17f4cbb60dda49e3c95307aa0eec1086145ba Mon Sep 17 00:00:00 2001 From: Leonardo Lodi Date: Fri, 19 Jul 2024 15:20:52 +0100 Subject: [PATCH 23/78] fix: password bug not changing value --- src/components/form/textInput/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/form/textInput/index.js b/src/components/form/textInput/index.js index 68b7448b..4c240fec 100644 --- a/src/components/form/textInput/index.js +++ b/src/components/form/textInput/index.js @@ -32,6 +32,10 @@ const TextInput = ({ type="text" name={name} value={input} + onChange={(e) => { + onChange(e); + setInput(e.target.value); + }} className="passwordreveal" /> )} From edd8af4543b6563d5719187243d9878173fe88b6 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Fri, 19 Jul 2024 16:43:30 +0200 Subject: [PATCH 24/78] fix typo --- src/context/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context/auth.js b/src/context/auth.js index 3266ee39..8fbbd2dd 100644 --- a/src/context/auth.js +++ b/src/context/auth.js @@ -66,7 +66,7 @@ const AuthProvider = ({ children }) => { const res= await createProfile(userId, firstName, lastName, username, githubUsername, mobile, bio); - if (res.status === "succes") { + if (res.status === "success") { navigate("/") } }; From 5715862a112144edbd04c005fcc7dbd9b2481f2c Mon Sep 17 00:00:00 2001 From: Angus Townsley Date: Mon, 22 Jul 2024 13:21:22 +0100 Subject: [PATCH 25/78] Locate hardcoded values --- src/components/createPostModal/index.js | 2 + src/components/editPostModal/index.js | 1 + src/components/header/index.js | 3 + src/pages/dashboard/index.js | 113 ++++++++++++------------ 4 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/components/createPostModal/index.js b/src/components/createPostModal/index.js index d77d996f..fb2d7241 100644 --- a/src/components/createPostModal/index.js +++ b/src/components/createPostModal/index.js @@ -23,6 +23,8 @@ const CreatePostModal = () => { }, 2000); }; + //TODO:Fix Hardcoded Text + return ( <>
diff --git a/src/components/editPostModal/index.js b/src/components/editPostModal/index.js index b21e5f86..19c884bf 100644 --- a/src/components/editPostModal/index.js +++ b/src/components/editPostModal/index.js @@ -20,6 +20,7 @@ const EditPostModal = () => { closeModal() }, 2000) } + //TODO: Fix hardcoded text return ( <> diff --git a/src/components/header/index.js b/src/components/header/index.js index 7b541381..7dea66ce 100644 --- a/src/components/header/index.js +++ b/src/components/header/index.js @@ -19,8 +19,11 @@ const Header = () => { if (!token) { return null; } + //TODO Fix hardcoded text return ( + +
diff --git a/src/pages/dashboard/index.js b/src/pages/dashboard/index.js index 8a65b832..d622767b 100644 --- a/src/pages/dashboard/index.js +++ b/src/pages/dashboard/index.js @@ -1,65 +1,68 @@ -import { useState } from "react"; -import SearchIcon from "../../assets/icons/searchIcon"; -import Button from "../../components/button"; -import Card from "../../components/card"; -import CreatePostModal from "../../components/createPostModal"; -import TextInput from "../../components/form/textInput"; -import Posts from "../../components/posts"; -import useModal from "../../hooks/useModal"; -import "./style.css"; +import { useState } from 'react' +import SearchIcon from '../../assets/icons/searchIcon' +import Button from '../../components/button' +import Card from '../../components/card' +import CreatePostModal from '../../components/createPostModal' +import TextInput from '../../components/form/textInput' +import Posts from '../../components/posts' +import useModal from '../../hooks/useModal' +import './style.css' const Dashboard = () => { - const [searchVal, setSearchVal] = useState(''); + const [searchVal, setSearchVal] = useState('') - const onChange = (e) => { - setSearchVal(e.target.value); - }; + const onChange = (e) => { + setSearchVal(e.target.value) + } - // Use the useModal hook to get the openModal and setModal functions - const { openModal, setModal } = useModal(); + // Use the useModal hook to get the openModal and setModal functions + const { openModal, setModal } = useModal() - // Create a function to run on user interaction - const showModal = () => { - // Use setModal to set the header of the modal and the component the modal should render - setModal("Create a post", ); // CreatePostModal is just a standard React component, nothing special + // Create a function to run on user interaction + const showModal = () => { + // Use setModal to set the header of the modal and the component the modal should render + setModal('Create a post', ) // CreatePostModal is just a standard React component, nothing special - // Open the modal! - openModal(); - }; + // Open the modal! + openModal() + } + //TODO Fix hardcoded text + return ( + <> +
+ +
+
+

AJ

+
+
+
- return ( - <> -
- -
-
-

AJ

-
-
-
+ +
- -
+ - - ); -}; - -export default Dashboard; +export default Dashboard From c9fa90906ed94dbecfcf1bfac012c4902e506af4 Mon Sep 17 00:00:00 2001 From: Angus Townsley Date: Mon, 22 Jul 2024 14:59:44 +0100 Subject: [PATCH 26/78] Create current user context and replace hardcoded data --- src/App.js | 90 ++++++++-------- src/components/createPostModal/index.js | 118 ++++++++++----------- src/components/editPostModal/index.js | 27 +++-- src/components/header/index.js | 131 ++++++++++++------------ src/components/profileCircle/index.js | 7 +- src/context/currentUser.js | 71 +++++++++++++ src/hooks/useUser.js | 8 ++ src/pages/dashboard/index.js | 6 +- src/service/apiClient.js | 6 +- 9 files changed, 285 insertions(+), 179 deletions(-) create mode 100644 src/context/currentUser.js create mode 100644 src/hooks/useUser.js diff --git a/src/App.js b/src/App.js index 4fe66c60..7d975ee9 100644 --- a/src/App.js +++ b/src/App.js @@ -1,46 +1,52 @@ -import "./App.css"; -import { Routes, Route } from "react-router-dom"; -import Dashboard from "./pages/dashboard"; -import Login from "./pages/login"; -import Register from "./pages/register"; -import Loading from "./pages/loading"; -import Verification from "./pages/verification"; -import { AuthProvider, ProtectedRoute } from "./context/auth"; -import { ModalProvider } from "./context/modal"; -import Welcome from "./pages/welcome"; +import './App.css' +import { Routes, Route } from 'react-router-dom' +import Dashboard from './pages/dashboard' +import Login from './pages/login' +import Register from './pages/register' +import Loading from './pages/loading' +import Verification from './pages/verification' +import { AuthProvider, ProtectedRoute } from './context/auth' +import { ModalProvider } from './context/modal' +import { CurrentUserProvider } from './context/currentUser' +import Welcome from './pages/welcome' const App = () => { - return ( - <> - - - - } /> - } /> - } /> - } /> + return ( + <> + + + + + } /> + } /> + } /> + } + /> - - - - } - /> - - - - } - /> - - - - - ); -}; + + + + } + /> + + + + } + /> + + + + + + ) +} -export default App; +export default App diff --git a/src/components/createPostModal/index.js b/src/components/createPostModal/index.js index fb2d7241..a6019343 100644 --- a/src/components/createPostModal/index.js +++ b/src/components/createPostModal/index.js @@ -1,61 +1,61 @@ -import { useState } from "react"; -import useModal from "../../hooks/useModal"; -import "./style.css"; -import Button from "../button"; +import { useState } from 'react' +import useModal from '../../hooks/useModal' +import './style.css' +import Button from '../button' +import useUser from '../../hooks/useUser' const CreatePostModal = () => { - // Use the useModal hook to get the closeModal function so we can close the modal on user interaction - const { closeModal } = useModal(); - - const [message, setMessage] = useState(null); - const [text, setText] = useState(""); - - const onChange = (e) => { - setText(e.target.value); - }; - - const onSubmit = () => { - setMessage("Submit button was clicked! Closing modal in 2 seconds..."); - - setTimeout(() => { - setMessage(null); - closeModal(); - }, 2000); - }; - - //TODO:Fix Hardcoded Text - - return ( - <> -
-
-

AJ

-
-
-

Alex J

-
-
- -
- -
- -
-
- - {message &&

{message}

} - - ); -}; - -export default CreatePostModal; + // Use the useModal hook to get the closeModal function so we can close the modal on user interaction + const { closeModal } = useModal() + const { userInitials, userFirstNameAndInital } = useUser() + + const [message, setMessage] = useState(null) + const [text, setText] = useState('') + + const onChange = (e) => { + setText(e.target.value) + } + + const onSubmit = () => { + setMessage('Submit button was clicked! Closing modal in 2 seconds...') + + setTimeout(() => { + setMessage(null) + closeModal() + }, 2000) + } + + return ( + <> +
+
+

{userInitials}

+
+
+

{userFirstNameAndInital}

+
+
+ +
+ +
+ +
+
+ + {message &&

{message}

} + + ) +} + +export default CreatePostModal diff --git a/src/components/editPostModal/index.js b/src/components/editPostModal/index.js index 19c884bf..efa167fe 100644 --- a/src/components/editPostModal/index.js +++ b/src/components/editPostModal/index.js @@ -1,12 +1,14 @@ -import { useState } from "react" -import useModal from "../../hooks/useModal" +import { useState } from 'react' +import useModal from '../../hooks/useModal' import './style.css' import Button from '../button' +import useUser from '../../hooks/useUser' const EditPostModal = () => { const { closeModal } = useModal() const [message, setMessage] = useState(null) const [text, setText] = useState('') + const { userInitials, userFirstNameAndInital } = useUser() const onChange = (e) => { setText(e.target.value) @@ -20,24 +22,31 @@ const EditPostModal = () => { closeModal() }, 2000) } - //TODO: Fix hardcoded text return ( <>
-

AJ

-

Alex J

+
+

{userInitials}

+
+
+

{userFirstNameAndInital}

+
- +
@@ -47,4 +56,4 @@ const EditPostModal = () => { ) } -export default EditPostModal \ No newline at end of file +export default EditPostModal diff --git a/src/components/header/index.js b/src/components/header/index.js index 7dea66ce..2daec5df 100644 --- a/src/components/header/index.js +++ b/src/components/header/index.js @@ -1,74 +1,77 @@ -import FullLogo from "../../assets/fullLogo"; -import useAuth from "../../hooks/useAuth"; -import "./style.css"; -import Card from "../card"; -import ProfileIcon from "../../assets/icons/profileIcon"; -import CogIcon from "../../assets/icons/cogIcon"; -import LogoutIcon from "../../assets/icons/logoutIcon"; -import { NavLink } from "react-router-dom"; -import { useState } from "react"; +import FullLogo from '../../assets/fullLogo' +import useAuth from '../../hooks/useAuth' +import './style.css' +import Card from '../card' +import ProfileIcon from '../../assets/icons/profileIcon' +import CogIcon from '../../assets/icons/cogIcon' +import LogoutIcon from '../../assets/icons/logoutIcon' +import { NavLink } from 'react-router-dom' +import { useState } from 'react' +import useUser from '../../hooks/useUser' const Header = () => { - const { token, onLogout } = useAuth(); - const [isMenuVisible, setIsMenuVisible] = useState(false); + const { token, onLogout } = useAuth() + const [isMenuVisible, setIsMenuVisible] = useState(false) + const { currentUser, userFullName, userInitials, userCohort } = useUser() - const onClickProfileIcon = () => { - setIsMenuVisible(!isMenuVisible); - }; + const onClickProfileIcon = () => { + setIsMenuVisible(!isMenuVisible) + } - if (!token) { - return null; - } - //TODO Fix hardcoded text + if (!token) { + return null + } - return ( - - -
- + return ( +
+ -
-

AJ

-
+
+

{userInitials}

+
- {isMenuVisible && ( -
- -
-
-

AJ

-
+ {isMenuVisible && ( +
+ +
+
+

{userInitials}

+
-
-

Alex Jameson

- Software Developer, Cohort 3 -
-
+
+

{userFullName}

+ + {currentUser.role},{' '} + {userCohort} + +
+
-
-
    -
  • - -

    Profile

    -
    -
  • -
  • - -

    Settings & Privacy

    -
    -
  • -
  • - -

    Log out

    -
    -
  • -
-
-
-
- )} -
- ); -}; +
+
    +
  • + +

    Profile

    +
    +
  • +
  • + + {' '} +

    Settings & Privacy

    +
    +
  • +
  • + +

    Log out

    +
    +
  • +
+
+ + + )} +
+ ) +} -export default Header; +export default Header diff --git a/src/components/profileCircle/index.js b/src/components/profileCircle/index.js index fa5237ef..5a812bd4 100644 --- a/src/components/profileCircle/index.js +++ b/src/components/profileCircle/index.js @@ -12,13 +12,16 @@ import './style.css' const ProfileCircle = ({ initials }) => { const [isMenuVisible, setIsMenuVisible] = useState(false) - + const uppercaseInitals = initials.map((element) => { + return element.toUpperCase() + }) + return (
setIsMenuVisible(!isMenuVisible)}> {isMenuVisible && }
-

{initials}

+

{uppercaseInitals}

diff --git a/src/context/currentUser.js b/src/context/currentUser.js new file mode 100644 index 00000000..d5defd8b --- /dev/null +++ b/src/context/currentUser.js @@ -0,0 +1,71 @@ +import { createContext, useEffect, useState } from 'react' +import useAuth from '../hooks/useAuth' +import jwt_decode from 'jwt-decode' +import { getUser } from '../service/apiClient' + +export const CurrentUserContext = createContext() + +export const CurrentUserProvider = ({ children }) => { + const { token } = useAuth() + const [currentUser, setCurrentUser] = useState({ empty: true }) + const [userInitials, setUserInitals] = useState('') + const [userFullName, setUserFullName] = useState('') + const [userCohort, setUserCohort] = useState('') + const [userFirstNameAndInital, setUserFirstNameAndInital] = useState('') + + useEffect(() => { + async function getUserFromToken() { + if (token) { + const { userId } = jwt_decode(token) + + const userDetails = await getUser(userId) + userDetails.status === 'success' + ? setCurrentUser({ ...userDetails.data.user }) + : setCurrentUser({ empty: true }) + return + } + setCurrentUser({ empty: true }) + return + } + getUserFromToken() + }, [token]) + + useEffect(() => { + if (!currentUser.empty) { + setUserInitals( + currentUser + ? `${currentUser.firstName[0].toUpperCase()}${currentUser.lastName[0].toUpperCase()}` + : '' + ) + setUserFullName( + currentUser + ? `${currentUser.firstName} ${currentUser.lastName}` + : '' + ) + setUserCohort( + currentUser && currentUser.cohort + ? 'Cohort' + currentUser.cohort + : '' + ) + setUserFirstNameAndInital( + currentUser + ? `${currentUser.firstName} ${currentUser.lastName[0]}` + : '' + ) + } + }, [currentUser]) + + return ( + + {children} + + ) +} diff --git a/src/hooks/useUser.js b/src/hooks/useUser.js new file mode 100644 index 00000000..a4035a0c --- /dev/null +++ b/src/hooks/useUser.js @@ -0,0 +1,8 @@ +import { useContext } from "react" +import { CurrentUserContext } from "../context/currentUser" + +const useUser = () => { + return useContext(CurrentUserContext) +} + +export default useUser \ No newline at end of file diff --git a/src/pages/dashboard/index.js b/src/pages/dashboard/index.js index d622767b..1a6a0cc1 100644 --- a/src/pages/dashboard/index.js +++ b/src/pages/dashboard/index.js @@ -7,9 +7,11 @@ import TextInput from '../../components/form/textInput' import Posts from '../../components/posts' import useModal from '../../hooks/useModal' import './style.css' +import useUser from '../../hooks/useUser' const Dashboard = () => { const [searchVal, setSearchVal] = useState('') + const { userInitials } = useUser() const onChange = (e) => { setSearchVal(e.target.value) @@ -26,14 +28,14 @@ const Dashboard = () => { // Open the modal! openModal() } - //TODO Fix hardcoded text + return ( <>
-

AJ

+

{userInitials}