diff --git a/src/backend/app/utils.py b/src/backend/app/utils.py index ec788ef..05b75b3 100644 --- a/src/backend/app/utils.py +++ b/src/backend/app/utils.py @@ -43,7 +43,7 @@ def send_test_email(email_to: str) -> None: email_to=email_to, subject_template=subject, html_template=template_str, - current_environment={"project_name": settings.PROJECT_NAME, "email": email_to}, + environment={"project_name": settings.PROJECT_NAME, "email": email_to}, ) @@ -58,7 +58,7 @@ def send_reset_password_email(email_to: str, email: str, token: str) -> None: email_to=email_to, subject_template=subject, html_template=template_str, - current_environment={ + environment={ "project_name": settings.PROJECT_NAME, "username": email, "email": email_to, @@ -78,7 +78,7 @@ def send_new_account_email(email_to: str, username: str, password: str) -> None: email_to=email_to, subject_template=subject, html_template=template_str, - current_environment={ + environment={ "project_name": settings.PROJECT_NAME, "username": username, "password": password, @@ -104,6 +104,6 @@ def generate_password_reset_token(email: str) -> str: def verify_password_reset_token(token: str) -> str | None: try: decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"]) - return decoded_token["email"] + return decoded_token["sub"] except jwt.JWTError: return None diff --git a/src/new-frontend/src/pages/RecoverPassword.tsx b/src/new-frontend/src/pages/RecoverPassword.tsx index cbe8ff7..1ed681f 100644 --- a/src/new-frontend/src/pages/RecoverPassword.tsx +++ b/src/new-frontend/src/pages/RecoverPassword.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { Button, Container, FormControl, Heading, Input, Text } from "@chakra-ui/react"; +import { Button, Container, FormControl, FormErrorMessage, Heading, Input, Text } from "@chakra-ui/react"; import { SubmitHandler, useForm } from "react-hook-form"; import { LoginService } from "../client"; @@ -11,14 +11,13 @@ interface FormData { } const RecoverPassword: React.FC = () => { - const { register, handleSubmit } = useForm(); + const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm(); const showToast = useCustomToast(); const onSubmit: SubmitHandler = async (data) => { - const response = await LoginService.recoverPassword({ + await LoginService.recoverPassword({ email: data.email, }); - console.log(response) showToast("Email sent.", "We sent an email with a link to get back into your account.", "success"); }; @@ -37,19 +36,14 @@ const RecoverPassword: React.FC = () => { Password Recovery - - - A password recovery email will be sent to the registered account. - - + + A password recovery email will be sent to the registered account. + + + + {errors.email && {errors.email.message}} - diff --git a/src/new-frontend/src/pages/ResetPassword.tsx b/src/new-frontend/src/pages/ResetPassword.tsx new file mode 100644 index 0000000..e80f2e9 --- /dev/null +++ b/src/new-frontend/src/pages/ResetPassword.tsx @@ -0,0 +1,72 @@ +import React from "react"; + +import { Button, Container, FormControl, FormErrorMessage, FormLabel, Heading, Input, Text } from "@chakra-ui/react"; +import { SubmitHandler, useForm } from "react-hook-form"; + +import { LoginService, NewPassword } from "../client"; +import useCustomToast from "../hooks/useCustomToast"; + +interface NewPasswordForm extends NewPassword { + confirm_password: string; +} + +const ResetPassword: React.FC = () => { + const { register, handleSubmit, getValues, formState: { errors } } = useForm({ + mode: 'onBlur', + criteriaMode: 'all', + defaultValues: { + new_password: '', + } + }); + const showToast = useCustomToast(); + + const onSubmit: SubmitHandler = async (data) => { + try { + const token = new URLSearchParams(window.location.search).get('token'); + await LoginService.resetPassword({ + requestBody: { new_password: data.new_password, token: token! } + }); + showToast("Password reset.", "Your password has been reset successfully.", "success"); + } catch (error) { + showToast("Error", "An error occurred while resetting your password.", "error"); + } + }; + + return ( + + + Reset Password + + + Please enter your new password and confirm it to reset your password. + + + Set Password + + {errors.new_password && {errors.new_password.message}} + + + Confirm Password + value === getValues().new_password || 'The passwords do not match' + })} placeholder='Password' type='password' /> + {errors.confirm_password && {errors.confirm_password.message}} + + + + ); +}; + +export default ResetPassword; \ No newline at end of file diff --git a/src/new-frontend/src/routes/public_route.tsx b/src/new-frontend/src/routes/public_route.tsx index 8b4dd4c..cffa5a3 100644 --- a/src/new-frontend/src/routes/public_route.tsx +++ b/src/new-frontend/src/routes/public_route.tsx @@ -1,11 +1,13 @@ import ErrorPage from '../pages/ErrorPage'; import Login from '../pages/Login'; import RecoverPassword from '../pages/RecoverPassword'; +import ResetPassword from '../pages/ResetPassword'; export default function publicRoutes() { return [ { path: '/login', element: , errorElement: }, { path: 'recover-password', element: , errorElement: }, + { path: 'reset-password', element: , errorElement: }, // TODO: complete this // { path: '*', element: } ];