Skip to content
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
6 changes: 5 additions & 1 deletion packages/functional-tests/pages/resetPassword.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,14 @@ export class ResetPasswordPage extends BaseLayout {
});
}

get statusBar() {
get successBanner() {
return this.page.getByRole('status');
}

get errorBanner() {
return this.page.getByRole('alert');
}

get createNewPasswordHeading() {
return this.page.getByRole('heading', { name: 'Create new password' });
}
Expand Down
2 changes: 1 addition & 1 deletion packages/functional-tests/tests/oauth/totp.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ test.describe('severity-1 #smoke', () => {
const { secret } = await totp.fillOutTotpForms();
await expect(settings.settingsHeading).toBeVisible();
await expect(settings.alertBar).toHaveText(
'Two-step authentication enabled'
'Two-step authentication has been enabled'
);
await expect(settings.totp.status).toHaveText('Enabled');
await settings.signOut();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ test.describe('severity-1 #smoke', () => {

await expect(settings.settingsHeading).toBeVisible();
await expect(settings.alertBar).toHaveText(
'Two-step authentication enabled'
'Two-step authentication has been enabled'
);
await expect(settings.totp.status).toHaveText('Enabled');

Expand Down Expand Up @@ -78,7 +78,7 @@ test.describe('severity-1 #smoke', () => {

await expect(settings.settingsHeading).toBeVisible();
await expect(settings.alertBar).toHaveText(
'Two-step authentication enabled'
'Two-step authentication has been enabled'
);
await expect(settings.totp.status).toHaveText('Enabled');

Expand Down Expand Up @@ -122,7 +122,7 @@ test.describe('severity-1 #smoke', () => {

await expect(settings.settingsHeading).toBeVisible();
await expect(settings.alertBar).toHaveText(
'Two-step authentication enabled'
'Two-step authentication has been enabled'
);
await expect(settings.totp.status).toHaveText('Enabled');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ test.describe('severity-1 #smoke', () => {

resetPassword.resendButton.click();

await expect(resetPassword.statusBar).toHaveText(
await expect(resetPassword.successBanner).toHaveText(
/A new code was sent to your email./
);
});
Expand All @@ -121,7 +121,7 @@ test.describe('severity-1 #smoke', () => {

await resetPassword.fillOutEmailForm('email@restmail.net');

await expect(resetPassword.statusBar).toHaveText('Unknown account');
await expect(resetPassword.errorBanner).toHaveText('Unknown account');
});

test('browse directly to page with email on query params', async ({
Expand Down Expand Up @@ -161,7 +161,7 @@ test.describe('severity-1 #smoke', () => {

await expect(settings.settingsHeading).toBeVisible();
await expect(settings.alertBar).toHaveText(
'Two-step authentication enabled'
'Two-step authentication has been enabled'
);
await expect(settings.totp.status).toHaveText('Enabled');

Expand Down Expand Up @@ -226,7 +226,7 @@ test.describe('severity-1 #smoke', () => {

await expect(settings.settingsHeading).toBeVisible();
await expect(settings.alertBar).toHaveText(
'Two-step authentication enabled'
'Two-step authentication has been enabled'
);
await expect(settings.totp.status).toHaveText('Enabled');

Expand Down Expand Up @@ -300,7 +300,7 @@ test.describe('severity-1 #smoke', () => {

await expect(settings.settingsHeading).toBeVisible();
await expect(settings.alertBar).toHaveText(
'Two-step authentication enabled'
'Two-step authentication has been enabled'
);
await expect(settings.totp.status).toHaveText('Enabled');

Expand Down Expand Up @@ -385,7 +385,7 @@ test.describe('severity-1 #smoke', () => {

await expect(settings.settingsHeading).toBeVisible();
await expect(settings.alertBar).toHaveText(
'Two-step authentication enabled'
'Two-step authentication has been enabled'
);
await expect(settings.totp.status).toHaveText('Enabled');

Expand Down
6 changes: 4 additions & 2 deletions packages/functional-tests/tests/settings/totp.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ test.describe('severity-1 #smoke', () => {

await expect(settings.settingsHeading).toBeVisible();
await expect(settings.alertBar).toHaveText(
'Two-step authentication enabled'
'Two-step authentication has been enabled'
);
await expect(settings.totp.status).toHaveText('Enabled');

Expand Down Expand Up @@ -343,7 +343,9 @@ async function addTotp(
const totpCredentials = await totp.fillOutTotpForms();

await expect(settings.settingsHeading).toBeVisible();
await expect(settings.alertBar).toHaveText('Two-step authentication enabled');
await expect(settings.alertBar).toHaveText(
'Two-step authentication has been enabled'
);
await expect(settings.totp.status).toHaveText('Enabled');

return totpCredentials;
Expand Down
15 changes: 15 additions & 0 deletions packages/fxa-settings/src/components/Banner/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,21 @@ export const TypeInfo = () => (
</AppLayout>
);

export const TypeInfoFancy = () => (
<AppLayout>
<Banner
type="info"
isFancy
content={{
localizedHeading: sampleHeading,
localizedDescription: sampleDescription,
}}
link={{ url: '#', localizedText: sampleCtaText }}
dismissButton={{ action: () => alert('Dismiss clicked') }}
/>
</AppLayout>
);

export const TypeSuccess = () => (
<AppLayout>
<Banner
Expand Down
8 changes: 0 additions & 8 deletions packages/fxa-settings/src/components/Banner/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,24 @@ describe('Banner Component', () => {
render(<Banner {...getDefaultProps()} />);
expect(screen.getByText('Heading')).toBeInTheDocument();
expect(screen.getByText('This is a description')).toBeInTheDocument();
expect(
screen.getByRole('img', { name: /Information/i })
).toBeInTheDocument();
});

it('renders the component with error type', () => {
render(<Banner {...getDefaultProps('error')} />);
expect(screen.getByText('Heading')).toBeInTheDocument();
expect(screen.getByText('This is a description')).toBeInTheDocument();
expect(screen.getByRole('img', { name: /Error/i })).toBeInTheDocument();
});

it('renders the component with success type', () => {
render(<Banner {...getDefaultProps('success')} />);
expect(screen.getByText('Heading')).toBeInTheDocument();
expect(screen.getByText('This is a description')).toBeInTheDocument();
expect(screen.getByRole('img', { name: /Success/i })).toBeInTheDocument();
});

it('renders the component with warning type', () => {
render(<Banner {...getDefaultProps('warning')} />);
expect(screen.getByText('Heading')).toBeInTheDocument();
expect(screen.getByText('This is a description')).toBeInTheDocument();
expect(
screen.getByRole('img', { name: 'Attention' })
).toBeInTheDocument();
});
});

Expand Down
32 changes: 26 additions & 6 deletions packages/fxa-settings/src/components/Banner/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
InformationOutlineCurrentIcon as InfoIcon,
AlertOutlineCurrentIcon as WarningIcon,
ErrorOutlineCurrentIcon as ErrorIcon,
InformationOutlineBlueIcon,
} from '../Icons';
import classNames from 'classnames';
import { useFtlMsgResolver } from '../../models';
Expand All @@ -23,31 +24,45 @@ export const Banner = ({
animation,
dismissButton,
link,
isFancy,
bannerId,
}: BannerProps) => {
return (
<div
id={bannerId || ''}
className={classNames(
'my-4 flex flex-row no-wrap items-center px-4 py-3 gap-3.5 rounded-md border border-transparent text-start text-sm',
type === 'error' && 'bg-red-100',
type === 'info' && 'bg-blue-50',
type === 'info' && !isFancy && 'bg-blue-50',
type === 'info' &&
isFancy &&
'bg-gradient-to-tr from-blue-600/10 to-purple-500/10',
type === 'success' && 'bg-green-200',
type === 'warning' && 'bg-orange-50',
animation?.animate && animation?.className
)}
role="status"
role={type === 'error' ? 'alert' : 'status'}
aria-live={type === 'error' ? 'assertive' : 'polite'}
onAnimationEnd={animation?.handleAnimationEnd}
tabIndex={-1}
>
{/* Icon fills use 'currentColor' (from text color) for better accessibility in HCM mode */}
{type === 'error' && <ErrorIcon className="shrink-0" />}
{type === 'info' && <InfoIcon className="shrink-0" />}
{type === 'error' && <ErrorIcon className="shrink-0" ariaHidden />}
{type === 'info' && !isFancy && (
<InfoIcon className="shrink-0" ariaHidden />
)}
{type === 'info' && isFancy && (
<InformationOutlineBlueIcon className="shrink-0" ariaHidden />
)}
{type === 'success' && (
<CheckmarkCircleOutlineCurrentIcon
className="shrink-0"
mode="success"
ariaHidden
/>
)}
{type === 'warning' && (
<WarningIcon className="shrink-0" mode="attention" />
<WarningIcon className="shrink-0" mode="attention" ariaHidden />
)}

<div className="flex flex-col grow ">
Expand Down Expand Up @@ -86,7 +101,12 @@ export const Banner = ({
className={classNames(
'shrink-0 self-start hover:backdrop-saturate-150 focus:backdrop-saturate-200',
type === 'error' && 'hover:bg-red-200 focus:bg-red-300',
type === 'info' && 'hover:bg-blue-100 focus:bg-blue-200',
type === 'info' &&
!isFancy &&
'hover:bg-blue-100 focus:bg-blue-200',
type === 'info' &&
isFancy &&
'hover:bg-gradient-to-tr hover:from-blue-700/10 hover:to-purple-600/10 focus:bg-gradient-to-tr focus:from-blue-800/10 focus:to-purple-700/10',
type === 'success' && 'hover:bg-green-400 focus:bg-green-500',
type === 'warning' && 'hover:bg-orange-100 focus:bg-orange-200'
)}
Expand Down
2 changes: 2 additions & 0 deletions packages/fxa-settings/src/components/Banner/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export type BannerProps = {
animation?: Animation;
dismissButton?: DismissButtonProps;
link?: BannerLinkProps;
isFancy?: boolean;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bannerId?: string;
};

export type Animation = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,55 @@ import React from 'react';
import FormPhoneNumber from '.';
import { withLocalization } from 'fxa-react/lib/storybooks';
import { Meta } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import AppLayout from '../AppLayout';

export default {
title: 'Components/FormPhoneNumber',
component: FormPhoneNumber,
decorators: [withLocalization],
decorators: [
(Story) => (
<AppLayout>
<Story />
</AppLayout>
),
withLocalization,
],
} as Meta;

const mockSubmit = async (phoneNumber: string) => {
action('submitPhoneNumber')(phoneNumber);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But really - I haven't played with this enough, seems cool!

return { hasErrors: false };
};

export const Default = () => (
<AppLayout>
<FormPhoneNumber localizedCTAText="Send code" />
</AppLayout>
<FormPhoneNumber
localizedCTAText="Send code"
submitPhoneNumber={mockSubmit}
/>
);

export const WithError = () => (
<FormPhoneNumber
localizedCTAText="Send code"
submitPhoneNumber={async () => {
action('submitPhoneNumber')();
return { hasErrors: true };
}}
/>
);

export const WithInfo = () => (
<AppLayout>
<FormPhoneNumber showInfo localizedCTAText="Confirm" />
</AppLayout>
export const WithInfoBanner = () => (
<FormPhoneNumber
infoBannerContent={{
localizedDescription: 'This is a description',
localizedHeading: 'This is a heading',
}}
infoBannerLink={{
localizedText: 'This is a link',
path: '#',
}}
localizedCTAText="Confirm"
submitPhoneNumber={mockSubmit}
/>
);
Loading