GH-3245 Change password from settings page (#3538)
* GH-3245 add passwordResetToken and passwordResetTokenExpiresAt column on user entity * Add password reset token expiry delay env variable * Add generatePasswordResetToken mutation resolver * Update .env.sample file on server * Add password reset token and expiry migration script * Add validate password reset token query and a dummy password update (WIP) resolver * Fix bug in password reset token generate * add update password mutation * Update name and add email password reset link * Add change password UI on settings page * Add reset password route on frontend * Add reset password form UI * sign in user on password reset * format code * make PASSWORD_RESET_TOKEN_EXPIRES_IN optional * add email template for password reset * Improve error message * Rename methods and DTO to improve naming * fix formatting of backend code * Update change password component * Update password reset via token component * update graphql files * spelling fix * Make password-reset route authless on frontend * show token generation wait time * remove constant from .env.example * Add PASSWORD_RESET_TOKEN_EXPIRES_IN in docs * refactor emails module in reset password * update Graphql generated file * update email template of password reset * add space between date and text * update method name * fix lint issues * remove unused code, fix indentation, and email link color * update test file for auth and token service * Fix ci: build twenty-emails when running tests --------- Co-authored-by: martmull <martmull@hotmail.fr>
This commit is contained in:
@ -42,7 +42,8 @@ export const useApolloFactory = () => {
|
||||
!isMatchingLocation(AppPath.Verify) &&
|
||||
!isMatchingLocation(AppPath.SignIn) &&
|
||||
!isMatchingLocation(AppPath.SignUp) &&
|
||||
!isMatchingLocation(AppPath.Invite)
|
||||
!isMatchingLocation(AppPath.Invite) &&
|
||||
!isMatchingLocation(AppPath.ResetPassword)
|
||||
) {
|
||||
navigate(AppPath.SignIn);
|
||||
}
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const EMAIL_PASSWORD_RESET_Link = gql`
|
||||
mutation EmailPasswordResetLink {
|
||||
emailPasswordResetLink {
|
||||
success
|
||||
}
|
||||
}
|
||||
`;
|
||||
@ -0,0 +1,12 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const UPDATE_PASSWORD_VIA_RESET_TOKEN = gql`
|
||||
mutation UpdatePasswordViaResetToken($token: String!, $newPassword: String!) {
|
||||
updatePasswordViaResetToken(
|
||||
passwordResetToken: $token
|
||||
newPassword: $newPassword
|
||||
) {
|
||||
success
|
||||
}
|
||||
}
|
||||
`;
|
||||
@ -0,0 +1,10 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const VALIDATE_PASSWORD_RESET_TOKEN = gql`
|
||||
query validatePasswordResetToken($token: String!) {
|
||||
validatePasswordResetToken(passwordResetToken: $token) {
|
||||
id
|
||||
email
|
||||
}
|
||||
}
|
||||
`;
|
||||
@ -0,0 +1,45 @@
|
||||
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
import { useEmailPasswordResetLinkMutation } from '~/generated/graphql';
|
||||
import { logError } from '~/utils/logError';
|
||||
|
||||
export const ChangePassword = () => {
|
||||
const { enqueueSnackBar } = useSnackBar();
|
||||
|
||||
const [emailPasswordResetLink] = useEmailPasswordResetLinkMutation();
|
||||
|
||||
const handlePasswordResetClick = async () => {
|
||||
try {
|
||||
const { data } = await emailPasswordResetLink();
|
||||
if (data?.emailPasswordResetLink?.success) {
|
||||
enqueueSnackBar('Password reset link has been sent to the email', {
|
||||
variant: 'success',
|
||||
});
|
||||
} else {
|
||||
enqueueSnackBar('There was some issue', {
|
||||
variant: 'error',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logError(error);
|
||||
enqueueSnackBar((error as Error).message, {
|
||||
variant: 'error',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<H2Title
|
||||
title="Change Password"
|
||||
description="Receive an email containing password update link"
|
||||
/>
|
||||
<Button
|
||||
onClick={handlePasswordResetClick}
|
||||
variant="secondary"
|
||||
title="Change Password"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -4,6 +4,7 @@ export enum AppPath {
|
||||
SignIn = '/sign-in',
|
||||
SignUp = '/sign-up',
|
||||
Invite = '/invite/:workspaceInviteHash',
|
||||
ResetPassword = '/reset-password/:passwordResetToken',
|
||||
|
||||
// Onboarding
|
||||
CreateWorkspace = '/create/workspace',
|
||||
|
||||
Reference in New Issue
Block a user