Skip to content

Commit 1144857

Browse files
Merge pull request #18912 from mozilla/FXA-10209
feat(2fa): Update design of DataBlock and GetDataTrio components
2 parents 920a45e + 0c83b61 commit 1144857

36 files changed

Lines changed: 296 additions & 214 deletions

File tree

packages/functional-tests/pages/settings/totp.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class TotpPage extends SettingsLayout {
3434
}
3535

3636
get step1ManualCode() {
37-
return this.page.getByTestId('manual-code');
37+
return this.page.getByTestId('manual-datablock');
3838
}
3939

4040
get step1QRCode() {
@@ -116,8 +116,11 @@ export class TotpPage extends SettingsLayout {
116116
}
117117

118118
async getRecoveryCodes(): Promise<string[]> {
119-
const codesRaw = await this.step2recoveryCodes.textContent();
120-
return codesRaw ? codesRaw.trim().split(/\s+/) : [];
119+
await expect(this.step2recoveryCodes).toBeVisible();
120+
const codeList = await this.step2recoveryCodes
121+
.getByRole('listitem')
122+
.allTextContents();
123+
return codeList ? codeList : [];
121124
}
122125

123126
async fillOutStep2Form(): Promise<string[]> {

packages/functional-tests/tests/oauth/totp.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ test.describe('severity-1 #smoke', () => {
106106
await expect(signin.page.getByText('Enter code manually')).toBeVisible();
107107

108108
const secret = (
109-
await signin.page.getByTestId('manual-code').innerText()
109+
await signin.page.getByTestId('manual-datablock').innerText()
110110
)?.replace(/\s/g, '');
111111
const code = await getCode(secret);
112112

packages/fxa-settings/src/components/BrandMessaging/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ export const BrandMessaging = ({
151151
<div className="flex justify-end mx-2 my-1 ms-auto">
152152
<FtlMsg
153153
id="brand-banner-dismiss-button-2"
154-
attrs={{ ariaLabel: true }}
154+
attrs={{ 'aria-label': true }}
155155
>
156156
<button
157157
className="w-4 h-4 rounded-sm focus-visible-default outline-offset-2"
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading

packages/fxa-settings/src/components/DataBlock/index.stories.tsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,21 @@ export default {
1414
decorators: [withLocalization],
1515
} as Meta;
1616

17-
export const SingleCodeInlineCopy = () => <Subject isInline />;
18-
1917
export const SingleCode = () => <Subject />;
2018

2119
export const SingleCodeOnIOS = () => <Subject isIOS />;
2220

2321
export const MultipleCodes = () => (
2422
<Subject
2523
value={[
26-
'C1OFZW7R04',
27-
'XVKRLKERT4',
28-
'CF0V94X204',
29-
'C3THX2SGZ4',
30-
'UXC6NRQT54',
31-
'24RF9WFA44',
32-
'ZBULPFN7J4',
33-
'D4J6KY8FL4',
24+
'c1ofzw7r04',
25+
'xvkrlkert4',
26+
'cf0v94x204',
27+
'c3thx2sgz4',
28+
'uxc6nrqt54',
29+
'24rf9wfa44',
30+
'zbulpfn7j4',
31+
'd4j6ky8fl4',
3432
]}
3533
/>
3634
);

packages/fxa-settings/src/components/DataBlock/index.test.tsx

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import React from 'react';
66
import { fireEvent, screen } from '@testing-library/react';
77
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
8-
import { act } from 'react-dom/test-utils';
98
import { Subject } from './mocks';
109

1110
const singleValue = 'ANMD 1S09 7Y2Y 4EES 02CW BJ6Z PYKP H69F';
@@ -38,18 +37,8 @@ it('can render multiple values', () => {
3837
});
3938
});
4039

41-
it('can apply spacing to multiple values', () => {
42-
renderWithLocalizationProvider(<Subject value={multiValue} separator=" " />);
43-
44-
expect(screen.getByTestId('datablock').textContent?.trim()).toEqual(
45-
multiValue.join(' ')
46-
);
47-
});
48-
4940
it('displays only Copy icon in iOS', () => {
50-
renderWithLocalizationProvider(
51-
<Subject value={multiValue} separator=" " isIOS />
52-
);
41+
renderWithLocalizationProvider(<Subject value={multiValue} isIOS />);
5342

5443
expect(screen.getByRole('button', { name: 'Copy' })).toBeInTheDocument();
5544
expect(
@@ -62,9 +51,7 @@ it('displays only Copy icon in iOS', () => {
6251

6352
it('displays a tooltip on action', async () => {
6453
renderWithLocalizationProvider(<Subject value={multiValue} />);
65-
await act(async () => {
66-
fireEvent.click(await screen.findByTestId('databutton-copy'));
67-
});
54+
fireEvent.click(await screen.findByTestId('databutton-copy'));
6855
expect(
6956
await screen.findByTestId('datablock-copy-tooltip')
7057
).toBeInTheDocument();

packages/fxa-settings/src/components/DataBlock/index.tsx

Lines changed: 23 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import React, { useState } from 'react';
66
import GetDataTrio, {
77
DownloadContentType,
88
GetDataCopySingleton,
9-
GetDataCopySingletonInline,
109
GetDataTrioGleanData,
1110
} from '../GetDataTrio';
1211
import { Tooltip } from '../Tooltip';
1312
import { FtlMsg } from 'fxa-react/lib/utils';
1413
import classNames from 'classnames';
14+
import { ReactComponent as CodeIcon } from './code.min.svg';
1515
const actionTypeToNotification = {
1616
download: 'Downloaded',
1717
copy: 'Copied',
@@ -25,11 +25,9 @@ export type DataBlockProps = {
2525
value: string | string[];
2626
contentType?: DownloadContentType;
2727
prefixDataTestId?: string;
28-
separator?: string;
29-
onCopy?: (event: React.ClipboardEvent<HTMLDivElement>) => void;
28+
onCopy?: (event: React.ClipboardEvent<HTMLElement>) => void;
3029
onAction?: actionFn;
3130
isIOS?: boolean;
32-
isInline?: boolean;
3331
email: string;
3432
gleanDataAttrs: {
3533
copy?: GetDataTrioGleanData;
@@ -42,11 +40,9 @@ export const DataBlock = ({
4240
value,
4341
contentType,
4442
prefixDataTestId,
45-
separator,
4643
onCopy,
4744
onAction = () => {},
4845
isIOS = false,
49-
isInline = false,
5046
email,
5147
gleanDataAttrs,
5248
}: DataBlockProps) => {
@@ -65,58 +61,40 @@ export const DataBlock = ({
6561
};
6662

6763
return (
68-
<div className="flex flex-col items-center">
69-
<div
64+
<div className="w-full flex flex-col gap-3 items-center bg-white rounded-xl border-2 border-grey-100 px-5 pt-5 pb-3">
65+
<ul
7066
className={classNames(
71-
'relative flex font-mono text-center text-sm font-bold text-black bg-gradient-to-tr from-blue-600/10 to-purple-500/10 border border-transparent',
72-
valueIsArray ? 'max-w-sm' : 'max-w-lg',
73-
isInline
74-
? 'flex-nowrap w-full rounded py-2 px-3'
75-
: 'flex-wrap mb-8 rounded-lg px-6 py-4'
67+
'relative gap-2 w-full text-black text-sm font-mono font-bold',
68+
valueIsArray ? 'grid grid-cols-2 max-w-sm' : 'flex flex-col max-w-lg'
7669
)}
77-
data-testid={dataTestId}
7870
{...{ onCopy }}
71+
data-testid={dataTestId}
7972
>
80-
{valueIsArray ? (
81-
(value as string[]).map((item) => (
82-
<span key={item} className="flex-50% py-1">
83-
{item}
84-
{separator || ''}
85-
</span>
86-
))
87-
) : (
88-
<span
89-
className={classNames({
90-
'flex flex-col self-center align-middle grow': isInline,
91-
})}
73+
{(valueIsArray ? value : [value]).map((item) => (
74+
<li
75+
key={item}
76+
className="px-3 py-[10px] flex items-center gap-3 rounded-lg bg-gradient-to-tr from-blue-600/10 to-purple-500/10 text-center justify-center mobileLandscape:justify-start"
9277
>
93-
{value}
94-
</span>
95-
)}
78+
<CodeIcon
79+
className="w-6 h-auto hidden mobileLandscape:block"
80+
aria-hidden
81+
/>
82+
{item}
83+
</li>
84+
))}
9685
{performedAction && tooltipVisible && (
9786
<FtlMsg id={`datablock-${performedAction}`} attrs={{ message: true }}>
9887
<Tooltip
9988
prefixDataTestId={`datablock-${performedAction}`}
10089
message={actionTypeToNotification[performedAction]}
101-
anchorPosition={isInline ? 'end' : 'middle'}
102-
position={isInline ? 'top' : 'bottom'}
90+
anchorPosition="middle"
91+
position="bottom"
10392
className="mt-1"
10493
></Tooltip>
10594
</FtlMsg>
10695
)}
107-
{isInline && (
108-
<GetDataCopySingletonInline
109-
{...{
110-
value,
111-
onAction: actionCb,
112-
setTooltipVisible,
113-
email,
114-
gleanDataAttrs,
115-
}}
116-
/>
117-
)}
118-
</div>
119-
{isIOS && !isInline && (
96+
</ul>
97+
{isIOS ? (
12098
<GetDataCopySingleton
12199
{...{
122100
value,
@@ -126,8 +104,7 @@ export const DataBlock = ({
126104
gleanDataAttrs,
127105
}}
128106
/>
129-
)}
130-
{!isIOS && !isInline && (
107+
) : (
131108
<GetDataTrio
132109
{...{
133110
value,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Tooltip notification when an account recovery key or one-time use code is copied.
2+
datablock-inline-copy =
3+
.message = Copied

packages/fxa-settings/src/components/DataBlockManual/index.stories.tsx renamed to packages/fxa-settings/src/components/DataBlockInline/index.stories.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
import React from 'react';
66
import { Meta } from '@storybook/react';
77
import { withLocalization } from 'fxa-react/lib/storybooks';
8-
import DataBlockManual from '.';
8+
import { Subject } from './mocks';
9+
import DataBlockInline from '.';
910

1011
export default {
11-
title: 'Components/DataBlockManual',
12-
component: DataBlockManual,
12+
title: 'Components/DataBlockInline',
13+
component: DataBlockInline,
1314
decorators: [withLocalization],
1415
} as Meta;
1516

16-
export const Default = () => (
17-
<DataBlockManual secret={'MMMMOOOOZZZZIIIILLLLLLLLAAAAYAAY'} />
18-
);
17+
export const SingleCodeInlineCopy = () => <Subject />;

0 commit comments

Comments
 (0)