From dd0a1328e841e7eccbe706b83ee35dba707126e7 Mon Sep 17 00:00:00 2001 From: "kasia.oczkowska" Date: Wed, 17 Jul 2024 15:04:15 +0100 Subject: [PATCH] feat: refactor reset password mutation with the REST API endpoint --- .../backend/src/graphql/mutation-resolvers.js | 2 - .../graphql/mutations/reset-password.ee.js | 23 --------- packages/backend/src/graphql/schema.graphql | 6 --- .../backend/src/helpers/authentication.js | 1 - .../components/ResetPasswordForm/index.ee.jsx | 48 +++++++++++-------- .../graphql/mutations/reset-password.ee.js | 6 --- packages/web/src/hooks/useResetPassword.js | 15 ++++++ packages/web/src/locales/en.json | 1 + 8 files changed, 45 insertions(+), 57 deletions(-) delete mode 100644 packages/backend/src/graphql/mutations/reset-password.ee.js delete mode 100644 packages/web/src/graphql/mutations/reset-password.ee.js create mode 100644 packages/web/src/hooks/useResetPassword.js diff --git a/packages/backend/src/graphql/mutation-resolvers.js b/packages/backend/src/graphql/mutation-resolvers.js index cacd3936..a695f6e9 100644 --- a/packages/backend/src/graphql/mutation-resolvers.js +++ b/packages/backend/src/graphql/mutation-resolvers.js @@ -32,7 +32,6 @@ import verifyConnection from './mutations/verify-connection.js'; // Converted mutations import deleteUser from './mutations/delete-user.ee.js'; import login from './mutations/login.js'; -import resetPassword from './mutations/reset-password.ee.js'; const mutationResolvers = { createAppAuthClient, @@ -54,7 +53,6 @@ const mutationResolvers = { login, registerUser, resetConnection, - resetPassword, updateAppAuthClient, updateAppConfig, updateConfig, diff --git a/packages/backend/src/graphql/mutations/reset-password.ee.js b/packages/backend/src/graphql/mutations/reset-password.ee.js deleted file mode 100644 index 309b006a..00000000 --- a/packages/backend/src/graphql/mutations/reset-password.ee.js +++ /dev/null @@ -1,23 +0,0 @@ -import User from '../../models/user.js'; - -const resetPassword = async (_parent, params) => { - const { token, password } = params.input; - - if (!token) { - throw new Error('Reset password token is required!'); - } - - const user = await User.query().findOne({ reset_password_token: token }); - - if (!user || !user.isResetPasswordTokenValid()) { - throw new Error( - 'Reset password link is not valid or expired. Try generating a new link.' - ); - } - - await user.resetPassword(password); - - return true; -}; - -export default resetPassword; diff --git a/packages/backend/src/graphql/schema.graphql b/packages/backend/src/graphql/schema.graphql index e64228fd..98d254c4 100644 --- a/packages/backend/src/graphql/schema.graphql +++ b/packages/backend/src/graphql/schema.graphql @@ -21,7 +21,6 @@ type Mutation { login(input: LoginInput): Auth registerUser(input: RegisterUserInput): User resetConnection(input: ResetConnectionInput): Connection - resetPassword(input: ResetPasswordInput): Boolean updateAppAuthClient(input: UpdateAppAuthClientInput): AppAuthClient updateAppConfig(input: UpdateAppConfigInput): AppConfig updateConfig(input: JSONObject): JSONObject @@ -404,11 +403,6 @@ input UpdateCurrentUserInput { fullName: String } -input ResetPasswordInput { - token: String! - password: String! -} - input LoginInput { email: String! password: String! diff --git a/packages/backend/src/helpers/authentication.js b/packages/backend/src/helpers/authentication.js index f57c41fa..b119915a 100644 --- a/packages/backend/src/helpers/authentication.js +++ b/packages/backend/src/helpers/authentication.js @@ -55,7 +55,6 @@ export const authenticationRules = { '*': isAuthenticatedRule, login: allow, registerUser: allow, - resetPassword: allow, }, }; diff --git a/packages/web/src/components/ResetPasswordForm/index.ee.jsx b/packages/web/src/components/ResetPasswordForm/index.ee.jsx index 996311ab..4d4cdaaf 100644 --- a/packages/web/src/components/ResetPasswordForm/index.ee.jsx +++ b/packages/web/src/components/ResetPasswordForm/index.ee.jsx @@ -1,4 +1,3 @@ -import { useMutation } from '@apollo/client'; import { yupResolver } from '@hookform/resolvers/yup'; import LoadingButton from '@mui/lab/LoadingButton'; import Paper from '@mui/material/Paper'; @@ -7,11 +6,12 @@ import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar'; import * as React from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; import * as yup from 'yup'; + import Form from 'components/Form'; import TextField from 'components/TextField'; import * as URLS from 'config/urls'; -import { RESET_PASSWORD } from 'graphql/mutations/reset-password.ee'; import useFormatMessage from 'hooks/useFormatMessage'; +import useResetPassword from 'hooks/useResetPassword'; const validationSchema = yup.object().shape({ password: yup.string().required('resetPasswordForm.mandatoryInput'), @@ -26,25 +26,35 @@ export default function ResetPasswordForm() { const formatMessage = useFormatMessage(); const navigate = useNavigate(); const [searchParams] = useSearchParams(); - const [resetPassword, { data, loading }] = useMutation(RESET_PASSWORD); + const { + mutateAsync: resetPassword, + isPending, + isSuccess, + } = useResetPassword(); const token = searchParams.get('token'); const handleSubmit = async (values) => { - await resetPassword({ - variables: { - input: { - password: values.password, - token, + const { password } = values; + try { + await resetPassword({ + password, + token, + }); + enqueueSnackbar(formatMessage('resetPasswordForm.passwordUpdated'), { + variant: 'success', + SnackbarProps: { + 'data-test': 'snackbar-reset-password-success', }, - }, - }); - enqueueSnackbar(formatMessage('resetPasswordForm.passwordUpdated'), { - variant: 'success', - SnackbarProps: { - 'data-test': 'snackbar-reset-password-success', - }, - }); - navigate(URLS.LOGIN); + }); + navigate(URLS.LOGIN); + } catch (error) { + enqueueSnackbar( + error?.message || formatMessage('resetPasswordForm.error'), + { + variant: 'error', + }, + ); + } }; return ( @@ -113,8 +123,8 @@ export default function ResetPasswordForm() { variant="contained" color="primary" sx={{ boxShadow: 2, my: 3 }} - loading={loading} - disabled={data || !token} + loading={isPending} + disabled={isSuccess || !token} fullWidth > {formatMessage('resetPasswordForm.submit')} diff --git a/packages/web/src/graphql/mutations/reset-password.ee.js b/packages/web/src/graphql/mutations/reset-password.ee.js deleted file mode 100644 index 42360bca..00000000 --- a/packages/web/src/graphql/mutations/reset-password.ee.js +++ /dev/null @@ -1,6 +0,0 @@ -import { gql } from '@apollo/client'; -export const RESET_PASSWORD = gql` - mutation ResetPassword($input: ResetPasswordInput) { - resetPassword(input: $input) - } -`; diff --git a/packages/web/src/hooks/useResetPassword.js b/packages/web/src/hooks/useResetPassword.js new file mode 100644 index 00000000..48e8b5c2 --- /dev/null +++ b/packages/web/src/hooks/useResetPassword.js @@ -0,0 +1,15 @@ +import { useMutation } from '@tanstack/react-query'; + +import api from 'helpers/api'; + +export default function useResetPassword() { + const mutation = useMutation({ + mutationFn: async (payload) => { + const { data } = await api.post('/v1/users/reset-password', payload); + + return data; + }, + }); + + return mutation; +} diff --git a/packages/web/src/locales/en.json b/packages/web/src/locales/en.json index d2485902..14a289f9 100644 --- a/packages/web/src/locales/en.json +++ b/packages/web/src/locales/en.json @@ -165,6 +165,7 @@ "resetPasswordForm.passwordFieldLabel": "Password", "resetPasswordForm.confirmPasswordFieldLabel": "Confirm password", "resetPasswordForm.passwordUpdated": "The password has been updated. Now, you can login.", + "resetPasswordForm.error": "Something went wrong. Please try again.", "acceptInvitationForm.passwordsMustMatch": "Passwords must match.", "acceptInvitationForm.mandatoryInput": "{inputName} is required.", "acceptInvitationForm.title": "Accept invitation",