From 8460b52278457168d78a1d2fe35671eee3751382 Mon Sep 17 00:00:00 2001 From: edwin6666 Date: Fri, 19 Jan 2024 01:35:03 -0400 Subject: [PATCH] Feat(auth): forgot and reset password Changes: -Forgot password -Reset password -Send email with nodemailer --- src/App.js | 8 +++ src/components/Login/Login.jsx | 2 +- src/components/Navbar/Location.jsx | 3 +- src/components/Navbar/Navbar.jsx | 2 +- src/hooks/useAuthentication.js | 3 +- src/pages/ForgotPassword.js | 105 +++++++++++++++++++++++++++ src/pages/ResetPassword.js | 112 +++++++++++++++++++++++++++++ 7 files changed, 231 insertions(+), 4 deletions(-) create mode 100644 src/pages/ForgotPassword.js create mode 100644 src/pages/ResetPassword.js diff --git a/src/App.js b/src/App.js index a1a1041..58dbc57 100644 --- a/src/App.js +++ b/src/App.js @@ -13,6 +13,8 @@ import UserList from "./pages/Users"; import { PostDetailsCard } from "./components/PostDetailsCard"; import ConfirmUnsubscribePage from './pages/UnsubscribePage'; import EmailVerificationPage from "./pages/EmailPage"; +import ForgotPassword from "./pages/ForgotPassword" +import ResetPassword from "./pages/ResetPassword"; function App() { return (
@@ -29,6 +31,12 @@ function App() { } /> } /> } /> + } /> + } + /> + {/* Private routes */} }> } /> diff --git a/src/components/Login/Login.jsx b/src/components/Login/Login.jsx index f570819..38db568 100644 --- a/src/components/Login/Login.jsx +++ b/src/components/Login/Login.jsx @@ -65,7 +65,7 @@ const Signin = () => { - + Forgot password?
diff --git a/src/components/Navbar/Location.jsx b/src/components/Navbar/Location.jsx index b5b891e..157b07f 100644 --- a/src/components/Navbar/Location.jsx +++ b/src/components/Navbar/Location.jsx @@ -15,6 +15,7 @@ export const useRouteVariables = () => { isDetailPage: location.pathname.startsWith("/post/"), hideHomeLink: location.pathname.startsWith("/posts/"), isEmailPage: location.pathname==="/email", - isConfirmPage: location.pathname==="/confirm-unsubscribe" + isConfirmPage: location.pathname==="/confirm-unsubscribe", + isForgotPage: location.pathname ==="/forgot-password" }; }; diff --git a/src/components/Navbar/Navbar.jsx b/src/components/Navbar/Navbar.jsx index 96d7994..b75fdb4 100644 --- a/src/components/Navbar/Navbar.jsx +++ b/src/components/Navbar/Navbar.jsx @@ -24,7 +24,7 @@ const Navbar = () => { const toggleMenu = () => { setOpen(!open); }; - if (isLoginPage || isSignupPage) { + if (isLoginPage || isSignupPage ) { return null; } diff --git a/src/hooks/useAuthentication.js b/src/hooks/useAuthentication.js index b63d1fb..407cf25 100644 --- a/src/hooks/useAuthentication.js +++ b/src/hooks/useAuthentication.js @@ -18,7 +18,8 @@ const useAuthentication = () => { throw new Error("No roles or token received in response."); } - Cookies.set("token", token, { secure: true, sameSite: "strict" }); + // Actualizar el token almacenado localmente + Cookies.set("token", token, { secure: true, httpOnly: true, sameSite: "strict" }); if (roles.some((role) => role.name === "moderator")) { navigate("/admin"); diff --git a/src/pages/ForgotPassword.js b/src/pages/ForgotPassword.js new file mode 100644 index 0000000..6c34af6 --- /dev/null +++ b/src/pages/ForgotPassword.js @@ -0,0 +1,105 @@ +import React, { useState } from "react"; +import { Link, useNavigate } from "react-router-dom"; +import axios from "axios"; +import toast from "react-hot-toast"; + +const ForgotPassword = () => { + const [email, setEmail] = useState(""); + const navigate = useNavigate(); + + const handleForgotPassword = async () => { + try { + const response = await axios.post( + "http://localhost:4000/api/auth/forgot-password", + { + email, + } + ); + + if (response.status === 200) { + navigate("/email"); + } else if (response.status === 204) { + toast.error("Tu correo electrónico no está registrado con nosotros"); + } else { + toast.error( + response.data.message || + "Error al enviar el correo de restablecimiento." + ); + } + } catch (error) { + toast.error("Error al enviar el correo de restablecimiento."); + } + }; + + return ( +
+
+
+
+ +
+
+

Forgot Your Password?

+

+ We get it, stuff happens. Just enter your email address below + and we'll send you a link to reset your password! +

+
+
+
+ + setEmail(e.target.value)} + /> +
+
+ +
+
+
+ + Create an Account! + +
+
+ + Already have an account? Login! + +
+
+
+
+
+
+ ); +}; + +export default ForgotPassword; diff --git a/src/pages/ResetPassword.js b/src/pages/ResetPassword.js new file mode 100644 index 0000000..49cd1f2 --- /dev/null +++ b/src/pages/ResetPassword.js @@ -0,0 +1,112 @@ +import React, { useState, useEffect } from "react"; +import axios from "axios"; +import toast from "react-hot-toast"; +import { useNavigate, useLocation } from "react-router-dom"; + +const ResetPassword = () => { + const [token, setToken] = useState(""); + const [newPassword, setNewPassword] = useState(""); + const navigate = useNavigate(); + const location = useLocation(); + + useEffect(() => { + const resetTokenFromUrl = location.pathname.split("/").pop(); + setToken(resetTokenFromUrl); + }, [location.pathname]); + + const handleResetPassword = async () => { + try { + const response = await axios.post( + "http://localhost:4000/api/auth/reset-password", + { + token, + newPassword, + } + ); + + if (response.status === 200) { + navigate("/login"); + toast.success("Password Reset successful"); + } else { + if (response.status === 204 && response.data.notFound) { + toast.error( + response.data.message || "Your email is not registered with us." + ); + } else { + toast.error(response.data.message || "Error resetting the password."); + } + } + } catch (error) { + toast.error("Error resetting the password."); + } + }; + + return ( +
+
+
+
+ +
+
+

Reset Your Password

+

+ Enter your new password below to reset your password! +

+
+
+
+ + +
+
+ + setNewPassword(e.target.value)} + /> +
+
+ +
+
+
+
+
+
+ ); +}; + +export default ResetPassword;