From b9f81bec83810c8fb29b58dd8f06131582b7e4d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cbc-yevhenii-buliuk=E2=80=9D?= <“yevhenii.buliuk@bigcommerce.com”> Date: Thu, 6 Jun 2024 12:13:15 +0300 Subject: [PATCH] fix(core): user is not redirected to Login page after requesting password reset link --- .changeset/healthy-cycles-visit.md | 5 ++ .../_components/change-password-form.tsx | 11 ++--- .../login/_components/login-form.tsx | 8 ++++ .../_components/login-status-provider.tsx | 46 +++++++++++++++++++ .../_components/reset-password-form/index.tsx | 16 ++++--- core/app/[locale]/(default)/login/layout.tsx | 10 ++++ core/messages/en.json | 8 ++-- 7 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 .changeset/healthy-cycles-visit.md create mode 100644 core/app/[locale]/(default)/login/_components/login-status-provider.tsx create mode 100644 core/app/[locale]/(default)/login/layout.tsx diff --git a/.changeset/healthy-cycles-visit.md b/.changeset/healthy-cycles-visit.md new file mode 100644 index 000000000..b1d9b2a37 --- /dev/null +++ b/.changeset/healthy-cycles-visit.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +fix redirection to the Login page after password change diff --git a/core/app/[locale]/(default)/login/_components/change-password-form.tsx b/core/app/[locale]/(default)/login/_components/change-password-form.tsx index e88a9a2fa..25ef1cdb3 100644 --- a/core/app/[locale]/(default)/login/_components/change-password-form.tsx +++ b/core/app/[locale]/(default)/login/_components/change-password-form.tsx @@ -18,6 +18,7 @@ import { Message } from '~/components/ui/message'; import { useRouter } from '~/navigation'; import { submitChangePasswordForm } from '../_actions/submit-change-password-form'; +import { useLoginStatusContext } from './login-status-provider'; interface Props { customerId: string; @@ -51,6 +52,7 @@ export const ChangePasswordForm = ({ customerId, customerToken }: Props) => { const [newPassword, setNewPasssword] = useState(''); const [isConfirmPasswordValid, setIsConfirmPasswordValid] = useState(true); + const { setLoginState } = useLoginStatusContext(); const t = useTranslations('Account.ChangePassword'); let messageText = ''; @@ -59,10 +61,6 @@ export const ChangePasswordForm = ({ customerId, customerToken }: Props) => { messageText = state.message; } - if (state.status === 'success') { - messageText = t('successMessage'); - } - const handleNewPasswordChange = (e: ChangeEvent) => setNewPasssword(e.target.value); const handleConfirmPasswordValidation = (e: ChangeEvent) => { @@ -72,12 +70,13 @@ export const ChangePasswordForm = ({ customerId, customerToken }: Props) => { }; if (state.status === 'success') { - setTimeout(() => router.push('/login'), 2000); + setLoginState({ status: 'success', message: t('confirmChangePassword') }); + router.push('/login'); } return ( <> - {(state.status === 'error' || state.status === 'success') && ( + {state.status === 'error' && (

{messageText}

diff --git a/core/app/[locale]/(default)/login/_components/login-form.tsx b/core/app/[locale]/(default)/login/_components/login-form.tsx index de24ad31a..736fb8c92 100644 --- a/core/app/[locale]/(default)/login/_components/login-form.tsx +++ b/core/app/[locale]/(default)/login/_components/login-form.tsx @@ -18,6 +18,7 @@ import { Input } from '~/components/ui/input'; import { Message } from '~/components/ui/message'; import { submitLoginForm } from '../_actions/submit-login-form'; +import { useLoginStatusContext } from './login-status-provider'; const SubmitButton = () => { const { pending } = useFormStatus(); @@ -39,6 +40,7 @@ export const LoginForm = () => { const [isEmailValid, setIsEmailValid] = useState(true); const [isPasswordValid, setIsPasswordValid] = useState(true); const [state, formAction] = useFormState(submitLoginForm, { status: 'idle' }); + const { loginState } = useLoginStatusContext(); const t = useTranslations('Account.Login'); @@ -62,6 +64,12 @@ export const LoginForm = () => { return ( <> + {loginState.status === 'success' && ( + +

{loginState.message}

+
+ )} + {isFormInvalid && ( LoginState)) => void; +} | null>(null); + +export const LoginStatusProvider = ({ children, isPermanentBanner }: { + children: ReactNode, + isPermanentBanner: ReactNode +}) => { + const [loginState, setLoginState] = useState({status: 'idle', message: ''}); + + if (!isPermanentBanner) { + useEffect(() => { + if (loginState.status !== 'idle') { + setTimeout(() => { + setLoginState({ status: 'idle', message: '' }); + }, 3000); + } + }, [loginState, setLoginState]); + } + + return ( + + {children} + + ) +} + +export function useLoginStatusContext() { + const context = useContext(LoginStatusContext); + + if (!context) { + throw new Error('useLoginStatusContext must be used within a LoginStatusProvider'); + } + + return context; +} diff --git a/core/app/[locale]/(default)/login/_components/reset-password-form/index.tsx b/core/app/[locale]/(default)/login/_components/reset-password-form/index.tsx index ad8ba2342..53c21fc18 100644 --- a/core/app/[locale]/(default)/login/_components/reset-password-form/index.tsx +++ b/core/app/[locale]/(default)/login/_components/reset-password-form/index.tsx @@ -21,6 +21,8 @@ import { Message } from '~/components/ui/message'; import { submitResetPasswordForm } from '../../_actions/submit-reset-password-form'; import { ResetPasswordFormFragment } from './fragment'; +import { useLoginStatusContext } from '../login-status-provider'; +import { useRouter } from 'next/navigation'; interface Props { reCaptchaSettings?: FragmentOf; @@ -58,6 +60,8 @@ export const ResetPasswordForm = ({ reCaptchaSettings }: Props) => { const reCaptchaRef = useRef(null); const [reCaptchaToken, setReCaptchaToken] = useState(''); const [isReCaptchaValid, setReCaptchaValid] = useState(true); + const { setLoginState } = useLoginStatusContext(); + const router = useRouter(); const onReCatpchaChange = (token: string | null) => { if (!token) { @@ -96,10 +100,8 @@ export const ResetPasswordForm = ({ reCaptchaSettings }: Props) => { const customerEmail = formData.get('email'); - setFormStatus({ - status: 'success', - message: t('successMessage', { email: customerEmail?.toString() }), - }); + setLoginState({ status: 'success', message: t('confirmResetPassword', { email: customerEmail?.toString() })}); + router.push('/login') } if (submit.status === 'error') { @@ -111,9 +113,9 @@ export const ResetPasswordForm = ({ reCaptchaSettings }: Props) => { return ( <> - {formStatus && ( - -

{formStatus.message}

+ {formStatus?.status === 'error' && ( + +

{formStatus?.message}

)} diff --git a/core/app/[locale]/(default)/login/layout.tsx b/core/app/[locale]/(default)/login/layout.tsx new file mode 100644 index 000000000..e0b7fdd34 --- /dev/null +++ b/core/app/[locale]/(default)/login/layout.tsx @@ -0,0 +1,10 @@ +import { PropsWithChildren } from 'react'; +import { LoginStatusProvider } from './_components/login-status-provider'; + +export default function LoginLayout({ children }: PropsWithChildren) { + return ( + + {children} + + ) +} diff --git a/core/messages/en.json b/core/messages/en.json index 7c8f6ac28..c0425dbc0 100644 --- a/core/messages/en.json +++ b/core/messages/en.json @@ -259,7 +259,7 @@ "Register": { "heading": "New account", "submit": "Create account", - "submitting": "Creating account...", + "submitting": "Creating account...", "recaptchaText": "Pass ReCAPTCHA check", "successMessage": "Dear {firstName} {lastName}, your account was successfully created. Redirecting to account...", "stateProvincePrefix": "Choose state or province", @@ -286,7 +286,8 @@ "confirmPasswordValidationMessage": "Entered passwords are mismatched. Please try again.", "newPasswordValidationMessage": "New password must be different from the current password or/and match confirm password.", "notEmptyMessage": "Field should not be empty", - "successMessage": "Password has been updated successfully!" + "successMessage": "Password has been updated successfully!", + "confirmChangePassword": "Your password has been successfully updated." }, "SubmitChangePassword": { "spinnerText": "Submitting...", @@ -297,7 +298,8 @@ "emailLabel": "Email", "emailValidationMessage": "Enter a valid email such as name@domain.com", "successMessage": "Your password reset email is on its way to {email}. If you don't see it, check your spam folder.", - "recaptchaText": "Pass ReCAPTCHA check" + "recaptchaText": "Pass ReCAPTCHA check", + "confirmResetPassword": "If the email address {email} is linked to an account in our store, we have sent you a password reset email. Please check your inbox and spam folder if you don't see it." }, "SubmitResetPassword": { "spinnerText": "Submitting...",