9 changed files with 303 additions and 33 deletions
@ -0,0 +1,30 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React from 'react' |
||||
|
import styled, { keyframes } from 'styled-components' |
||||
|
|
||||
|
import Box from 'components/base/Box' |
||||
|
import IconLoader from 'icons/Loader' |
||||
|
|
||||
|
const rotate = keyframes` |
||||
|
0% { |
||||
|
transform: rotate(0deg); |
||||
|
} |
||||
|
100% { |
||||
|
transform: rotate(360deg); |
||||
|
} |
||||
|
` |
||||
|
|
||||
|
const Container = styled(Box)` |
||||
|
width: ${p => p.size}px; |
||||
|
height: ${p => p.size}px; |
||||
|
animation: ${rotate} 1.5s linear infinite; |
||||
|
` |
||||
|
|
||||
|
export default function Spinner({ size, ...props }: { size: number }) { |
||||
|
return ( |
||||
|
<Container size={size} {...props}> |
||||
|
<IconLoader size={size} /> |
||||
|
</Container> |
||||
|
) |
||||
|
} |
@ -0,0 +1,159 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React, { PureComponent } from 'react' |
||||
|
import styled from 'styled-components' |
||||
|
|
||||
|
import { darken } from 'styles/helpers' |
||||
|
|
||||
|
import Box from 'components/base/Box' |
||||
|
import Radio from 'components/base/Radio' |
||||
|
import CryptoCurrencyIcon from 'components/CryptoCurrencyIcon' |
||||
|
import FormattedVal from 'components/base/FormattedVal' |
||||
|
import Input from 'components/base/Input' |
||||
|
import IconEdit from 'icons/Edit' |
||||
|
import IconCheck from 'icons/Check' |
||||
|
|
||||
|
type Props = { |
||||
|
account: Account, |
||||
|
isChecked: boolean, |
||||
|
onClick: Account => void, |
||||
|
onAccountUpdate: Account => void, |
||||
|
} |
||||
|
|
||||
|
type State = { |
||||
|
isEditing: boolean, |
||||
|
accountNameCopy: string, |
||||
|
} |
||||
|
|
||||
|
export default class AccountRow extends PureComponent<Props, State> { |
||||
|
state = { |
||||
|
isEditing: false, |
||||
|
accountNameCopy: '', |
||||
|
} |
||||
|
|
||||
|
componentDidUpdate(prevProps, prevState) { |
||||
|
const startedEditing = !prevState.isEditing && this.state.isEditing |
||||
|
if (startedEditing) { |
||||
|
this._input.handleSelectEverything() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
handleEditClick = e => { |
||||
|
this.handlePreventSubmit(e) |
||||
|
const { account } = this.props |
||||
|
this.setState({ isEditing: true, accountNameCopy: account.name }) |
||||
|
} |
||||
|
|
||||
|
handleSubmitName = e => { |
||||
|
this.handlePreventSubmit(e) |
||||
|
const { account, onAccountUpdate, isChecked, onClick } = this.props |
||||
|
const { accountNameCopy } = this.state |
||||
|
const updatedAccount = { ...account, name: accountNameCopy } |
||||
|
this.setState({ isEditing: false, accountNameCopy: '' }) |
||||
|
onAccountUpdate(updatedAccount) |
||||
|
if (!isChecked) { |
||||
|
onClick(updatedAccount) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
handlePreventSubmit = e => { |
||||
|
// prevent account row to be submitted
|
||||
|
e.preventDefault() |
||||
|
e.stopPropagation() |
||||
|
} |
||||
|
|
||||
|
handleChangeName = accountNameCopy => this.setState({ accountNameCopy }) |
||||
|
|
||||
|
_input = null |
||||
|
|
||||
|
render() { |
||||
|
const { account, isChecked, onClick } = this.props |
||||
|
const { isEditing, accountNameCopy } = this.state |
||||
|
|
||||
|
return ( |
||||
|
<AccountRowContainer onClick={() => onClick(account)}> |
||||
|
<CryptoCurrencyIcon currency={account.currency} size={16} color={account.currency.color} /> |
||||
|
<Box shrink grow ff="Open Sans|SemiBold" color="dark" fontSize={4}> |
||||
|
{isEditing ? ( |
||||
|
<Input |
||||
|
containerProps={{ style: { width: 260 } }} |
||||
|
value={accountNameCopy} |
||||
|
onChange={this.handleChangeName} |
||||
|
onClick={this.handlePreventSubmit} |
||||
|
onEnter={this.handleSubmitName} |
||||
|
renderRight={ |
||||
|
<InputRight onClick={this.handleSubmitName}> |
||||
|
<IconCheck size={16} /> |
||||
|
</InputRight> |
||||
|
} |
||||
|
ref={input => (this._input = input)} |
||||
|
/> |
||||
|
) : ( |
||||
|
<div style={{ textOverflow: 'ellipsis', overflow: 'hidden' }}>{account.name}</div> |
||||
|
)} |
||||
|
</Box> |
||||
|
{!isEditing && ( |
||||
|
<Edit onClick={this.handleEditClick}> |
||||
|
<IconEdit size={13} /> |
||||
|
<span>{'edit name'}</span> |
||||
|
</Edit> |
||||
|
)} |
||||
|
<FormattedVal |
||||
|
val={account.balance} |
||||
|
unit={account.unit} |
||||
|
showCode |
||||
|
fontSize={4} |
||||
|
color="grey" |
||||
|
/> |
||||
|
<Radio isChecked={isChecked} /> |
||||
|
</AccountRowContainer> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const AccountRowContainer = styled(Box).attrs({ |
||||
|
horizontal: true, |
||||
|
align: 'center', |
||||
|
bg: 'lightGrey', |
||||
|
px: 3, |
||||
|
flow: 3, |
||||
|
})` |
||||
|
height: 48px; |
||||
|
border-radius: 4px; |
||||
|
cursor: pointer; |
||||
|
|
||||
|
&:hover { |
||||
|
background-color: ${p => darken(p.theme.colors.lightGrey, 0.015)}; |
||||
|
} |
||||
|
|
||||
|
&:active { |
||||
|
background-color: ${p => darken(p.theme.colors.lightGrey, 0.03)}; |
||||
|
} |
||||
|
` |
||||
|
|
||||
|
const Edit = styled(Box).attrs({ |
||||
|
color: 'wallet', |
||||
|
fontSize: 3, |
||||
|
horizontal: true, |
||||
|
align: 'center', |
||||
|
flow: 1, |
||||
|
py: 1, |
||||
|
})` |
||||
|
display: none; |
||||
|
${AccountRowContainer}:hover & { |
||||
|
display: flex; |
||||
|
} |
||||
|
&:hover { |
||||
|
text-decoration: underline; |
||||
|
} |
||||
|
` |
||||
|
|
||||
|
const InputRight = styled(Box).attrs({ |
||||
|
bg: 'wallet', |
||||
|
color: 'white', |
||||
|
align: 'center', |
||||
|
justify: 'center', |
||||
|
shrink: 0, |
||||
|
})` |
||||
|
width: 40px; |
||||
|
` |
Loading…
Reference in new issue