Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core): improve redirect behavior after creating account #1088

Merged
merged 1 commit into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/strong-terms-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bigcommerce/catalyst-core": patch
---

improve redirect behavior after creating account
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use client';

import { Message } from '~/components/ui/message';

import { useAccountStatusContext } from './account-status-provider';

interface Props {
message: string;
}

export const AccountNotification = ({ message }: Props) => {
const { accountState } = useAccountStatusContext();

return (
accountState.status === 'success' && (
<Message className="col-span-full mb-8 w-full text-gray-500" variant={accountState.status}>
<p>{message}</p>
</Message>
)
);
};
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
'use client';

import { usePathname } from 'next/navigation';
import { createContext, ReactNode, useContext, useEffect, useState } from 'react';

import { State as AccountState } from '../settings/_actions/submit-customer-change-password-form';

const defaultState: AccountState = { status: 'idle', message: '' };

export const AccountStatusContext = createContext<{
accountState: AccountState;
setAccountState: (state: AccountState | ((prevState: AccountState) => AccountState)) => void;
} | null>(null);

export const AccountStatusProvider = ({
children,
isPermanentBanner = false,
}: {
children: ReactNode;
isPermanentBanner?: boolean;
}) => {
const [accountState, setAccountState] = useState<AccountState>({ status: 'idle', message: '' });
export const AccountStatusProvider = ({ children }: { children: ReactNode }) => {
const [accountState, setAccountState] = useState<AccountState>(defaultState);
const pathname = usePathname();

useEffect(() => {
if (accountState.status !== 'idle' && !isPermanentBanner) {
setTimeout(() => {
setAccountState({ status: 'idle', message: '' });
}, 3000);
// Reset account state when changing the route except the Account Page
if (pathname !== '/account/') {
setAccountState(defaultState);
}
}, [accountState, setAccountState, isPermanentBanner]);
}, [pathname]);

return (
<AccountStatusContext.Provider value={{ accountState, setAccountState }}>
Expand Down
6 changes: 2 additions & 4 deletions core/app/[locale]/(default)/account/(tabs)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { Link } from '~/components/link';
import { LocaleType } from '~/i18n';
import { cn } from '~/lib/utils';

import { AccountStatusProvider } from './_components/account-status-provider';

const tabList = ['addresses', 'settings'] as const;

export type TabType = (typeof tabList)[number];
Expand All @@ -27,7 +25,7 @@ export default function AccountTabLayout({ children, params: { locale } }: Props
};

return (
<AccountStatusProvider isPermanentBanner={true}>
<>
<h1 className="my-8 text-4xl font-black lg:my-8 lg:text-5xl">{t('heading')}</h1>
<nav aria-label={t('accountTabsLabel')}>
<ul className="mb-8 flex items-start overflow-x-auto">
Expand All @@ -46,6 +44,6 @@ export default function AccountTabLayout({ children, params: { locale } }: Props
</ul>
</nav>
{children}
</AccountStatusProvider>
</>
);
}
4 changes: 4 additions & 0 deletions core/app/[locale]/(default)/account/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { ReactNode } from 'react';

import { Link } from '~/components/link';

import { AccountNotification } from './(tabs)/_components/account-notification';

interface AccountItem {
children: ReactNode;
description?: string;
Expand Down Expand Up @@ -33,6 +35,8 @@ export default function Account() {
<div className="mx-auto">
<h1 className="my-8 text-4xl font-black lg:my-8 lg:text-5xl">{t('heading')}</h1>

<AccountNotification message={t('successMessage')} />

<div className="mb-14 grid gap-6 md:grid-cols-2 lg:grid-cols-3">
<AccountItem href="/account/addresses" title={t('addresses')}>
<BookUser className="me-8" size={48} strokeWidth={1.5} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useRouter } from 'next/navigation';
import { useTranslations } from 'next-intl';
import { ChangeEvent, useRef, useState } from 'react';
import { ChangeEvent, useEffect, useRef, useState } from 'react';
import { useFormStatus } from 'react-dom';
import ReCaptcha from 'react-google-recaptcha';

Expand Down Expand Up @@ -63,6 +63,10 @@ export const ResetPasswordForm = ({ reCaptchaSettings }: Props) => {
const { setAccountState } = useAccountStatusContext();
const router = useRouter();

useEffect(() => {
setAccountState({ status: 'idle' });
}, [setAccountState]);

const onReCatpchaChange = (token: string | null) => {
if (!token) {
setReCaptchaValid(false);
Expand Down
7 changes: 0 additions & 7 deletions core/app/[locale]/(default)/login/layout.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ChangeEvent, MouseEvent, useRef, useState } from 'react';
import { useFormStatus } from 'react-dom';
import ReCaptcha from 'react-google-recaptcha';

import { useAccountStatusContext } from '~/app/[locale]/(default)/account/(tabs)/_components/account-status-provider';
import {
createDatesValidationHandler,
createMultilineTextValidationHandler,
Expand Down Expand Up @@ -114,6 +115,8 @@ export const RegisterCustomerForm = ({
const [reCaptchaToken, setReCaptchaToken] = useState('');
const [isReCaptchaValid, setReCaptchaValid] = useState(true);

const { setAccountState } = useAccountStatusContext();

const t = useTranslations('Login.Register');

const handleTextInputValidation = (e: ChangeEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -239,13 +242,7 @@ export const RegisterCustomerForm = ({
const submit = await registerCustomer({ formData, reCaptchaToken });

if (submit.status === 'success') {
setFormStatus({
status: 'success',
message: t('successMessage', {
firstName: submit.data?.firstName,
lastName: submit.data?.lastName,
}),
});
setAccountState({ status: 'success' });

await login(formData);
}
Expand Down
8 changes: 7 additions & 1 deletion core/app/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import { PropsWithChildren } from 'react';

import { CompareDrawerProvider } from '~/components/ui/compare-drawer';

import { AccountStatusProvider } from './[locale]/(default)/account/(tabs)/_components/account-status-provider';

export function Providers({ children }: PropsWithChildren) {
return <CompareDrawerProvider>{children}</CompareDrawerProvider>;
return (
<AccountStatusProvider>
<CompareDrawerProvider>{children}</CompareDrawerProvider>
</AccountStatusProvider>
);
}
3 changes: 2 additions & 1 deletion core/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@
"wishlists": "Wish lists",
"recentlyViewed": "Recently viewed",
"settings": "Account settings",
"changePassword": "Change password"
"changePassword": "Change password",
"successMessage": "Your account has been successfully created"
},
"Addresses": {
"defaultAddress": "Default",
Expand Down
8 changes: 3 additions & 5 deletions core/tests/ui/desktop/e2e/register.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import { test } from '~/tests/fixtures';

// Prefix is added to ensure that the password requirements are met
const password = faker.internet.password({ pattern: /[a-zA-Z0-9]/, prefix: '1At', length: 10 });
const firstName = faker.person.firstName();
const lastName = faker.person.lastName();

test('Account register', async ({ page }) => {
await page.goto('/login');
Expand All @@ -19,8 +17,8 @@ test('Account register', async ({ page }) => {
.fill(faker.internet.email({ provider: 'mybigcommerce.com' }));
await page.getByLabel('PasswordRequired', { exact: true }).fill(password);
await page.getByLabel('Confirm PasswordRequired').fill(password);
await page.getByLabel('First NameRequired').fill(firstName);
await page.getByLabel('Last NameRequired').fill(lastName);
await page.getByLabel('First NameRequired').fill(faker.person.firstName());
await page.getByLabel('Last NameRequired').fill(faker.person.lastName());
await page.getByLabel('Phone Number').fill(faker.phone.number());
await page.getByLabel('Address Line 1Required').fill(faker.location.streetAddress());
await page.getByLabel('Suburb/CityRequired').fill(faker.location.city());
Expand All @@ -29,5 +27,5 @@ test('Account register', async ({ page }) => {
await page.getByRole('button', { name: 'Create account' }).click();

await expect(page).toHaveURL('/account/');
await expect(page.getByRole('heading', { name: 'My Account' })).toBeVisible();
await expect(page.getByText('Your account has been successfully created')).toBeVisible();
});
Loading