Skip to content

Commit

Permalink
add rpc url and block explorer modals
Browse files Browse the repository at this point in the history
  • Loading branch information
bergeron committed Sep 11, 2024
1 parent 716bfb1 commit e353881
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 50 deletions.
3 changes: 3 additions & 0 deletions ui/components/multichain/multichain-components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@
@import 'connected-accounts-menu';
@import 'connected-site-menu';
@import 'create-named-snap-account';
@import 'dropdown-editor';
@import 'token-list-item';
@import 'network-list-item';
@import 'network-list-item-menu';
@import 'network-list-menu/add-rpc-url-modal';
@import 'network-list-menu/add-block-explorer-modal';
@import 'network-list-menu';
@import 'product-tour-popover';
@import 'nft-item';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, { useEffect, useState } from 'react';
import {
Box,
ButtonPrimary,
ButtonPrimarySize,
FormTextField,
FormTextFieldSize,
HelpText,
HelpTextSeverity,
} from '../../../component-library';
import {
BackgroundColor,
BlockSize,
BorderRadius,
Display,
FlexDirection,
JustifyContent,
TextVariant,
} from '../../../../helpers/constants/design-system';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import { isWebUrl } from '../../../../../app/scripts/lib/util';

const AddBlockExplorerModal = ({
onAdded,
}: {
onAdded: (url: string) => void;
}) => {
const t = useI18nContext();
const [url, setUrl] = useState<string>();
const [error, setError] = useState<string>();

useEffect(() => {
if (url && url?.length > 0 && !isWebUrl(url)) {
setError(t('urlErrorMsg'));
} else {
setError(undefined);
}
}, [url]);

return (
<Box
className="add-block-explorer-modal"
display={Display.Flex}
flexDirection={FlexDirection.Column}
justifyContent={JustifyContent.spaceBetween}
height={BlockSize.Full}
>
<Box paddingLeft={4} paddingRight={4}>
<FormTextField
size={FormTextFieldSize.Lg}
textFieldProps={{ borderRadius: BorderRadius.LG }}
error={Boolean(error)}
id="additional-rpc-url"
label={t('blockExplorerUrl')}
inputProps={{
'data-testid': 'explorer-url-input',
}}
labelProps={{
children: undefined,
variant: TextVariant.bodyMdMedium,
}}
onChange={(e) => setUrl(e.target.value)}
/>
{error && (
<HelpText severity={HelpTextSeverity.Danger}>{error}</HelpText>
)}
</Box>
<Box
className="add-block-explorer-modal__footer"
backgroundColor={BackgroundColor.backgroundDefault}
padding={4}
width={BlockSize.Full}
>
<ButtonPrimary
width={BlockSize.Full}
disabled={Boolean(error)}
size={ButtonPrimarySize.Lg}
onClick={async () => {
if (url) {
onAdded(url);
}
}}
>
{t('addUrl')}
</ButtonPrimary>
</Box>
</Box>
);
};

