Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/browser-ui-update' into x-id-cards
Browse files Browse the repository at this point in the history
  • Loading branch information
limemloh committed Oct 30, 2024
2 parents ceb05d2 + c43caef commit 5de695d
Show file tree
Hide file tree
Showing 23 changed files with 399 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
margin: rem(1px);
width: rem(106px);
height: rem(106px);
background-color: $color-main-bg;

&.wide {
width: rem(160px);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ export default function Header({
accountOpen,
setAccountOpen,
}: HeaderProps) {
if (menuOpen) {
setAccountOpen(false);
}
useEffect(() => {
if (menuOpen) {
setAccountOpen(false);
}
if (menuOpen || accountOpen) {
background?.classList.add('fade-bg');
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
.change-passcode-x {
.divider {
display: block;
margin: rem(16px) 0 rem(24px) 0;
border-bottom: 1px solid rgba($color-white, 0.1);
.change-passcode-page__form {
display: flex;
flex-direction: column;
gap: rem(8px);

.divider {
display: block;
margin: rem(8px) 0 rem(16px) 0;
border-bottom: 1px solid rgba($color-white, 0.1);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default function ChangePasscode() {
<Page.Top heading={t('changePasscode')} />
<Page.Main>
<Form
id="test-form"
id="change-password-form"
onSubmit={handleSubmit}
className="change-passcode-page__form"
formMethods={form}
Expand Down Expand Up @@ -98,7 +98,7 @@ export default function ChangePasscode() {
</Page.Main>
<Page.Footer>
<Button.Main
form="test-form"
form="change-password-form"
type="submit"
label={t('changePasscode')}
disabled={form.formState.isSubmitting}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { NetworkConfiguration } from '@shared/storage/types';
import { getNet } from '@shared/utils/network-helpers';
import { copyToClipboard } from '@popup/popupX/shared/utils/helpers';
import { Navigate, useParams } from 'react-router-dom';
import { withPasswordProtected } from '@popup/popupX/shared/utils/hoc';

type CredentialKeys = {
threshold: number;
Expand Down Expand Up @@ -123,11 +124,17 @@ function PrivateKey({ address }: Props) {
);
}

export default function Loader() {
function Loader() {
const params = useParams();
if (!('account' in params) || params.account === undefined) {
// No account address passed in the url.
return <Navigate to="../" />;
}
return <PrivateKey address={params.account} />;
}

export default withPasswordProtected(Loader, {
headingKey: 'privateKey.accountPrivateKey',
pageInfoKey: 'privateKey.passwordDescription',
submitKey: 'privateKey.showPrivateKey',
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const t = {
'Your account private key is the access key to all the funds in your account. Copy it and keep it safe. To avoid mistakes, do not write it down manually.',
export: 'Export',
copyKey: 'Copy account private key',
passwordDescription: 'Please enter your passcode to show the private key',
showPrivateKey: 'Show private key',
};

export default t;
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,52 @@ import Page from '@popup/popupX/shared/Page';
import Text from '@popup/popupX/shared/Text';
import Card from '@popup/popupX/shared/Card';
import Copy from '@assets/svgX/copy.svg';
import { useAsyncMemo } from 'wallet-common-helpers';
import { decrypt } from '@shared/utils/crypto';
import { useAtomValue } from 'jotai';
import { encryptedSeedPhraseAtom, sessionPasscodeAtom } from '@popup/store/settings';
import { copyToClipboard } from '@popup/popupX/shared/utils/helpers';
import { withPasswordProtected } from '@popup/popupX/shared/utils/hoc';

const RECOVERY_PHRASE =
'meadow salad weather rural next promote fence mass leopard mail regret mushroom love coral viable layer lumber soft setup radar oppose miracle rural agree'.split(
' '
function SeedPhrase() {
const { t } = useTranslation('x', { keyPrefix: 'seedPhrase' });
const passcode = useAtomValue(sessionPasscodeAtom);
const encryptedSeed = useAtomValue(encryptedSeedPhraseAtom);

const seedPhrase = useAsyncMemo(
async () => {
if (encryptedSeed.loading || passcode.loading) {
return undefined;
}
if (encryptedSeed.value && passcode.value) {
return decrypt(encryptedSeed.value, passcode.value);
}
throw new Error('SeedPhrase should not be retrieved without unlocking the wallet.');
},
undefined,
[encryptedSeed.loading, passcode.loading]
);

export default function SeedPhrase() {
const { t } = useTranslation('x', { keyPrefix: 'seedPhrase' });
if (!seedPhrase) return null;

return (
<Page className="seed-phrase-x">
<Page.Top heading={t('seedPhrase')} />
<Page.Main>
<Text.Capture>{t('seedPhraseDescription')}</Text.Capture>
<Card>
{RECOVERY_PHRASE.map((word) => (
<Text.LabelRegular>{word}</Text.LabelRegular>
{seedPhrase.split(' ').map((word) => (
<Text.LabelRegular key={word}>{word}</Text.LabelRegular>
))}
</Card>
<Button.IconText icon={<Copy />} label={t('copy')} />
<Button.IconText icon={<Copy />} label={t('copy')} onClick={() => copyToClipboard(seedPhrase)} />
</Page.Main>
</Page>
);
}

export default withPasswordProtected(SeedPhrase, {
headingKey: 'seedPhrase.seedPhrase',
pageInfoKey: 'seedPhrase.passwordDescription',
submitKey: 'seedPhrase.showSeedPhrase',
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const t = {
seedPhraseDescription:
'Your seed phrase is the access key to all the funds in your wallet. If you forget it you will lose access to your wallet(s). Keep it somewhere safe.',
copy: 'Copy seed phrase',
passwordDescription: 'Please enter your passcode to show the seed phrase.',
showSeedPhrase: 'Show secret recovery phrase',
};

export default t;
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const Form = forwardRef(
const internal = useForm<V>({ defaultValues });
const methods = external ?? internal;

const submit = () => (onSubmit === undefined ? noOp : methods.handleSubmit(onSubmit));
const submit = onSubmit === undefined ? () => noOp : methods.handleSubmit(onSubmit);

return (
<FormProvider {...methods}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.fullscreen-notice {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;

&__back {
border: none;
background: none;

&:hover {
background: none !important;
}
}

&__content {
padding: 0 rem(24px);
overflow: auto;
height: calc(100% - 7.4rem);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* eslint-disable react/function-component-definition, react/destructuring-assignment */
import React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import FullscreenNotice from './FullscreenNotice';
import Page from '../Page';
import Button from '../Button';

export default {
title: 'X/Shared/FullscreenNotice',
component: FullscreenNotice,
beforeEach: () => {
const body = document.getElementsByTagName('body').item(0);
body?.classList.add('popup-x');

return () => {
body?.classList.remove('popup-x');
};
},
tags: ['!autodocs'],
} as Meta<typeof FullscreenNotice>;

type Story = StoryObj<typeof FullscreenNotice>;

export const Primary: Story = {
args: {
children: (
<Page>
<Page.Top heading="Some title" />
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore
et dolore magna aliqua. Tincidunt nunc pulvinar sapien et. Mattis aliquam faucibus purus in.
Tristique sollicitudin nibh sit amet commodo nulla facilisi. Eget nullam non nisi est sit amet. At
lectus urna duis convallis. Consequat semper viverra nam libero. Gravida rutrum quisque non tellus
orci ac auctor. Mattis aliquam faucibus purus in massa tempor nec feugiat. Consectetur adipiscing
elit duis tristique sollicitudin. Sit amet est placerat in egestas erat imperdiet sed euismod.
Ornare massa eget egestas purus viverra. Viverra maecenas accumsan lacus vel facilisis. Malesuada
fames ac turpis egestas integer eget aliquet nibh. Non diam phasellus vestibulum lorem sed risus.
Tincidunt vitae semper quis lectus nulla. Cursus euismod quis viverra nibh cras pulvinar mattis nunc
sed.
</p>
<Page.Footer>
<Button.Main label="Some action" />
</Page.Footer>
</Page>
),
open: true,
},
};

export const WallOfText: Story = {
args: {
children: (
<>
<h1>Lorem ipsum!</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore
et dolore magna aliqua. Tincidunt nunc pulvinar sapien et. Mattis aliquam faucibus purus in.
Tristique sollicitudin nibh sit amet commodo nulla facilisi. Eget nullam non nisi est sit amet. At
lectus urna duis convallis. Consequat semper viverra nam libero. Gravida rutrum quisque non tellus
orci ac auctor. Mattis aliquam faucibus purus in massa tempor nec feugiat. Consectetur adipiscing
elit duis tristique sollicitudin. Sit amet est placerat in egestas erat imperdiet sed euismod.
Ornare massa eget egestas purus viverra. Viverra maecenas accumsan lacus vel facilisis. Malesuada
fames ac turpis egestas integer eget aliquet nibh. Non diam phasellus vestibulum lorem sed risus.
Tincidunt vitae semper quis lectus nulla. Cursus euismod quis viverra nibh cras pulvinar mattis nunc
sed.
</p>
<p>
Commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula. Vitae congue mauris rhoncus
aenean vel elit scelerisque mauris pellentesque. Nec feugiat in fermentum posuere urna. Lobortis
scelerisque fermentum dui faucibus in ornare quam. Sit amet est placerat in egestas erat imperdiet
sed euismod. Nulla aliquet porttitor lacus luctus accumsan tortor posuere. Arcu risus quis varius
quam. Ullamcorper a lacus vestibulum sed arcu non odio. Eu mi bibendum neque egestas. Duis at
consectetur lorem donec.
</p>
<p>
Hendrerit dolor magna eget est lorem ipsum dolor sit amet. Dignissim sodales ut eu sem. Tellus
molestie nunc non blandit massa enim nec. Amet nulla facilisi morbi tempus iaculis urna. Metus
vulputate eu scelerisque felis imperdiet proin. Mauris ultrices eros in cursus turpis massa
tincidunt dui ut. Praesent tristique magna sit amet purus gravida quis blandit turpis. Turpis nunc
eget lorem dolor sed viverra ipsum. Et egestas quis ipsum suspendisse ultrices gravida. Egestas diam
in arcu cursus euismod quis. Egestas purus viverra accumsan in. Convallis convallis tellus id
interdum. Donec pretium vulputate sapien nec sagittis. Consectetur adipiscing elit ut aliquam purus
sit amet luctus venenatis.
</p>
<p>
Eget gravida cum sociis natoque penatibus et. Tincidunt eget nullam non nisi est. Amet mattis
vulputate enim nulla. Eget mi proin sed libero enim sed faucibus turpis in. Mattis ullamcorper velit
sed ullamcorper. Nunc vel risus commodo viverra. At tellus at urna condimentum mattis. At elementum
eu facilisis sed odio. Egestas dui id ornare arcu. Proin libero nunc consequat interdum varius.
Scelerisque eleifend donec pretium vulputate sapien nec.
</p>
<p>
Eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar. Sapien eget mi proin sed
libero enim. Eget velit aliquet sagittis id consectetur. Est placerat in egestas erat. Diam maecenas
ultricies mi eget mauris pharetra et ultrices neque. Ut sem nulla pharetra diam sit amet nisl
suscipit adipiscing. Curabitur vitae nunc sed velit dignissim sodales ut eu sem. Adipiscing at in
tellus integer feugiat scelerisque varius. Ultrices mi tempus imperdiet nulla malesuada pellentesque
elit eget. Quisque sagittis purus sit amet volutpat. Dignissim diam quis enim lobortis scelerisque
fermentum dui. At lectus urna duis convallis convallis tellus id. Ultrices dui sapien eget mi proin
sed.
</p>
</>
),
open: true,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React, { PropsWithChildren, useCallback, useEffect, useMemo } from 'react';
import clsx from 'clsx';
import { Portal, noOp } from 'wallet-common-helpers';
import Back from '@assets/svgX/arrow-left.svg';
import { Connection, Fullscreen } from '@popup/popupX/page-layouts/MainLayout/Header/components';
import Button from '../Button';

type HeaderProps = {
isScrolling: boolean;
onBack(): void;
};

function Header({ isScrolling, onBack }: HeaderProps) {
return (
<div className={clsx('main-header', isScrolling && 'scroll-border')}>
<div className="main-header__top">
<Fullscreen />
<Connection hideConnection={false} />
</div>
<div className="main-header__bottom">
<Button.Icon className="fullscreen-notice__back" icon={<Back />} onClick={() => onBack()} />
</div>
</div>
);
}

const htmlElement = document.getElementsByTagName('html')[0]!;
const bodyElement = document.getElementsByTagName('body')[0]!;

type Props = {
/** Control whether notice is shown or not */
open: boolean;
/** Invoked when the notice is closed */
onClose(): void;
};

/**
* @description
* Opens content in a modal overlay on top of the current wallet window.
*
* @example
* <FullscreenNotice open={isOpen} onClose={() => setIsOpen(false)}>
* <Page>
* <Page.Top heading="Notice title"/>
* This is the body
* <Page.Footer>
* <Button.Main>Some action</Button.Main>
* </Page.Footer>
* </Page>
* This content is shown in a modal!
* </FullscreenNotice>
*/
export default function FullscreenNotice({ open, onClose, children }: PropsWithChildren<Props>): JSX.Element | null {
const [scroll, setScroll] = React.useState(0);
const isScrolling = useMemo(() => scroll > 0, [!!scroll]);
const close = useCallback(() => {
onClose();
}, [onClose]);

useEffect(() => {
if (open) {
htmlElement.classList.add('modal-open');

// Prevent modal from stretching window height
htmlElement.style.height = bodyElement.style.height;

return () => {
htmlElement.classList.remove('modal-open');
// Reset to initial value
htmlElement.style.height = '100%';
};
}
return noOp;
}, [open]);

if (!open) {
return null;
}

return (
<Portal className="fullscreen-notice">
<Header isScrolling={isScrolling} onBack={close} />
<div
className="fullscreen-notice__content"
onScroll={(e) => {
setScroll(e.currentTarget.scrollTop);
}}
>
{children}
</div>
</Portal>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './FullscreenNotice';
Loading

0 comments on commit 5de695d

Please sign in to comment.