1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 18:00:18 +01:00

Merge pull request #18102 from MetaMask/fix/599-fix-theme-issues-of-desktop-pairing-page-in-the-extension-ui

fix: fix theme issues of desktop pairing page
This commit is contained in:
OGPoyraz 2023-03-29 10:58:17 +02:00 committed by GitHub
commit f32d71ba1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 417 additions and 301 deletions

View File

@ -121,12 +121,17 @@ export async function getErrorHtml(
} }
///: BEGIN:ONLY_INCLUDE_IN(flask) ///: BEGIN:ONLY_INCLUDE_IN(flask)
export const MMD_DOWNLOAD_LINK =
'https://github.com/MetaMask/metamask-desktop/releases';
function disableDesktop(backgroundConnection) { function disableDesktop(backgroundConnection) {
backgroundConnection.disableDesktopError(); backgroundConnection.disableDesktopError();
} }
export function downloadDesktopApp() { export function downloadDesktopApp() {
global.platform.openTab({ url: 'https://metamask.io/' }); global.platform.openTab({
url: MMD_DOWNLOAD_LINK,
});
} }
export function downloadExtension() { export function downloadExtension() {
@ -139,7 +144,7 @@ export function restartExtension() {
export function openOrDownloadMMD() { export function openOrDownloadMMD() {
openCustomProtocol('metamask-desktop://pair').catch(() => { openCustomProtocol('metamask-desktop://pair').catch(() => {
window.open('https://metamask.io/download.html', '_blank').focus(); window.open(MMD_DOWNLOAD_LINK, '_blank').focus();
}); });
} }

View File

@ -1,13 +1,48 @@
import browser from 'webextension-polyfill';
import { fetchLocale } from '../../ui/helpers/utils/i18n-helper'; import { fetchLocale } from '../../ui/helpers/utils/i18n-helper';
import { SUPPORT_LINK } from './ui-utils'; import { SUPPORT_LINK } from './ui-utils';
import { getErrorHtml } from './error-utils'; import {
downloadDesktopApp,
openOrDownloadMMD,
downloadExtension,
getErrorHtml,
restartExtension,
registerDesktopErrorActions,
MMD_DOWNLOAD_LINK,
} from './error-utils';
import { openCustomProtocol } from './deep-linking';
jest.mock('../../ui/helpers/utils/i18n-helper', () => ({ jest.mock('../../ui/helpers/utils/i18n-helper', () => ({
fetchLocale: jest.fn(), fetchLocale: jest.fn(),
loadRelativeTimeFormatLocaleData: jest.fn(), loadRelativeTimeFormatLocaleData: jest.fn(),
})); }));
jest.mock('./deep-linking', () => ({
openCustomProtocol: jest.fn(),
}));
jest.mock('webextension-polyfill', () => {
return {
runtime: {
reload: jest.fn(),
},
};
});
describe('Error utils Tests', function () { describe('Error utils Tests', function () {
beforeEach(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
global.platform = {
openTab: jest.fn(),
};
});
afterAll(() => {
jest.clearAllMocks();
jest.restoreAllMocks();
delete global.platform;
});
it('should get error html', async function () { it('should get error html', async function () {
const mockStore = { const mockStore = {
localeMessages: { localeMessages: {
@ -50,4 +85,93 @@ describe('Error utils Tests', function () {
expect(errorHtml).toContain(stillGettingMessageMessage); expect(errorHtml).toContain(stillGettingMessageMessage);
expect(errorHtml).toContain(sendBugReportMessage); expect(errorHtml).toContain(sendBugReportMessage);
}); });
describe('desktop', () => {
it('downloadDesktopApp opens a new tab on metamask-desktop releases url', () => {
downloadDesktopApp();
expect(global.platform.openTab).toHaveBeenCalledTimes(1);
expect(global.platform.openTab).toHaveBeenCalledWith({
url: MMD_DOWNLOAD_LINK,
});
});
it('downloadExtension opens a new tab on metamask extension url', () => {
downloadExtension();
expect(global.platform.openTab).toHaveBeenCalledTimes(1);
expect(global.platform.openTab).toHaveBeenCalledWith({
url: 'https://metamask.io/',
});
});
it('restartExtension calls runtime reload method', () => {
restartExtension();
expect(browser.runtime.reload).toHaveBeenCalledTimes(1);
});
describe('openOrDownloadMMD', () => {
it('launches installed desktop app by calling openCustomProtocol successfully', () => {
openCustomProtocol.mockResolvedValue();
openOrDownloadMMD();
expect(openCustomProtocol).toHaveBeenCalledTimes(1);
expect(openCustomProtocol).toHaveBeenCalledWith(
'metamask-desktop://pair',
);
});
it('opens metamask-desktop release url when fails to find and start a local metamask-desktop app', async () => {
openCustomProtocol.mockRejectedValue();
const focusMock = jest.fn();
jest.spyOn(window, 'open').mockReturnValue({
focus: focusMock,
});
openOrDownloadMMD();
// this ensures that we are awaiting for pending promises to resolve
// as the openOrDownloadMMD calls a promise, but returns before it is resolved
await new Promise(process.nextTick);
expect(openCustomProtocol).toHaveBeenCalledTimes(1);
expect(openCustomProtocol).toHaveBeenCalledWith(
'metamask-desktop://pair',
);
expect(window.open).toHaveBeenCalledTimes(1);
expect(window.open).toHaveBeenCalledWith(MMD_DOWNLOAD_LINK, '_blank');
expect(focusMock).toHaveBeenCalledTimes(1);
});
});
it('registerDesktopErrorActions add click event listeners for each desktop error elements', async () => {
const addEventListenerMock = jest.fn();
jest.spyOn(document, 'getElementById').mockReturnValue({
addEventListener: addEventListenerMock,
});
registerDesktopErrorActions();
expect(document.getElementById).toHaveBeenCalledTimes(4);
expect(document.getElementById).toHaveBeenNthCalledWith(
1,
'desktop-error-button-disable-mmd',
);
expect(document.getElementById).toHaveBeenNthCalledWith(
2,
'desktop-error-button-restart-mm',
);
expect(document.getElementById).toHaveBeenNthCalledWith(
3,
'desktop-error-button-download-mmd',
);
expect(document.getElementById).toHaveBeenNthCalledWith(
4,
'desktop-error-button-open-or-download-mmd',
);
expect(addEventListenerMock).toHaveBeenCalledTimes(4);
});
});
}); });

View File

@ -3,139 +3,134 @@
exports[`Desktop Pairing page should render otp component 1`] = ` exports[`Desktop Pairing page should render otp component 1`] = `
<div> <div>
<div <div
class="page-container__content" class="box box--margin-right-2 box--margin-left-2 box--display-flex box--flex-direction-column box--align-items-center"
> >
<div <div
class="desktop-pairing" class="box box--margin-top-8 box--margin-bottom-8 box--display-flex box--flex-direction-row box--justify-content-center"
> >
<div> <svg
<div class="desktop-pairing__icon"
class="box box--margin-top-12 box--margin-right-6 box--margin-left-6 box--display-flex box--flex-direction-column box--align-items-center box--text-align-center" fill="currentColor"
> height="64"
<svg viewBox="0 0 64 39"
fill="currentColor" width="64"
height="64" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 64 39"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2.05588 38.7539L2.05764 38.7541H40.952H40.9539C40.9557 38.7541 40.9573 38.7536 40.9591 38.7536C42.0608 38.7497 43.0116 37.8498 43.0116 36.6965C43.0112 35.5025 43.0127 41.0218 43.0084 25.0192H41.7318V32.2147H1.27784V8.06471H41.7318V13.7349H43.0084C43.0088 12.6803 43.0073 17.5546 43.0116 3.42458C43.0116 2.33886 42.1096 1.3715 40.9592 1.36749C40.9574 1.36749 40.9557 1.36694 40.9539 1.36694H40.952H2.05826L2.05592 1.3671C0.938953 1.36848 0 2.2928 0 3.42458C0.00118187 40.1604 0.00115779 35.5443 0.00151939 36.7115C0.00442983 37.7954 0.916013 38.7525 2.05588 38.7539ZM40.952 2.64354C40.9545 2.64354 40.9568 2.64459 40.9593 2.64463C41.3592 2.6475 41.7318 2.97087 41.7318 3.42396V6.78811H1.27784V3.42396C1.27784 3.4215 1.27776 3.42143 1.27773 3.41905C1.28066 3.03143 1.60496 2.64481 2.05596 2.64389L2.05826 2.64354H40.952ZM41.7318 33.4913V36.6971C41.7318 37.1484 41.3421 37.4739 40.959 37.4765C40.9566 37.4765 40.9545 37.4775 40.952 37.4775H2.05826L2.05588 37.4772C1.67874 37.4762 1.2822 37.1511 1.278 36.7035C1.278 36.7013 1.27784 36.6993 1.27784 36.6971V33.4913H41.7318Z"
fill="black"
/>
<path
d="M8.2473 4.07751H3.19141V5.35411H8.2473V4.07751Z"
fill="black"
/>
<path
d="M23.5665 34.8462H18.5106V36.1228H23.5665V34.8462Z"
fill="black"
/>
<path
d="M36.5719 5.16847C36.8185 4.92251 36.8186 4.50823 36.5719 4.26214C36.3294 4.0259 35.9018 4.03244 35.6656 4.26214C35.4197 4.52205 35.4195 4.90836 35.6656 5.16847C35.9317 5.42024 36.3318 5.40917 36.5719 5.16847Z"
fill="black"
/>
<path
d="M58.7234 1.98595V5.13942H44.305V6.41602H58.7234V29.2623H44.305V30.5389H58.7234V33.544C58.7234 33.9351 58.408 34.2533 58.0203 34.2533H44.305V35.5299H58.0203C59.1117 35.5299 60 34.6392 60 33.544C60 26.776 60 9.50087 60 1.98595V1.97972C60 0.888256 59.1117 0 58.0203 0H42.8152V1.2766H58.0203C58.408 1.2766 58.7234 1.59481 58.7234 1.98595Z"
fill="black"
/>
<path
d="M51.0488 2.56812H46.2522V3.84471H51.0488V2.56812Z"
fill="black"
/>
<path
d="M51.0488 31.7573H46.2522V33.0339H51.0488V31.7573Z"
fill="black"
/>
<path
d="M53.8826 3.65558C54.1329 3.4194 54.1259 2.98539 53.8826 2.7558C53.6463 2.51955 53.2125 2.51955 52.9762 2.7558C52.7244 3.02196 52.7345 3.41386 52.9762 3.65558C53.236 3.91538 53.6465 3.90578 53.8826 3.65558Z"
fill="black"
/>
<path
d="M37.2794 13.3285L34.9387 15.6694L37.2794 18.0101L38.1819 17.1075L37.3822 16.3077H48.899V15.0311H37.382L38.1819 14.2311L37.2794 13.3285Z"
fill="black"
/>
<path
d="M46.5582 24.5231L47.4608 25.4257L49.8015 23.0848L47.4608 20.7441L46.5582 21.6467L47.358 22.4465H35.8412V23.7231H47.3581L46.5582 24.5231Z"
fill="black"
/>
<path
d="M33.8298 12.7659H8.29785V14.0425H33.8298V12.7659Z"
fill="black"
/>
<path
d="M33.8298 15.9574H8.29785V17.234H33.8298V15.9574Z"
fill="black"
/>
<path
d="M33.8298 19.7874H8.29785V21.0639H33.8298V19.7874Z"
fill="black"
/>
<path
d="M33.8298 22.9788H8.29785V24.2554H33.8298V22.9788Z"
fill="black"
/>
<path
d="M57.0254 12.6194H51.0127V13.896H57.0254V12.6194Z"
fill="black"
/>
<path
d="M57.0254 16.0691H51.0127V17.3457H57.0254V16.0691Z"
fill="black"
/>
<path
d="M57.0254 19.5188H51.0127V20.7954H57.0254V19.5188Z"
fill="black"
/>
<path
d="M57.0254 22.9688H51.0127V24.2453H57.0254V22.9688Z"
fill="black"
/>
</svg>
</div>
</div>
<div
class="desktop-pairing__title"
> >
Pair with Desktop <path
</div> d="M2.05588 38.7539L2.05764 38.7541H40.952H40.9539C40.9557 38.7541 40.9573 38.7536 40.9591 38.7536C42.0608 38.7497 43.0116 37.8498 43.0116 36.6965C43.0112 35.5025 43.0127 41.0218 43.0084 25.0192H41.7318V32.2147H1.27784V8.06471H41.7318V13.7349H43.0084C43.0088 12.6803 43.0073 17.5546 43.0116 3.42458C43.0116 2.33886 42.1096 1.3715 40.9592 1.36749C40.9574 1.36749 40.9557 1.36694 40.9539 1.36694H40.952H2.05826L2.05592 1.3671C0.938953 1.36848 0 2.2928 0 3.42458C0.00118187 40.1604 0.00115779 35.5443 0.00151939 36.7115C0.00442983 37.7954 0.916013 38.7525 2.05588 38.7539ZM40.952 2.64354C40.9545 2.64354 40.9568 2.64459 40.9593 2.64463C41.3592 2.6475 41.7318 2.97087 41.7318 3.42396V6.78811H1.27784V3.42396C1.27784 3.4215 1.27776 3.42143 1.27773 3.41905C1.28066 3.03143 1.60496 2.64481 2.05596 2.64389L2.05826 2.64354H40.952ZM41.7318 33.4913V36.6971C41.7318 37.1484 41.3421 37.4739 40.959 37.4765C40.9566 37.4765 40.9545 37.4775 40.952 37.4775H2.05826L2.05588 37.4772C1.67874 37.4762 1.2822 37.1511 1.278 36.7035C1.278 36.7013 1.27784 36.6993 1.27784 36.6971V33.4913H41.7318Z"
<div fill="black"
class="desktop-pairing__subtitle" />
> <path
Open your MetaMask Desktop and type this code d="M8.2473 4.07751H3.19141V5.35411H8.2473V4.07751Z"
</div> fill="black"
/>
<path
d="M23.5665 34.8462H18.5106V36.1228H23.5665V34.8462Z"
fill="black"
/>
<path
d="M36.5719 5.16847C36.8185 4.92251 36.8186 4.50823 36.5719 4.26214C36.3294 4.0259 35.9018 4.03244 35.6656 4.26214C35.4197 4.52205 35.4195 4.90836 35.6656 5.16847C35.9317 5.42024 36.3318 5.40917 36.5719 5.16847Z"
fill="black"
/>
<path
d="M58.7234 1.98595V5.13942H44.305V6.41602H58.7234V29.2623H44.305V30.5389H58.7234V33.544C58.7234 33.9351 58.408 34.2533 58.0203 34.2533H44.305V35.5299H58.0203C59.1117 35.5299 60 34.6392 60 33.544C60 26.776 60 9.50087 60 1.98595V1.97972C60 0.888256 59.1117 0 58.0203 0H42.8152V1.2766H58.0203C58.408 1.2766 58.7234 1.59481 58.7234 1.98595Z"
fill="black"
/>
<path
d="M51.0488 2.56812H46.2522V3.84471H51.0488V2.56812Z"
fill="black"
/>
<path
d="M51.0488 31.7573H46.2522V33.0339H51.0488V31.7573Z"
fill="black"
/>
<path
d="M53.8826 3.65558C54.1329 3.4194 54.1259 2.98539 53.8826 2.7558C53.6463 2.51955 53.2125 2.51955 52.9762 2.7558C52.7244 3.02196 52.7345 3.41386 52.9762 3.65558C53.236 3.91538 53.6465 3.90578 53.8826 3.65558Z"
fill="black"
/>
<path
d="M37.2794 13.3285L34.9387 15.6694L37.2794 18.0101L38.1819 17.1075L37.3822 16.3077H48.899V15.0311H37.382L38.1819 14.2311L37.2794 13.3285Z"
fill="black"
/>
<path
d="M46.5582 24.5231L47.4608 25.4257L49.8015 23.0848L47.4608 20.7441L46.5582 21.6467L47.358 22.4465H35.8412V23.7231H47.3581L46.5582 24.5231Z"
fill="black"
/>
<path
d="M33.8298 12.7659H8.29785V14.0425H33.8298V12.7659Z"
fill="black"
/>
<path
d="M33.8298 15.9574H8.29785V17.234H33.8298V15.9574Z"
fill="black"
/>
<path
d="M33.8298 19.7874H8.29785V21.0639H33.8298V19.7874Z"
fill="black"
/>
<path
d="M33.8298 22.9788H8.29785V24.2554H33.8298V22.9788Z"
fill="black"
/>
<path
d="M57.0254 12.6194H51.0127V13.896H57.0254V12.6194Z"
fill="black"
/>
<path
d="M57.0254 16.0691H51.0127V17.3457H57.0254V16.0691Z"
fill="black"
/>
<path
d="M57.0254 19.5188H51.0127V20.7954H57.0254V19.5188Z"
fill="black"
/>
<path
d="M57.0254 22.9688H51.0127V24.2453H57.0254V22.9688Z"
fill="black"
/>
</svg>
</div> </div>
<h3
align="center"
class="box mm-text mm-text--heading-md box--flex-direction-row box--color-text-default"
>
Pair with Desktop
</h3>
<p
align="center"
class="box mm-text mm-text--body-md box--margin-top-2 box--flex-direction-row box--color-text-default"
>
Open your MetaMask Desktop and type this code
</p>
<div <div
class="desktop-pairing" class="box desktop-pairing__clickable box--margin-top-6 box--margin-bottom-6 box--flex-direction-row"
data-testid="desktop-pairing-otp-content"
> >
<div <div
class="desktop-pairing__clickable" class="desktop-pairing__tooltip-wrapper"
data-testid="desktop-pairing-otp-content"
> >
<div <div
class="box box--margin-right-6 box--margin-left-6 box--display-flex box--flex-direction-column box--align-items-center box--text-align-center" aria-describedby="tippy-tooltip-1"
class=""
data-original-title="Copy to clipboard"
data-tooltipped=""
style="display: inline;"
tabindex="0"
> >
<div <h1
class="desktop-pairing__tooltip-wrapper" align="center"
class="box mm-text desktop-pairing__otp mm-text--display-md box--flex-direction-row box--color-text-default"
> >
<div 123456
aria-describedby="tippy-tooltip-1" </h1>
class=""
data-original-title="Copy to clipboard"
data-tooltipped=""
style="display: inline;"
tabindex="0"
>
<p
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography desktop-pairing__otp typography--p typography--weight-normal typography--style-normal typography--align-center typography--color-text-default"
>
123456
</p>
</div>
</div>
</div> </div>
</div>
<div
class="box box--margin-top-4 box--margin-bottom-6 box--display-flex box--flex-direction-row box--justify-content-center box--align-items-center"
>
<p <p
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography desktop-pairing__countdown-timer typography--p typography--weight-normal typography--style-normal typography--align-center typography--color-text-default" align="center"
class="box mm-text desktop-pairing__countdown-timer mm-text--body-md box--padding-2 box--flex-direction-row box--color-text-default box--background-color-background-default box--rounded-xl"
> >
<span> <span>
@ -149,20 +144,19 @@ exports[`Desktop Pairing page should render otp component 1`] = `
</span> </span>
</p> </p>
<div
class="desktop-pairing__description"
>
If the pairing is successful, extension will restart and you'll have to re-enter your password.
</div>
</div> </div>
<p
align="center"
class="box mm-text mm-text--body-sm box--flex-direction-row box--color-text-default"
>
If the pairing is successful, extension will restart and you'll have to re-enter your password.
</p>
</div> </div>
<div <div
class="desktop-pairing__buttons" class="box box--flex-direction-row"
> >
<button <button
class="button btn--rounded btn-primary" class="box mm-text mm-button-base mm-button-base--size-md mm-button-primary mm-text--body-md box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-primary-inverse box--background-color-primary-default box--rounded-pill"
role="button"
tabindex="0"
> >
Done Done
</button> </button>

View File

@ -1,21 +1,22 @@
import React, { useState, useEffect, useRef, useContext } from 'react'; import React, { useState, useEffect, useRef, useContext } from 'react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Button from '../../components/ui/button';
import { SECOND } from '../../../shared/constants/time'; import { SECOND } from '../../../shared/constants/time';
import Typography from '../../components/ui/typography';
import { I18nContext } from '../../contexts/i18n'; import { I18nContext } from '../../contexts/i18n';
import IconDesktopPairing from '../../components/ui/icon/icon-desktop-pairing'; import IconDesktopPairing from '../../components/ui/icon/icon-desktop-pairing';
import { import {
TEXT_ALIGN, TEXT_ALIGN,
TypographyVariant, TextVariant,
DISPLAY, DISPLAY,
AlignItems, AlignItems,
FLEX_DIRECTION, JustifyContent,
BackgroundColor,
BorderRadius,
} from '../../helpers/constants/design-system'; } from '../../helpers/constants/design-system';
import Box from '../../components/ui/box/box'; import Box from '../../components/ui/box/box';
import { useCopyToClipboard } from '../../hooks/useCopyToClipboard'; import { useCopyToClipboard } from '../../hooks/useCopyToClipboard';
import Tooltip from '../../components/ui/tooltip'; import Tooltip from '../../components/ui/tooltip';
import { Text, Button } from '../../components/component-library';
export default function DesktopPairingPage({ export default function DesktopPairingPage({
generateDesktopOtp, generateDesktopOtp,
@ -75,19 +76,14 @@ export default function DesktopPairingPage({
const renderIcon = () => { const renderIcon = () => {
return ( return (
<div> <Box
<Box display={DISPLAY.FLEX}
display={DISPLAY.FLEX} justifyContent={JustifyContent.center}
alignItems={AlignItems.center} marginTop={8}
textAlign={TEXT_ALIGN.CENTER} marginBottom={8}
flexDirection={FLEX_DIRECTION.COLUMN} >
marginLeft={6} <IconDesktopPairing className="desktop-pairing__icon" size={64} />
marginRight={6} </Box>
marginTop={12}
>
<IconDesktopPairing size={64} />
</Box>
</div>
); );
}; };
@ -104,81 +100,94 @@ export default function DesktopPairingPage({
hideLoadingIndication(); hideLoadingIndication();
return ( return (
<div <>
className="desktop-pairing__clickable" <Text variant={TextVariant.headingMd} align={TEXT_ALIGN.CENTER}>
onClick={() => { {t('desktopPageTitle')}
handleCopy(otp); </Text>
}} <Text marginTop={2} align={TEXT_ALIGN.CENTER}>
data-testid="desktop-pairing-otp-content" {t('desktopPageSubTitle')}
> </Text>
<Box <Box
display={DISPLAY.FLEX} marginBottom={6}
alignItems={AlignItems.center} marginTop={6}
textAlign={TEXT_ALIGN.CENTER} className="desktop-pairing__clickable"
flexDirection={FLEX_DIRECTION.COLUMN} onClick={() => {
marginLeft={6} handleCopy(otp);
marginRight={6} }}
data-testid="desktop-pairing-otp-content"
> >
<Tooltip <Tooltip
wrapperClassName="desktop-pairing__tooltip-wrapper" wrapperClassName="desktop-pairing__tooltip-wrapper"
position="top" position="top"
title={copied ? t('copiedExclamation') : t('copyToClipboard')} title={copied ? t('copiedExclamation') : t('copyToClipboard')}
> >
<Typography <Text
align={TEXT_ALIGN.CENTER} align={TEXT_ALIGN.CENTER}
variant={TextVariant.displayMd}
className="desktop-pairing__otp" className="desktop-pairing__otp"
> >
{otp} {otp}
</Typography> </Text>
</Tooltip> </Tooltip>
<Box
display={DISPLAY.FLEX}
alignItems={AlignItems.center}
justifyContent={JustifyContent.center}
marginTop={4}
marginBottom={6}
>
<Text
className="desktop-pairing__countdown-timer"
variant={TextVariant.paragraph}
align={TEXT_ALIGN.CENTER}
backgroundColor={BackgroundColor.backgroundDefault}
borderRadius={BorderRadius.XL}
padding={2}
>
{t('desktopPairingExpireMessage', [
<span
className="desktop-pairing__countdown-timer-seconds"
key={1}
>
{getExpireDuration()}
</span>,
])}
</Text>
</Box>
<Text align={TEXT_ALIGN.CENTER} variant={TextVariant.bodySm}>
{t('desktopPageDescription')}
</Text>
</Box> </Box>
</>
<Typography
variant={TypographyVariant.paragraph}
align={TEXT_ALIGN.CENTER}
className="desktop-pairing__countdown-timer"
>
{t('desktopPairingExpireMessage', [
<span className="desktop-pairing__countdown-timer-seconds" key={1}>
{getExpireDuration()}
</span>,
])}
</Typography>
<div className="desktop-pairing__description">
{t('desktopPageDescription')}
</div>
</div>
); );
}; };
const renderFooter = () => { const renderFooter = () => {
return ( return (
<div className="desktop-pairing__buttons"> <Box>
<Button <Button
type="primary"
rounded
onClick={() => { onClick={() => {
goBack(); goBack();
}} }}
> >
{t('done')} {t('done')}
</Button> </Button>
</div> </Box>
); );
}; };
return ( return (
<div className="page-container__content"> <Box
<div className="desktop-pairing"> display={DISPLAY.FLEX}
{renderIcon()} flexDirection="column"
<div className="desktop-pairing__title">{t('desktopPageTitle')}</div> alignItems={AlignItems.center}
<div className="desktop-pairing__subtitle"> marginLeft={2}
{t('desktopPageSubTitle')} marginRight={2}
</div> >
</div> {renderIcon()}
<div className="desktop-pairing">{renderContent()}</div> {renderContent()}
{renderFooter()} {renderFooter()}
</div> </Box>
); );
} }

View File

@ -0,0 +1,30 @@
import React from 'react';
import DesktopPairingPage from './desktop-pairing.component';
export default {
title: 'Pages/DesktopPairingPage',
component: DesktopPairingPage,
argTypes: {
showLoadingIndication: {
action: 'showLoadingIndication',
},
hideLoadingIndication: {
action: 'hideLoadingIndication',
},
generateDesktopOtp: {
action: 'generateDesktopOtp',
},
},
args: {
mostRecentOverviewPage: '/',
},
};
export const DefaultStory = (args) => {
const generateDesktopOtp = async () => Promise.resolve('123456');
return (
<DesktopPairingPage {...args} generateDesktopOtp={generateDesktopOtp} />
);
};
DefaultStory.storyName = 'Default';

View File

@ -1,11 +1,12 @@
import React from 'react'; import React from 'react';
import reactRouterDom from 'react-router-dom'; import reactRouterDom from 'react-router-dom';
import { waitFor, act, screen } from '@testing-library/react'; import { waitFor, act, screen, fireEvent } from '@testing-library/react';
import actions from '../../store/actions'; import actions from '../../store/actions';
import configureStore from '../../store/store'; import configureStore from '../../store/store';
import { renderWithProvider } from '../../../test/jest'; import { renderWithProvider } from '../../../test/jest';
import mockState from '../../../test/data/mock-state.json'; import mockState from '../../../test/data/mock-state.json';
import { SECOND } from '../../../shared/constants/time'; import { SECOND } from '../../../shared/constants/time';
import { useCopyToClipboard } from '../../hooks/useCopyToClipboard';
import DesktopPairingPage from '.'; import DesktopPairingPage from '.';
const mockHideLoadingIndication = jest.fn(); const mockHideLoadingIndication = jest.fn();
@ -19,10 +20,13 @@ jest.mock('../../store/actions', () => {
}; };
}); });
jest.mock('../../hooks/useCopyToClipboard');
const mockedActions = actions; const mockedActions = actions;
describe('Desktop Pairing page', () => { describe('Desktop Pairing page', () => {
const mockHistoryPush = jest.fn(); const mockHistoryPush = jest.fn();
const handleCopy = jest.fn();
function flushPromises() { function flushPromises() {
// Wait for promises running in the non-async timer callback to complete. // Wait for promises running in the non-async timer callback to complete.
@ -35,6 +39,7 @@ describe('Desktop Pairing page', () => {
.spyOn(reactRouterDom, 'useHistory') .spyOn(reactRouterDom, 'useHistory')
.mockImplementation() .mockImplementation()
.mockReturnValue({ push: mockHistoryPush }); .mockReturnValue({ push: mockHistoryPush });
useCopyToClipboard.mockReturnValue([false, handleCopy]);
}); });
afterEach(() => { afterEach(() => {
@ -107,4 +112,53 @@ describe('Desktop Pairing page', () => {
jest.clearAllTimers(); jest.clearAllTimers();
jest.useRealTimers(); jest.useRealTimers();
}); });
it('should copy otp value when content is clicked', async () => {
const otp = '123456';
mockedActions.generateDesktopOtp.mockResolvedValue(otp);
const store = configureStore(mockState);
act(() => {
renderWithProvider(<DesktopPairingPage />, store);
});
await waitFor(() => {
expect(screen.getByTestId('desktop-pairing-otp-content')).toBeDefined();
expect(screen.getByText(otp)).toBeDefined();
});
act(() => {
fireEvent.click(screen.getByTestId('desktop-pairing-otp-content'));
});
await waitFor(() => {
expect(handleCopy).toHaveBeenCalledWith(otp);
});
});
it('should return to previews page when the done button is clicked', async () => {
const otp = '123456';
const mostRecentOverviewPage = '/mostRecentOverviewPage';
mockedActions.generateDesktopOtp.mockResolvedValue(otp);
const store = configureStore(mockState);
act(() => {
renderWithProvider(<DesktopPairingPage />, store);
});
await waitFor(() => {
expect(screen.getByTestId('desktop-pairing-otp-content')).toBeDefined();
});
act(() => {
fireEvent.click(screen.getByText('Done'));
});
await waitFor(() => {
expect(mockHistoryPush).toHaveBeenCalledTimes(1);
expect(mockHistoryPush).toHaveBeenCalledWith(mostRecentOverviewPage);
});
});
}); });

View File

@ -1,128 +1,28 @@
.desktop-pairing { .desktop-pairing {
display: flex;
flex-flow: column;
align-items: center;
padding: 0 30px 0;
&__countdown-timer { &__countdown-timer {
background: #f2f3f4;
border-radius: 15.5px;
padding: 7px 0 7px 0;
margin: 0 32px 0 32px;
font-size: 12px; font-size: 12px;
} }
&__countdown-timer-seconds { &__countdown-timer-seconds {
color: var(--color-primary-default); color: var(--color-primary-default);
} min-width: 180px;
&__icon {
padding-top: 24px;
}
&__title {
font-style: normal;
font-weight: 700;
font-size: 24px;
line-height: 140.62%;
text-align: center;
color: #24292e;
padding-top: 24px;
}
&__subtitle,
&__description {
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 140.62%;
text-align: center;
color: #000;
padding-top: 8px;
margin: 0 56px;
}
&__description {
margin: 18px 0;
} }
&__otp { &__otp {
font-style: normal;
font-weight: 500;
font-size: 48px;
letter-spacing: 10px; letter-spacing: 10px;
color: #000;
}
&__buttons {
display: flex;
width: 70%;
justify-content: space-between;
margin: auto;
} }
&__tooltip-wrapper { &__tooltip-wrapper {
width: 100%; width: 100%;
} }
&__clickable { &__clickable:hover {
width: 100%; cursor: pointer;
}
&:hover { &__icon {
cursor: pointer; path {
} fill: var(--color-icon-default);
}
}
.desktop-pairing-warning {
font-style: normal;
font-weight: 400;
font-size: 14px;
&__close-button {
z-index: 1050;
font-size: 24px;
cursor: pointer;
&__close::after {
content: '\00D7';
font-size: 24px;
cursor: pointer;
position: relative;
float: right;
margin-top: -8px;
}
}
&__title {
font-weight: bold;
font-size: 16px;
}
&__text {
font-size: 0.875rem;
}
&__link {
color: var(--color-primary-default);
display: block;
cursor: pointer;
line-height: 100%;
font-size: 0.875rem;
padding: 0 0;
}
&__warning-content {
border-left: 5px solid var(--color-warning-default);
border-right: 0;
border-bottom: 0;
border-top: 0;
margin: 4px;
.icon {
position: absolute;
left: 5px;
top: 10px;
} }
} }
} }