export default AddBlockExplorerModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.add-block-explorer-modal {
overflow-y: auto;

&__footer {
position: sticky;
bottom: 0;
box-shadow: 0 0 8px 0 var(--color-shadow-default);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,70 @@
exports[`AddRpcUrlModal should render correctly 1`] = `
<div>
<div
class="mm-box mm-box--padding-4"
class="mm-box add-rpc-modal mm-box--display-flex mm-box--flex-direction-column mm-box--justify-content-space-between mm-box--height-full"
>
<div
class="mm-box mm-form-text-field mm-box--display-flex mm-box--flex-direction-column"
class="mm-box mm-box--padding-top-4 mm-box--padding-right-4 mm-box--padding-left-4"
>
<label
class="mm-box mm-text mm-label mm-label--html-for mm-form-text-field__label mm-text--body-sm-medium mm-text--font-weight-medium mm-box--display-inline-flex mm-box--align-items-center mm-box--color-text-default"
for="additional-rpc-url"
<div
class="mm-box mm-form-text-field mm-box--display-flex mm-box--flex-direction-column"
>
additionalRpcUrl
</label>
<label
class="mm-box mm-text mm-label mm-label--html-for mm-form-text-field__label mm-text--body-md-medium mm-text--font-weight-medium mm-box--display-inline-flex mm-box--align-items-center mm-box--color-text-default"
for="rpcUrl"
>
rpcUrl
</label>
<div
class="mm-box mm-text-field mm-text-field--size-lg mm-text-field--truncate mm-form-text-field__text-field mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--align-items-center mm-box--background-color-background-default mm-box--rounded-lg mm-box--border-width-1 box--border-style-solid"
>
<input
autocomplete="off"
class="mm-box mm-text mm-input mm-input--disable-state-styles mm-text-field__input mm-text--body-md mm-box--margin-0 mm-box--padding-0 mm-box--padding-right-4 mm-box--padding-left-4 mm-box--color-text-default mm-box--background-color-transparent mm-box--border-style-none"
data-testid="rpc-url-input-test"
focused="false"
id="rpcUrl"
placeholder="enterRpcUrl"
type="text"
value=""
/>
</div>
</div>
<div
class="mm-box mm-text-field mm-text-field--size-md mm-text-field--truncate mm-form-text-field__text-field mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--align-items-center mm-box--background-color-background-default mm-box--rounded-sm mm-box--border-width-1 box--border-style-solid"
class="mm-box mm-form-text-field mm-box--padding-top-4 mm-box--display-flex mm-box--flex-direction-column"
>
<input
autocomplete="off"
class="mm-box mm-text mm-input mm-input--disable-state-styles mm-text-field__input mm-text--body-md mm-box--margin-0 mm-box--padding-0 mm-box--padding-right-4 mm-box--padding-left-4 mm-box--color-text-default mm-box--background-color-transparent mm-box--border-style-none"
focused="false"
id="additional-rpc-url"
type="text"
value=""
/>
<label
class="mm-box mm-text mm-label mm-label--html-for mm-form-text-field__label mm-text--body-md-medium mm-text--font-weight-medium mm-box--display-inline-flex mm-box--align-items-center mm-box--color-text-default"
for="rpcName"
>
rpcNameOptional
</label>
<div
class="mm-box mm-text-field mm-text-field--size-lg mm-text-field--truncate mm-form-text-field__text-field mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--align-items-center mm-box--background-color-background-default mm-box--rounded-lg mm-box--border-width-1 box--border-style-solid"
>
<input
autocomplete="off"
class="mm-box mm-text mm-input mm-input--disable-state-styles mm-text-field__input mm-text--body-md mm-box--margin-0 mm-box--padding-0 mm-box--padding-right-4 mm-box--padding-left-4 mm-box--color-text-default mm-box--background-color-transparent mm-box--border-style-none"
data-testid="rpc-name-input-test"
focused="false"
id="rpcName"
placeholder="enterANameToIdentifyTheUrl"
type="text"
value=""
/>
</div>
</div>
</div>
<button
class="mm-box mm-text mm-button-base mm-button-base--size-lg mm-button-primary mm-text--body-md-medium mm-box--margin-top-8 mm-box--margin-right-auto mm-box--margin-left-auto mm-box--padding-0 mm-box--padding-right-4 mm-box--padding-left-4 mm-box--display-block mm-box--justify-content-center mm-box--align-items-center mm-box--width-full mm-box--color-primary-inverse mm-box--background-color-primary-default mm-box--rounded-pill"
data-theme="light"
<div
class="mm-box add-rpc-modal__footer mm-box--padding-4 mm-box--width-full mm-box--background-color-background-default"
>
addUrl
</button>
<button
class="mm-box mm-text mm-button-base mm-button-base--size-lg mm-button-primary mm-text--body-md-medium mm-box--padding-0 mm-box--padding-right-4 mm-box--padding-left-4 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--width-full mm-box--color-primary-inverse mm-box--background-color-primary-default mm-box--rounded-pill"
data-theme="light"
>
addUrl
</button>
</div>
</div>
</div>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,19 @@ describe('AddRpcUrlModal', () => {
});

it('should render correctly', () => {
const { container } = render(<AddRpcUrlModal />);
const { container } = render(<AddRpcUrlModal onAdded={() => undefined} />);
expect(container).toMatchSnapshot();
});

it('should render the input field with the correct label', () => {
render(<AddRpcUrlModal />);
const inputLabel = screen.getByLabelText('additionalRpcUrl');
expect(inputLabel).toBeInTheDocument();
});

it('should render the "Add URL" button with correct text', () => {
render(<AddRpcUrlModal />);
render(<AddRpcUrlModal onAdded={() => undefined} />);
const addButton = screen.getByRole('button', { name: 'addUrl' });
expect(addButton).toBeInTheDocument();
});

it('should call the appropriate function when "Add URL" button is clicked', () => {
const mockAddUrl = jest.fn();
render(<AddRpcUrlModal />);
render(<AddRpcUrlModal onAdded={() => null} />);
const addButton = screen.getByRole('button', { name: 'addUrl' });
userEvent.click(addButton);
expect(mockAddUrl).not.toHaveBeenCalled();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,109 @@
import React from 'react';
import React, { useEffect, useRef, useState } from 'react';
import {
Box,
ButtonPrimary,
ButtonPrimarySize,
FormTextField,
FormTextFieldSize,
HelpText,
HelpTextSeverity,
} from '../../../component-library';
import {
BackgroundColor,
BlockSize,
BorderRadius,
Display,
FlexDirection,
JustifyContent,
TextVariant,
} from '../../../../helpers/constants/design-system';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import { isWebUrl } from '../../../../../app/scripts/lib/util';

const AddRpcUrlModal = () => {
const AddRpcUrlModal = ({
onAdded,
}: {
onAdded: (url: string, name?: string) => void;
}) => {
const t = useI18nContext();

const [url, setUrl] = useState<string>();
const [error, setError] = useState<string>();
const nameRef = useRef<HTMLInputElement>(null);

useEffect(() => {
if (url && !isWebUrl(url)) {
setError(isWebUrl(`https://${url}`) ? t('urlErrorMsg') : t('invalidRPC'));
} else {
setError(undefined);
}
}, [url]);

