mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Add tx list-item component (#8195)
* Add tx list-item component New list item compoent for transaction history * Simplify component logic and remove type checks * Address remaining feedback * Remove extra line * Place className prop on its own line * Rename to primaryCurrency and secondaryCurrency * Make the title `isRequired` * Fix no-undef * Remove more + buttons to be implemented in seperate PR * Add minimal store and I18nProvider to storybook * Use Component to support translations * Add `metamask` to store * Rename decorator
This commit is contained in:
parent
4d38a59182
commit
8ba35f673e
@ -1,7 +1,11 @@
|
||||
import React from 'react'
|
||||
import { addDecorator, addParameters } from '@storybook/react'
|
||||
import { withKnobs } from '@storybook/addon-knobs/react'
|
||||
import I18nProvider from '../ui/app/helpers/higher-order-components/i18n-provider'
|
||||
import { Provider } from 'react-redux'
|
||||
import configureStore from '../ui/app/store/store'
|
||||
import '../ui/app/css/index.scss'
|
||||
import en from '../app/_locales/en/messages'
|
||||
|
||||
addParameters({
|
||||
backgrounds: [
|
||||
@ -17,11 +21,24 @@ const styles = {
|
||||
alignItems: 'center',
|
||||
}
|
||||
|
||||
const CenterDecorator = story => (
|
||||
<div style={styles}>
|
||||
{ story() }
|
||||
</div>
|
||||
const store = configureStore({
|
||||
metamask: { metamask: { currentLocale: 'en' } },
|
||||
|
||||
localeMessages: {
|
||||
current: en,
|
||||
en: en,
|
||||
},
|
||||
})
|
||||
|
||||
const metamaskDecorator = story => (
|
||||
<Provider store={store}>
|
||||
<I18nProvider>
|
||||
<div style={styles}>
|
||||
{ story() }
|
||||
</div>
|
||||
</I18nProvider>
|
||||
</Provider>
|
||||
)
|
||||
|
||||
addDecorator(withKnobs)
|
||||
addDecorator(CenterDecorator)
|
||||
addDecorator(metamaskDecorator)
|
||||
|
3
ui/app/components/ui/list-item/index.js
Normal file
3
ui/app/components/ui/list-item/index.js
Normal file
@ -0,0 +1,3 @@
|
||||
import ListItem from './list-item.component'
|
||||
|
||||
export default ListItem
|
64
ui/app/components/ui/list-item/index.scss
Normal file
64
ui/app/components/ui/list-item/index.scss
Normal file
@ -0,0 +1,64 @@
|
||||
.list-item {
|
||||
width: 100%;
|
||||
min-width: 374px;
|
||||
min-height: 86px;
|
||||
margin: 0 20px;
|
||||
background: #FFFFFF;
|
||||
padding: 24px 16px;
|
||||
@extend %font;
|
||||
border-top: 1px solid $mercury;
|
||||
border-bottom: 1px solid $mercury;
|
||||
color: $Grey-500;
|
||||
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
|
||||
&__icon {
|
||||
margin: 8px 14px 0 0;
|
||||
}
|
||||
|
||||
&__col {
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
&__heading {
|
||||
font-size: 16px;
|
||||
line-height: 160%;
|
||||
position: relative;
|
||||
|
||||
&-wrap {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&__subheading {
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
&__status {
|
||||
&--unapproved {
|
||||
color: $flamingo;
|
||||
}
|
||||
&--failed {
|
||||
color: $valencia;
|
||||
}
|
||||
}
|
||||
|
||||
&__approved {
|
||||
.list-item__heading {
|
||||
color: $shark;
|
||||
}
|
||||
}
|
||||
|
||||
&__amount {
|
||||
margin: 0 0 0 auto;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
138
ui/app/components/ui/list-item/list-item.component.js
Normal file
138
ui/app/components/ui/list-item/list-item.component.js
Normal file
@ -0,0 +1,138 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Approve from '../icon/approve-icon.component'
|
||||
import Interaction from '../icon/interaction-icon.component'
|
||||
import Preloader from '../icon/preloader'
|
||||
import Send from '../icon/send-icon.component'
|
||||
import classnames from 'classnames'
|
||||
|
||||
const SendIcon = () => (
|
||||
<Send
|
||||
className="list-item__icon"
|
||||
size={28}
|
||||
color="#2F80ED"
|
||||
/>
|
||||
)
|
||||
|
||||
const InteractionIcon = () => (
|
||||
<Interaction
|
||||
className="list-item__icon"
|
||||
size={28}
|
||||
color="#2F80ED"
|
||||
/>
|
||||
)
|
||||
|
||||
const ApproveIcon = () => (
|
||||
<Approve
|
||||
className="list-item__icon"
|
||||
size={28}
|
||||
color="#2F80ED"
|
||||
/>
|
||||
)
|
||||
|
||||
const FailIcon = () => (
|
||||
<Interaction
|
||||
className="list-item__icon"
|
||||
size={28}
|
||||
color="#D73A49"
|
||||
/>
|
||||
)
|
||||
|
||||
export default class ListItem extends Component {
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
className: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
title: PropTypes.string.isRequired,
|
||||
subtitle: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
primaryCurrency: PropTypes.string,
|
||||
secondaryCurrency: PropTypes.string,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
status: 'pending',
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
className,
|
||||
status,
|
||||
title,
|
||||
subtitle,
|
||||
children,
|
||||
primaryCurrency,
|
||||
secondaryCurrency,
|
||||
} = this.props
|
||||
const { t } = this.context
|
||||
|
||||
const isApproved = status === 'approved'
|
||||
const isUnapproved = status === 'unapproved'
|
||||
const isPending = status === 'pending'
|
||||
const isFailed = status === 'failed'
|
||||
|
||||
let icon = <InteractionIcon />
|
||||
if (isApproved) {
|
||||
icon = <ApproveIcon />
|
||||
} else if (isPending) {
|
||||
icon = <SendIcon />
|
||||
} else if (isFailed) {
|
||||
icon = <FailIcon />
|
||||
}
|
||||
|
||||
let subtitleStatus = null
|
||||
if (isUnapproved) {
|
||||
subtitleStatus = (
|
||||
<span><span className="list-item__status--unapproved">{t('unapproved')}</span> · </span>
|
||||
)
|
||||
} else if (isFailed) {
|
||||
subtitleStatus = (
|
||||
<span><span className="list-item__status--failed">{t('failed')}</span> · </span>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<div className="list-item__col">
|
||||
{ icon }
|
||||
</div>
|
||||
<div
|
||||
className={classnames('list-item__col', {
|
||||
'list-item__approved': isApproved,
|
||||
})}
|
||||
>
|
||||
<h2 className="list-item__heading">
|
||||
{ title } {isPending && (
|
||||
<span className="list-item__heading-wrap">
|
||||
<Preloader
|
||||
size={16}
|
||||
color="#D73A49"
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
</h2>
|
||||
<h3 className="list-item__subheading">
|
||||
{subtitleStatus}
|
||||
{subtitle}
|
||||
</h3>
|
||||
{children && (
|
||||
<div className="list-item__more">
|
||||
{ children }
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={classnames('list-item__col list-item__amount', {
|
||||
'list-item__approved': isApproved,
|
||||
})}
|
||||
>
|
||||
<h2 className="list-item__heading">{primaryCurrency}</h2>
|
||||
<h3 className="list-item__subheading">{secondaryCurrency}</h3>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
51
ui/app/components/ui/list-item/list-item.stories.js
Normal file
51
ui/app/components/ui/list-item/list-item.stories.js
Normal file
@ -0,0 +1,51 @@
|
||||
import React from 'react'
|
||||
import ListItem from './list-item.component'
|
||||
import { text } from '@storybook/addon-knobs/react'
|
||||
|
||||
export default {
|
||||
title: 'ListItem',
|
||||
}
|
||||
|
||||
export const send = () => (
|
||||
<ListItem
|
||||
title={text('title', 'Send DAI')}
|
||||
className="list-item"
|
||||
status="pending"
|
||||
subtitle={text('subtitle', 'Sept 20 · To: 00X4...3058')}
|
||||
primaryCurrency={text('primaryCurrency', '- 0.0732 DAI')}
|
||||
secondaryCurrency={text('secondaryCurrency', '- $6.04 USD')}
|
||||
/>
|
||||
)
|
||||
|
||||
export const pending = () => (
|
||||
<ListItem
|
||||
title={text('title', 'Hatch Turtles')}
|
||||
className="list-item"
|
||||
status="unapproved"
|
||||
subtitle={text('subtitle', 'Turtlefarm.com')}
|
||||
primaryCurrency={text('primaryCurrency', '- 0.0732 ETH')}
|
||||
secondaryCurrency={text('secondaryCurrency', '- $6.00 USD')}
|
||||
/>
|
||||
)
|
||||
|
||||
export const approve = () => (
|
||||
<ListItem
|
||||
title={text('title', 'Approve spend limit')}
|
||||
className="list-item"
|
||||
status="approved"
|
||||
subtitle={text('subtitle', 'Sept 20 · oxuniverse.com')}
|
||||
primaryCurrency={text('primaryCurrency', '0.00070 DAI')}
|
||||
secondaryCurrency={text('secondaryCurrency', '$0.02 USD')}
|
||||
/>
|
||||
)
|
||||
|
||||
export const failed = () => (
|
||||
<ListItem
|
||||
title={text('title', 'Hatch Turtles')}
|
||||
className="list-item"
|
||||
status="failed"
|
||||
subtitle={text('subtitle', 'Turtlefarm.com')}
|
||||
primaryCurrency={text('primaryCurrency', '- 0.0732 ETH')}
|
||||
secondaryCurrency={text('secondaryCurrency', '- $6.00 USD')}
|
||||
/>
|
||||
)
|
@ -1,6 +1,7 @@
|
||||
@import '../../../components/ui/button/buttons';
|
||||
@import '../../../components/ui/dialog/dialog';
|
||||
@import '../../../components/ui/snackbar/index';
|
||||
@import '../../../components/ui/list-item/index';
|
||||
@import '../../../components/ui/icon/preloader/index';
|
||||
|
||||
@import './footer.scss';
|
||||
|
@ -17,6 +17,8 @@ $white-linen: #faf6f0; // formerly 'faint orange (textfield shades)'
|
||||
$rajah: #f5c26d; // formerly 'light orange (button shades)'
|
||||
$buttercup: #f5a623; // formerly 'dark orange (text)'
|
||||
$tundora: #4a4a4a; // formerly 'borders/font/any gray'
|
||||
$flamingo: #F56821;
|
||||
$valencia: #D73A49;
|
||||
$gallery: #efefef;
|
||||
$alabaster: #f7f7f7;
|
||||
$shark: #22232c;
|
||||
@ -60,6 +62,8 @@ $polar: #fafcfe;
|
||||
$blizzard-blue: #bfdef3;
|
||||
$mischka: #dddee9;
|
||||
$web-orange: #f2a202;
|
||||
$mercury: #E5E5E5;
|
||||
$lochmara: #037DD6;
|
||||
|
||||
/*
|
||||
notification and error message colors
|
||||
|
Loading…
Reference in New Issue
Block a user