mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 09:57:02 +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:
commit
f32d71ba1a
@ -121,12 +121,17 @@ export async function getErrorHtml(
|
||||
}
|
||||
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
export const MMD_DOWNLOAD_LINK =
|
||||
'https://github.com/MetaMask/metamask-desktop/releases';
|
||||
|
||||
function disableDesktop(backgroundConnection) {
|
||||
backgroundConnection.disableDesktopError();
|
||||
}
|
||||
|
||||
export function downloadDesktopApp() {
|
||||
global.platform.openTab({ url: 'https://metamask.io/' });
|
||||
global.platform.openTab({
|
||||
url: MMD_DOWNLOAD_LINK,
|
||||
});
|
||||
}
|
||||
|
||||
export function downloadExtension() {
|
||||
@ -139,7 +144,7 @@ export function restartExtension() {
|
||||
|
||||
export function openOrDownloadMMD() {
|
||||
openCustomProtocol('metamask-desktop://pair').catch(() => {
|
||||
window.open('https://metamask.io/download.html', '_blank').focus();
|
||||
window.open(MMD_DOWNLOAD_LINK, '_blank').focus();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,48 @@
|
||||
import browser from 'webextension-polyfill';
|
||||
import { fetchLocale } from '../../ui/helpers/utils/i18n-helper';
|
||||
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', () => ({
|
||||
fetchLocale: 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 () {
|
||||
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 () {
|
||||
const mockStore = {
|
||||
localeMessages: {
|
||||
@ -50,4 +85,93 @@ describe('Error utils Tests', function () {
|
||||
expect(errorHtml).toContain(stillGettingMessageMessage);
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -3,139 +3,134 @@
|
||||
exports[`Desktop Pairing page should render otp component 1`] = `
|
||||
<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
|
||||
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>
|
||||
<div
|
||||
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"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
height="64"
|
||||
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"
|
||||
<svg
|
||||
class="desktop-pairing__icon"
|
||||
fill="currentColor"
|
||||
height="64"
|
||||
viewBox="0 0 64 39"
|
||||
width="64"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
Pair with Desktop
|
||||
</div>
|
||||
<div
|
||||
class="desktop-pairing__subtitle"
|
||||
>
|
||||
Open your MetaMask Desktop and type this code
|
||||
</div>
|
||||
<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>
|
||||
<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
|
||||
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
|
||||
class="desktop-pairing__clickable"
|
||||
data-testid="desktop-pairing-otp-content"
|
||||
class="desktop-pairing__tooltip-wrapper"
|
||||
>
|
||||
<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
|
||||
class="desktop-pairing__tooltip-wrapper"
|
||||
<h1
|
||||
align="center"
|
||||
class="box mm-text desktop-pairing__otp mm-text--display-md box--flex-direction-row box--color-text-default"
|
||||
>
|
||||
<div
|
||||
aria-describedby="tippy-tooltip-1"
|
||||
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>
|
||||
123456
|
||||
</h1>
|
||||
</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
|
||||
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>
|
||||
|
||||
@ -149,20 +144,19 @@ exports[`Desktop Pairing page should render otp component 1`] = `
|
||||
|
||||
</span>
|
||||
</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>
|
||||
<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
|
||||
class="desktop-pairing__buttons"
|
||||
class="box box--flex-direction-row"
|
||||
>
|
||||
<button
|
||||
class="button btn--rounded btn-primary"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
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"
|
||||
>
|
||||
Done
|
||||
</button>
|
||||
|
@ -1,21 +1,22 @@
|
||||
import React, { useState, useEffect, useRef, useContext } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import Button from '../../components/ui/button';
|
||||
import { SECOND } from '../../../shared/constants/time';
|
||||
import Typography from '../../components/ui/typography';
|
||||
import { I18nContext } from '../../contexts/i18n';
|
||||
import IconDesktopPairing from '../../components/ui/icon/icon-desktop-pairing';
|
||||
import {
|
||||
TEXT_ALIGN,
|
||||
TypographyVariant,
|
||||
TextVariant,
|
||||
DISPLAY,
|
||||
AlignItems,
|
||||
FLEX_DIRECTION,
|
||||
JustifyContent,
|
||||
BackgroundColor,
|
||||
BorderRadius,
|
||||
} from '../../helpers/constants/design-system';
|
||||
import Box from '../../components/ui/box/box';
|
||||
import { useCopyToClipboard } from '../../hooks/useCopyToClipboard';
|
||||
import Tooltip from '../../components/ui/tooltip';
|
||||
import { Text, Button } from '../../components/component-library';
|
||||
|
||||
export default function DesktopPairingPage({
|
||||
generateDesktopOtp,
|
||||
@ -75,19 +76,14 @@ export default function DesktopPairingPage({
|
||||
|
||||
const renderIcon = () => {
|
||||
return (
|
||||
<div>
|
||||
<Box
|
||||
display={DISPLAY.FLEX}
|
||||
alignItems={AlignItems.center}
|
||||
textAlign={TEXT_ALIGN.CENTER}
|
||||
flexDirection={FLEX_DIRECTION.COLUMN}
|
||||
marginLeft={6}
|
||||
marginRight={6}
|
||||
marginTop={12}
|
||||
>
|
||||
<IconDesktopPairing size={64} />
|
||||
</Box>
|
||||
</div>
|
||||
<Box
|
||||
display={DISPLAY.FLEX}
|
||||
justifyContent={JustifyContent.center}
|
||||
marginTop={8}
|
||||
marginBottom={8}
|
||||
>
|
||||
<IconDesktopPairing className="desktop-pairing__icon" size={64} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@ -104,81 +100,94 @@ export default function DesktopPairingPage({
|
||||
hideLoadingIndication();
|
||||
|
||||
return (
|
||||
<div
|
||||
className="desktop-pairing__clickable"
|
||||
onClick={() => {
|
||||
handleCopy(otp);
|
||||
}}
|
||||
data-testid="desktop-pairing-otp-content"
|
||||
>
|
||||
<>
|
||||
<Text variant={TextVariant.headingMd} align={TEXT_ALIGN.CENTER}>
|
||||
{t('desktopPageTitle')}
|
||||
</Text>
|
||||
<Text marginTop={2} align={TEXT_ALIGN.CENTER}>
|
||||
{t('desktopPageSubTitle')}
|
||||
</Text>
|
||||
<Box
|
||||
display={DISPLAY.FLEX}
|
||||
alignItems={AlignItems.center}
|
||||
textAlign={TEXT_ALIGN.CENTER}
|
||||
flexDirection={FLEX_DIRECTION.COLUMN}
|
||||
marginLeft={6}
|
||||
marginRight={6}
|
||||
marginBottom={6}
|
||||
marginTop={6}
|
||||
className="desktop-pairing__clickable"
|
||||
onClick={() => {
|
||||
handleCopy(otp);
|
||||
}}
|
||||
data-testid="desktop-pairing-otp-content"
|
||||
>
|
||||
<Tooltip
|
||||
wrapperClassName="desktop-pairing__tooltip-wrapper"
|
||||
position="top"
|
||||
title={copied ? t('copiedExclamation') : t('copyToClipboard')}
|
||||
>
|
||||
<Typography
|
||||
<Text
|
||||
align={TEXT_ALIGN.CENTER}
|
||||
variant={TextVariant.displayMd}
|
||||
className="desktop-pairing__otp"
|
||||
>
|
||||
{otp}
|
||||
</Typography>
|
||||
</Text>
|
||||
</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>
|
||||
|
||||
<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 = () => {
|
||||
return (
|
||||
<div className="desktop-pairing__buttons">
|
||||
<Box>
|
||||
<Button
|
||||
type="primary"
|
||||
rounded
|
||||
onClick={() => {
|
||||
goBack();
|
||||
}}
|
||||
>
|
||||
{t('done')}
|
||||
</Button>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="page-container__content">
|
||||
<div className="desktop-pairing">
|
||||
{renderIcon()}
|
||||
<div className="desktop-pairing__title">{t('desktopPageTitle')}</div>
|
||||
<div className="desktop-pairing__subtitle">
|
||||
{t('desktopPageSubTitle')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="desktop-pairing">{renderContent()}</div>
|
||||
<Box
|
||||
display={DISPLAY.FLEX}
|
||||
flexDirection="column"
|
||||
alignItems={AlignItems.center}
|
||||
marginLeft={2}
|
||||
marginRight={2}
|
||||
>
|
||||
{renderIcon()}
|
||||
{renderContent()}
|
||||
{renderFooter()}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
30
ui/pages/desktop-pairing/desktop-pairing.stories.js
Normal file
30
ui/pages/desktop-pairing/desktop-pairing.stories.js
Normal 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';
|
@ -1,11 +1,12 @@
|
||||
import React from 'react';
|
||||
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 configureStore from '../../store/store';
|
||||
import { renderWithProvider } from '../../../test/jest';
|
||||
import mockState from '../../../test/data/mock-state.json';
|
||||
import { SECOND } from '../../../shared/constants/time';
|
||||
import { useCopyToClipboard } from '../../hooks/useCopyToClipboard';
|
||||
import DesktopPairingPage from '.';
|
||||
|
||||
const mockHideLoadingIndication = jest.fn();
|
||||
@ -19,10 +20,13 @@ jest.mock('../../store/actions', () => {
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('../../hooks/useCopyToClipboard');
|
||||
|
||||
const mockedActions = actions;
|
||||
|
||||
describe('Desktop Pairing page', () => {
|
||||
const mockHistoryPush = jest.fn();
|
||||
const handleCopy = jest.fn();
|
||||
|
||||
function flushPromises() {
|
||||
// Wait for promises running in the non-async timer callback to complete.
|
||||
@ -35,6 +39,7 @@ describe('Desktop Pairing page', () => {
|
||||
.spyOn(reactRouterDom, 'useHistory')
|
||||
.mockImplementation()
|
||||
.mockReturnValue({ push: mockHistoryPush });
|
||||
useCopyToClipboard.mockReturnValue([false, handleCopy]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -107,4 +112,53 @@ describe('Desktop Pairing page', () => {
|
||||
jest.clearAllTimers();
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,128 +1,28 @@
|
||||
.desktop-pairing {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
padding: 0 30px 0;
|
||||
|
||||
&__countdown-timer {
|
||||
background: #f2f3f4;
|
||||
border-radius: 15.5px;
|
||||
padding: 7px 0 7px 0;
|
||||
margin: 0 32px 0 32px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&__countdown-timer-seconds {
|
||||
color: var(--color-primary-default);
|
||||
}
|
||||
|
||||
&__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;
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
&__otp {
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 48px;
|
||||
letter-spacing: 10px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
display: flex;
|
||||
width: 70%;
|
||||
justify-content: space-between;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
&__tooltip-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__clickable {
|
||||
width: 100%;
|
||||
&__clickable:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
&__icon {
|
||||
path {
|
||||
fill: var(--color-icon-default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user