return (
<Box padding={4}>
<FormTextField
id="additional-rpc-url"
label={t('additionalRpcUrl')}
labelProps={{
children: undefined,
variant: TextVariant.bodySmMedium,
}}
/>
<Box
className="add-rpc-modal"
display={Display.Flex}
flexDirection={FlexDirection.Column}
justifyContent={JustifyContent.spaceBetween}
height={BlockSize.Full}
>
<Box paddingTop={4} paddingLeft={4} paddingRight={4}>
<FormTextField
id="rpcUrl"
size={FormTextFieldSize.Lg}
error={Boolean(error)}
label={t('rpcUrl')}
placeholder={t('enterRpcUrl')}
textFieldProps={{ borderRadius: BorderRadius.LG }}
labelProps={{
children: undefined,
variant: TextVariant.bodyMdMedium,
}}
inputProps={{
'data-testid': 'rpc-url-input-test',
}}
onChange={(e) => setUrl(e.target.value)}
/>
{error && (
<HelpText severity={HelpTextSeverity.Danger}>{error}</HelpText>
)}
<FormTextField
id="rpcName"
size={FormTextFieldSize.Lg}
inputProps={{
'data-testid': 'rpc-name-input-test',
}}
placeholder={t('enterANameToIdentifyTheUrl')}
paddingTop={4}
inputRef={nameRef}
label={t('rpcNameOptional')}
textFieldProps={{ borderRadius: BorderRadius.LG }}
labelProps={{
children: undefined,
variant: TextVariant.bodyMdMedium,
}}
/>
</Box>

<ButtonPrimary
size={ButtonPrimarySize.Lg}
display={Display.Block}
<Box
className="add-rpc-modal__footer"
backgroundColor={BackgroundColor.backgroundDefault}
padding={4}
width={BlockSize.Full}
marginTop={8}
marginLeft={'auto'}
marginRight={'auto'}
onClick={() => ({})}
>
{t('addUrl')}
</ButtonPrimary>
<ButtonPrimary
width={BlockSize.Full}
disabled={Boolean(error)}
size={ButtonPrimarySize.Lg}
onClick={async () => {
if (url && !error && nameRef.current) {
onAdded(url, nameRef.current.value || undefined);
}
}}
>
{t('addUrl')}
</ButtonPrimary>
</Box>
</Box>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.add-rpc-modal {
overflow-y: auto;

&__footer {
position: sticky;
bottom: 0;
box-shadow: 0 0 8px 0 var(--color-shadow-default);
}
}

0 comments on commit e353881

Please sign in to comment.