Created a new contract details modal (#15549)
Co-authored-by: Brad Decker <bhdecker84@gmail.com>feature/default_network_editable
parent
47d61c6832
commit
69b5505a1c
@ -0,0 +1,213 @@ |
||||
import React from 'react'; |
||||
import PropTypes from 'prop-types'; |
||||
import Box from '../../../ui/box'; |
||||
import IconCopy from '../../../ui/icon/icon-copy'; |
||||
import IconBlockExplorer from '../../../ui/icon/icon-block-explorer'; |
||||
import Button from '../../../ui/button/button.component'; |
||||
import Tooltip from '../../../ui/tooltip/tooltip'; |
||||
import { useI18nContext } from '../../../../hooks/useI18nContext'; |
||||
import Identicon from '../../../ui/identicon/identicon.component'; |
||||
import { ellipsify } from '../../../../pages/send/send.utils'; |
||||
import Popover from '../../../ui/popover'; |
||||
import Typography from '../../../ui/typography'; |
||||
import { |
||||
FONT_WEIGHT, |
||||
TYPOGRAPHY, |
||||
DISPLAY, |
||||
COLORS, |
||||
JUSTIFY_CONTENT, |
||||
SIZES, |
||||
BORDER_STYLE, |
||||
} from '../../../../helpers/constants/design-system'; |
||||
|
||||
export default function ContractDetailsModal({ onClose, address, tokenName }) { |
||||
const t = useI18nContext(); |
||||
|
||||
return ( |
||||
<Popover className="contract-details-modal"> |
||||
<Box |
||||
paddingTop={6} |
||||
paddingRight={4} |
||||
paddingBottom={8} |
||||
paddingLeft={4} |
||||
className="contract-details-modal__content" |
||||
> |
||||
<Typography |
||||
fontWeight={FONT_WEIGHT.BOLD} |
||||
variant={TYPOGRAPHY.H5} |
||||
display={DISPLAY.FLEX} |
||||
boxProps={{ marginTop: 0, marginBottom: 0 }} |
||||
> |
||||
{t('contractTitle')} |
||||
</Typography> |
||||
<Typography |
||||
variant={TYPOGRAPHY.H7} |
||||
display={DISPLAY.FLEX} |
||||
color={COLORS.TEXT_ALTERNATIVE} |
||||
boxProps={{ marginTop: 2, marginBottom: 0 }} |
||||
> |
||||
{t('contractDescription')} |
||||
</Typography> |
||||
<Typography |
||||
variant={TYPOGRAPHY.H6} |
||||
display={DISPLAY.FLEX} |
||||
marginTop={4} |
||||
marginBottom={2} |
||||
> |
||||
{t('contractToken')} |
||||
</Typography> |
||||
<Box |
||||
display={DISPLAY.FLEX} |
||||
borderRadius={SIZES.SM} |
||||
borderStyle={BORDER_STYLE.SOLID} |
||||
borderColor={COLORS.BORDER_DEFAULT} |
||||
className="contract-details-modal__content__contract" |
||||
> |
||||
<Identicon |
||||
className="contract-details-modal__content__contract__identicon" |
||||
address={address} |
||||
diameter={24} |
||||
/> |
||||
<Box data-testid="recipient"> |
||||
<Typography |
||||
fontWeight={FONT_WEIGHT.BOLD} |
||||
variant={TYPOGRAPHY.H5} |
||||
marginTop={4} |
||||
> |
||||
{tokenName || ellipsify(address)} |
||||
</Typography> |
||||
{tokenName && ( |
||||
<Typography |
||||
variant={TYPOGRAPHY.H6} |
||||
display={DISPLAY.FLEX} |
||||
color={COLORS.TEXT_ALTERNATIVE} |
||||
> |
||||
{ellipsify(address)} |
||||
</Typography> |
||||
)} |
||||
</Box> |
||||
<Box |
||||
justifyContent={JUSTIFY_CONTENT.FLEX_END} |
||||
className="contract-details-modal__content__contract__buttons" |
||||
> |
||||
<Box marginTop={4} marginRight={5}> |
||||
<Tooltip position="top" title={t('copyToClipboard')}> |
||||
<Button |
||||
className="contract-details-modal__content__contract__buttons__copy" |
||||
type="link" |
||||
> |
||||
<IconCopy color="var(--color-icon-muted)" /> |
||||
</Button> |
||||
</Tooltip> |
||||
</Box> |
||||
<Box marginTop={5} marginRight={5}> |
||||
<Tooltip position="top" title={t('openInBlockExplorer')}> |
||||
<Button |
||||
className="contract-details-modal__content__contract__buttons__block-explorer" |
||||
type="link" |
||||
> |
||||
<IconBlockExplorer |
||||
size={16} |
||||
color="var(--color-icon-muted)" |
||||
/> |
||||
</Button> |
||||
</Tooltip> |
||||
</Box> |
||||
</Box> |
||||
</Box> |
||||
|
||||
<Typography |
||||
variant={TYPOGRAPHY.H6} |
||||
display={DISPLAY.FLEX} |
||||
marginTop={4} |
||||
marginBottom={2} |
||||
> |
||||
{t('contractRequestingSpendingCap')} |
||||
</Typography> |
||||
<Box |
||||
display={DISPLAY.FLEX} |
||||
borderRadius={SIZES.SM} |
||||
borderStyle={BORDER_STYLE.SOLID} |
||||
borderColor={COLORS.BORDER_DEFAULT} |
||||
className="contract-details-modal__content__contract" |
||||
> |
||||
<Identicon |
||||
className="contract-details-modal__content__contract__identicon" |
||||
address={address} |
||||
diameter={24} |
||||
/> |
||||
<Box data-testid="recipient"> |
||||
<Typography |
||||
fontWeight={FONT_WEIGHT.BOLD} |
||||
variant={TYPOGRAPHY.H5} |
||||
marginTop={4} |
||||
> |
||||
{tokenName || ellipsify(address)} |
||||
</Typography> |
||||
{tokenName && ( |
||||
<Typography |
||||
variant={TYPOGRAPHY.H6} |
||||
display={DISPLAY.FLEX} |
||||
color={COLORS.TEXT_ALTERNATIVE} |
||||
> |
||||
{ellipsify(address)} |
||||
</Typography> |
||||
)} |
||||
</Box> |
||||
<Box |
||||
justifyContent={JUSTIFY_CONTENT.FLEX_END} |
||||
className="contract-details-modal__content__contract__buttons" |
||||
> |
||||
<Box marginTop={4} marginRight={5}> |
||||
<Tooltip position="top" title={t('copyToClipboard')}> |
||||
<Button |
||||
className="contract-details-modal__content__contract__buttons__copy" |
||||
type="link" |
||||
> |
||||
<IconCopy color="var(--color-icon-muted)" /> |
||||
</Button> |
||||
</Tooltip> |
||||
</Box> |
||||
<Box marginTop={5} marginRight={5}> |
||||
<Tooltip position="top" title={t('openInBlockExplorer')}> |
||||
<Button |
||||
className="contract-details-modal__content__contract__buttons__block-explorer" |
||||
type="link" |
||||
> |
||||
<IconBlockExplorer |
||||
size={16} |
||||
color="var(--color-icon-muted)" |
||||
/> |
||||
</Button> |
||||
</Tooltip> |
||||
</Box> |
||||
</Box> |
||||
</Box> |
||||
</Box> |
||||
<Box |
||||
display={DISPLAY.FLEX} |
||||
paddingTop={6} |
||||
paddingRight={4} |
||||
paddingBottom={6} |
||||
paddingLeft={4} |
||||
className="contract-details-modal__footer" |
||||
> |
||||
<Button |
||||
type="secondary" |
||||
onClick={() => { |
||||
onClose(); |
||||
}} |
||||
> |
||||
{t('cancel')} |
||||
</Button> |
||||
<Button type="primary">{t('confirm')}</Button> |
||||
</Box> |
||||
</Popover> |
||||
); |
||||
} |
||||
|
||||
ContractDetailsModal.propTypes = { |
||||
onClose: PropTypes.func, |
||||
address: PropTypes.string, |
||||
tokenName: PropTypes.string, |
||||
}; |
@ -0,0 +1,57 @@ |
||||
import React, { useState } from 'react'; |
||||
import Button from '../../../ui/button'; |
||||
import ContractDetailsModal from './contract-details-modal'; |
||||
|
||||
export default { |
||||
title: 'Components/App/Modals/ContractDetailsModal', |
||||
id: __filename, |
||||
argTypes: { |
||||
onClosePopover: { |
||||
action: 'Close Contract Details', |
||||
}, |
||||
onOpenPopover: { |
||||
action: 'Open Contract Details', |
||||
}, |
||||
tokenName: { |
||||
control: { |
||||
type: 'text', |
||||
}, |
||||
}, |
||||
address: { |
||||
control: { |
||||
type: 'text', |
||||
}, |
||||
}, |
||||
}, |
||||
args: { |
||||
tokenName: 'DAI', |
||||
address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', |
||||
}, |
||||
}; |
||||
|
||||
export const DefaultStory = (args) => { |
||||
const [showContractDetails, setshowContractDetails] = useState(false); |
||||
return ( |
||||
<> |
||||
<Button |
||||
onClick={() => { |
||||
args.onOpenPopover(); |
||||
setshowContractDetails(true); |
||||
}} |
||||
> |
||||
Verify contract details |
||||
</Button> |
||||
{showContractDetails && ( |
||||
<ContractDetailsModal |
||||
onClose={() => { |
||||
args.onClosePopover(); |
||||
setshowContractDetails(false); |
||||
}} |
||||
{...args} |
||||
/> |
||||
)} |
||||
</> |
||||
); |
||||
}; |
||||
|
||||
DefaultStory.storyName = 'Default'; |
@ -0,0 +1 @@ |
||||
export { default } from './contract-details-modal'; |
@ -0,0 +1,31 @@ |
||||
.contract-details-modal { |
||||
width: 360px !important; |
||||
|
||||
&__content { |
||||
border-bottom: 1px solid var(--color-border-muted); |
||||
|
||||
&__contract { |
||||
&__identicon { |
||||
margin: 16px 16px 38px 16px; |
||||
} |
||||
|
||||
&__buttons { |
||||
flex-grow: 1; |
||||
|
||||
&__copy.btn-link { |
||||
padding: 0; |
||||
} |
||||
|
||||
&__block-explorer.btn-link { |
||||
padding: 0; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
&__footer { |
||||
button + button { |
||||
margin-inline-start: 1rem; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
import React from 'react'; |
||||
import PropTypes from 'prop-types'; |
||||
|
||||
const IconBlockExplorer = ({ |
||||
size = 24, |
||||
color = 'currentColor', |
||||
ariaLabel, |
||||
className, |
||||
onClick, |
||||
}) => ( |
||||
<svg |
||||
width={size} |
||||
height={size} |
||||
fill={color} |
||||
className={className} |
||||
aria-label={ariaLabel} |
||||
onClick={onClick} |
||||
xmlns="http://www.w3.org/2000/svg" |
||||
viewBox="0 0 512 512" |
||||
> |
||||
<path d="m328 482l-128 0c-115 0-168-52-168-169l0-128c0-115 53-168 168-168l43 0c5 0 10 2 14 6 3 3 5 8 5 13 0 5-2 10-5 14-4 3-9 5-14 5l-43 0c-96 0-130 34-130 130l0 128c0 96 34 131 130 131l128 0c96 0 130-35 130-131l0-42c0-5 3-10 6-14 4-3 9-5 14-5 5 0 10 2 13 5 4 4 6 9 6 14l0 42c0 117-52 169-169 169z m-42-235c-5 0-10-2-14-5-3-4-5-9-5-14 0-5 2-10 5-13l159-160-56 0c-5 0-10-2-13-5-4-4-6-9-6-14 0-5 2-10 6-13 3-4 8-6 13-6l103 0c2 0 5 0 7 1 2 1 5 3 6 5 2 1 4 3 5 6 0 2 1 5 1 7l0 103c0 5-2 10-6 13-3 4-8 6-13 6-5 0-10-2-14-6-3-3-6-8-6-13l0-56-159 159c-3 3-8 5-13 5z" /> |
||||
</svg> |
||||
); |
||||
|
||||
IconBlockExplorer.propTypes = { |
||||
/** |
||||
* The size of the icon in pixels. Should follow 8px grid 16, 24, 32, etc |
||||
*/ |
||||
size: PropTypes.number, |
||||
/** |
||||
* The color of the icon accepts design token css variables |
||||
*/ |
||||
color: PropTypes.string, |
||||
/** |
||||
* An additional className to assign the Icon |
||||
*/ |
||||
className: PropTypes.string, |
||||
/** |
||||
* The onClick handler |
||||
*/ |
||||
onClick: PropTypes.func, |
||||
/** |
||||
* The aria-label of the icon for accessibility purposes |
||||
*/ |
||||
ariaLabel: PropTypes.string, |
||||
}; |
||||
|
||||
export default IconBlockExplorer; |
@ -0,0 +1,47 @@ |
||||
import React from 'react'; |
||||
import PropTypes from 'prop-types'; |
||||
|
||||
const IconCopy = ({ |
||||
size = 24, |
||||
color = 'currentColor', |
||||
ariaLabel, |
||||
className, |
||||
onClick, |
||||
}) => ( |
||||
<svg |
||||
width={size} |
||||
height={size} |
||||
fill={color} |
||||
className={className} |
||||
aria-label={ariaLabel} |
||||
onClick={onClick} |
||||
xmlns="http://www.w3.org/2000/svg" |
||||
viewBox="0 0 512 512" |
||||
> |
||||
<path d="m333 274l0 86c0 72-28 101-100 101l-86 0c-72 0-100-29-100-101l0-86c0-71 28-100 100-100l86 0c72 0 100 29 100 100z m23-223l-86 0c-63 0-93 23-99 77-1 11 8 20 20 20l42 0c86 0 126 40 126 126l0 43c0 11 9 21 21 19 54-6 76-35 76-98l0-86c0-72-28-101-100-101z" /> |
||||
</svg> |
||||
); |
||||
|
||||
IconCopy.propTypes = { |
||||
/** |
||||
* The size of the icon in pixels. Should follow 8px grid 16, 24, 32, etc |
||||
*/ |
||||
size: PropTypes.number, |
||||
/** |
||||
* The color of the icon accepts design token css variables |
||||
*/ |
||||
color: PropTypes.string, |
||||
/** |
||||
* An additional className to assign the Icon |
||||
*/ |
||||
className: PropTypes.string, |
||||
/** |
||||
* The onClick handler |
||||
*/ |
||||
onClick: PropTypes.func, |
||||
/** |
||||
* The aria-label of the icon for accessibility purposes |
||||
*/ |
||||
ariaLabel: PropTypes.string, |
||||
}; |
||||
export default IconCopy; |
Loading…
Reference in new issue