Browse Source

Add Send, Receive and Options button in Account page

master
Loëck Vézien 7 years ago
parent
commit
c0f80baac7
No known key found for this signature in database GPG Key ID: CBCDCE384E853AC4
  1. 6
      package.json
  2. 54
      src/components/AccountPage.js
  3. 8
      src/components/DashboardPage.js
  4. 20
      src/components/SideBar/Item.js
  5. 8
      src/components/SideBar/index.js
  6. 53
      src/components/base/Button/index.js
  7. 8
      src/components/base/Modal/index.js
  8. 4
      src/components/modals/AddAccount/index.js
  9. 25
      src/components/modals/Receive.js
  10. 18
      src/components/modals/Send.js
  11. 4
      src/constants.js
  12. 3
      src/reducers/modals.js
  13. 18
      src/styles/global.js
  14. 2
      src/styles/theme.js
  15. 43
      yarn.lock

6
package.json

@ -53,7 +53,7 @@
"bs58check": "^2.1.1",
"color": "^3.0.0",
"cross-env": "^5.1.3",
"downshift": "^1.26.0",
"downshift": "^1.26.1",
"electron-store": "^1.3.0",
"electron-updater": "^2.20.1",
"fuse.js": "^3.2.0",
@ -80,7 +80,7 @@
"redux-thunk": "^2.2.0",
"shortid": "^2.2.8",
"source-map-support": "^0.5.3",
"styled-components": "^3.1.1",
"styled-components": "^3.1.2",
"styled-system": "^1.1.1"
},
"devDependencies": {
@ -113,7 +113,7 @@
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-react": "^7.6.1",
"flow-bin": "^0.64.0",
"flow-typed": "^2.2.3",
"flow-typed": "^2.3.0",
"husky": "^0.14.3",
"lint-staged": "^6.1.0",
"node-loader": "^0.6.0",

54
src/components/AccountPage.js

@ -1,23 +1,32 @@
// @flow
import React, { PureComponent, Fragment } from 'react'
import { compose } from 'redux'
import { connect } from 'react-redux'
import { translate } from 'react-i18next'
import { MODAL_SEND, MODAL_RECEIVE } from 'constants'
import type { MapStateToProps } from 'react-redux'
import type { Account, AccountData } from 'types/common'
import type { T, Account, AccountData } from 'types/common'
import { formatBTC } from 'helpers/format'
import { getAccountById, getAccountData } from 'reducers/accounts'
import { openModal } from 'reducers/modals'
import TransactionsList from 'components/TransactionsList'
import Box, { Card } from 'components/base/Box'
import Text from 'components/base/Text'
import Button from 'components/base/Button'
import Icon from 'components/base/Icon'
import ReceiveBox from 'components/ReceiveBox'
import Text from 'components/base/Text'
import TransactionsList from 'components/TransactionsList'
type Props = {
t: T,
account: Account,
accountData: AccountData,
openModal: Function,
}
const mapStateToProps: MapStateToProps<*, *, *> = (state, props) => ({
@ -25,14 +34,45 @@ const mapStateToProps: MapStateToProps<*, *, *> = (state, props) => ({
accountData: getAccountData(state, props.match.params.id),
})
const mapDispatchToProps = {
openModal,
}
class AccountPage extends PureComponent<Props> {
render() {
const { account, accountData } = this.props
const { account, accountData, openModal, t } = this.props
return (
<Box flow={3}>
<Box>
<Text fontSize={4}>{`${account.name} account`}</Text>
<Box horizontal>
<Box>
<Text fontSize={4}>{`${account.name} account`}</Text>
</Box>
<Box horizontal align="center" justify="flex-end" grow flow={20}>
<Box>
<Button primary onClick={() => openModal(MODAL_SEND, { account })}>
<Box horizontal flow={2}>
<Box>
<Icon name="upload" />
</Box>
<Box>{t('send.title')}</Box>
</Box>
</Button>
</Box>
<Box>
<Button primary onClick={() => openModal(MODAL_RECEIVE, { account })}>
<Box horizontal flow={2}>
<Box>
<Icon name="download" />
</Box>
<Box>{t('receive.title')}</Box>
</Box>
</Button>
</Box>
<Box>
<Button icon="sliders-h" />
</Box>
</Box>
</Box>
{accountData && (
<Fragment>
@ -59,4 +99,4 @@ class AccountPage extends PureComponent<Props> {
}
}
export default connect(mapStateToProps)(AccountPage)
export default compose(connect(mapStateToProps, mapDispatchToProps), translate())(AccountPage)

8
src/components/DashboardPage.js

@ -7,6 +7,8 @@ import { connect } from 'react-redux'
import chunk from 'lodash/chunk'
import { push } from 'react-router-redux'
import { MODAL_ADD_ACCOUNT } from 'constants'
import type { MapStateToProps } from 'react-redux'
import type { Accounts, T } from 'types/common'
@ -106,7 +108,7 @@ class DashboardPage extends PureComponent<Props, State> {
/>
</Card>
<Box flow={3}>
{chunk([...Object.keys(accounts), 'add-account'], 3).map((line, i) => (
{chunk([...Object.keys(accounts), MODAL_ADD_ACCOUNT], 3).map((line, i) => (
<Box
key={i} // eslint-disable-line react/no-array-index-key
horizontal
@ -114,7 +116,7 @@ class DashboardPage extends PureComponent<Props, State> {
>
{line.map(
key =>
key === 'add-account' ? (
key === MODAL_ADD_ACCOUNT ? (
<Box
key={key}
p={3}
@ -124,7 +126,7 @@ class DashboardPage extends PureComponent<Props, State> {
justify="center"
borderColor="mouse"
style={{ borderStyle: 'dashed', cursor: 'pointer', textAlign: 'center' }}
onClick={() => openModal('add-account')}
onClick={() => openModal(MODAL_ADD_ACCOUNT)}
>
{`+ ${t('addAccount.title')}`}
</Box>

20
src/components/SideBar/Item.js

@ -7,7 +7,7 @@ import { withRouter } from 'react-router'
import { push } from 'react-router-redux'
import { connect } from 'react-redux'
import { openModal, isModalOpened } from 'reducers/modals'
import { openModal } from 'reducers/modals'
import type { MapStateToProps } from 'react-redux'
import type { Location } from 'react-router'
@ -16,11 +16,10 @@ import Box from 'components/base/Box'
import Text from 'components/base/Text'
import Icon from 'components/base/Icon'
const mapStateToProps: MapStateToProps<*, *, *> = (state, { modal }: any) => ({
const mapStateToProps: MapStateToProps<*, *, *> = (state: any) => ({
// connect router here only to make components re-render
// see https://github.com/ReactTraining/react-router/issues/4671
router: state.router,
isModalOpened: modal ? isModalOpened(state, modal) : false,
})
const mapDispatchToProps = {
@ -54,24 +53,13 @@ type Props = {
desc?: string | null,
icon?: string | null,
location: Location,
isModalOpened: boolean,
push: Function,
openModal: Function,
}
function Item({
children,
desc,
icon,
linkTo,
push,
location,
modal,
openModal,
isModalOpened,
}: Props) {
function Item({ children, desc, icon, linkTo, push, location, modal, openModal }: Props) {
const { pathname } = location
const isActive = pathname === linkTo || isModalOpened
const isActive = pathname === linkTo
return (
<Container
onClick={

8
src/components/SideBar/index.js

@ -6,6 +6,8 @@ import { translate } from 'react-i18next'
import styled from 'styled-components'
import { connect } from 'react-redux'
import { MODAL_SEND, MODAL_RECEIVE, MODAL_ADD_ACCOUNT } from 'constants'
import type { MapStateToProps } from 'react-redux'
import type { Accounts, T } from 'types/common'
@ -73,10 +75,10 @@ class SideBar extends PureComponent<Props> {
<Item icon="chart-bar" linkTo="/">
{t('dashboard.title')}
</Item>
<Item icon="upload" modal="send">
<Item icon="upload" modal={MODAL_SEND}>
{t('send.title')}
</Item>
<Item icon="download" modal="receive">
<Item icon="download" modal={MODAL_RECEIVE}>
{t('receive.title')}
</Item>
<Item icon="cog" linkTo="/settings">
@ -94,7 +96,7 @@ class SideBar extends PureComponent<Props> {
))}
</div>
</Box>
<BtnAddAccount onClick={() => openModal('add-account')}>
<BtnAddAccount onClick={() => openModal(MODAL_ADD_ACCOUNT)}>
{t('addAccount.title')}
</BtnAddAccount>
</GrowScroll>

53
src/components/base/Button/index.js

@ -2,36 +2,69 @@
import React from 'react'
import styled from 'styled-components'
import { space, fontSize, fontWeight, color } from 'styled-system'
import { borderColor, borderWidth, space, fontSize, fontWeight, color } from 'styled-system'
const Base = styled.button.attrs({
px: 4,
fontSize: 1,
})`
import Icon from 'components/base/Icon'
const Base = styled.button`
${borderColor};
${borderWidth};
${space};
${color};
${fontSize};
${fontWeight};
border-radius: 5px;
cursor: pointer;
border: none;
height: 40px;
box-shadow: ${p => (p.withShadow ? 'rgba(0, 0, 0, 0.2) 0 3px 10px' : '')};
outline: none;
`
type Props = {
children?: any,
icon?: string,
primary?: boolean,
}
const Button = ({ primary, ...props }: Props) => {
if (primary) {
return <Base fontWeight="bold" color="white" bg="blue" withShadow {...props} />
const Button = ({ primary, children, icon, ...props }: Props) => {
children = icon ? <Icon name={icon} /> : children
props = {
...props,
bg: 'transparent',
color: 'mouse',
...(icon
? {
fontSize: 3,
px: 1,
}
: {
fontSize: 1,
px: 3,
}),
...(primary
? {
color: 'white',
bg: 'blue',
borderWidth: 0,
withShadow: true,
}
: {
borderColor: 'mouse',
borderWidth: 1,
}),
}
return <Base color="white" {...props} />
return (
<Base {...props} icon={icon}>
{children}
</Base>
)
}
Button.defaultProps = {
children: undefined,
icon: undefined,
primary: false,
}

8
src/components/base/Modal/index.js

@ -11,7 +11,7 @@ import noop from 'lodash/noop'
import { rgba } from 'styles/helpers'
import { closeModal, isModalOpened } from 'reducers/modals'
import { closeModal, isModalOpened, getModalData } from 'reducers/modals'
import Box from 'components/base/Box'
import Icon from 'components/base/Icon'
@ -22,6 +22,7 @@ type Props = {
preventBackdropClick?: boolean,
preventSideMargin?: boolean,
render: Function,
data?: any,
}
const springConfig = {
@ -30,6 +31,7 @@ const springConfig = {
const mapStateToProps = (state, { name, isOpened }) => ({
isOpened: isOpened || (name && isModalOpened(state, name)),
data: getModalData(state, name),
})
const mapDispatchToProps = (dispatch, { name, onClose = noop }) => ({
@ -110,7 +112,7 @@ export class Modal extends PureComponent<Props> {
}
render() {
const { preventBackdropClick, preventSideMargin, isOpened, onClose, render } = this.props
const { preventBackdropClick, preventSideMargin, isOpened, onClose, render, data } = this.props
return (
<Mortal
isOpened={isOpened}
@ -124,7 +126,7 @@ export class Modal extends PureComponent<Props> {
<Container isVisible={isVisible}>
<Backdrop op={m.opacity} onClick={preventBackdropClick ? undefined : onClose} />
<Wrapper preventSideMargin={preventSideMargin} op={m.opacity} offset={m.y}>
{render({ onClose })}
{render({ data, onClose })}
</Wrapper>
</Container>
)}

4
src/components/modals/AddAccount/index.js

@ -4,6 +4,8 @@ import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { ipcRenderer } from 'electron'
import { MODAL_ADD_ACCOUNT } from 'constants'
import type { MapStateToProps } from 'react-redux'
import type { Accounts, Device } from 'types/common'
@ -280,7 +282,7 @@ class AddAccountModal extends PureComponent<Props, State> {
return (
<Modal
name="add-account"
name={MODAL_ADD_ACCOUNT}
preventBackdropClick={step !== 'chooseWallet'}
onClose={this.handleClose}
render={({ onClose }) => (

25
src/components/modals/Receive.js

@ -2,6 +2,9 @@
import React, { PureComponent } from 'react'
import { translate } from 'react-i18next'
import get from 'lodash/get'
import { MODAL_RECEIVE } from 'constants'
import Modal, { ModalBody } from 'components/base/Modal'
import Text from 'components/base/Text'
@ -17,27 +20,41 @@ type State = {
account: AccountType | null,
}
const defaultState = {
account: null,
}
class ReceiveModal extends PureComponent<Props, State> {
state = {
account: null,
...defaultState,
}
handleChangeAccount = account => {
this.setState({ account })
}
handleClose = () =>
this.setState({
...defaultState,
})
render() {
const { account } = this.state
const { t } = this.props
return (
<Modal
name="receive"
render={({ onClose }) => (
name={MODAL_RECEIVE}
onClose={this.handleClose}
render={({ data, onClose }) => (
<ModalBody onClose={onClose} flow={3}>
<Text fontSize={4} color="steel">
{t('receive.modalTitle')}
</Text>
<SelectAccount value={account} onChange={this.handleChangeAccount} />
<SelectAccount
value={account || get(data, 'account')}
onChange={this.handleChangeAccount}
/>
</ModalBody>
)}
/>

18
src/components/modals/Send.js

@ -2,6 +2,9 @@
import React, { Fragment, PureComponent } from 'react'
import styled from 'styled-components'
import get from 'lodash/get'
import { MODAL_SEND } from 'constants'
import Button from 'components/base/Button'
import Input from 'components/base/Input'
@ -71,7 +74,7 @@ type State = {
const defaultState = {
inputValue: {
account: undefined,
account: null,
address: '',
amount: '',
},
@ -83,7 +86,7 @@ class Send extends PureComponent<{}, State> {
...defaultState,
}
getStepProps() {
getStepProps(data: any) {
const { inputValue, step } = this.state
const props = (predicate, props) => (predicate ? props : {})
@ -91,7 +94,10 @@ class Send extends PureComponent<{}, State> {
return {
...props(step === 'amount', {
onChangeInput: this.handleChangeInput,
value: inputValue,
value: {
...inputValue,
account: inputValue.account || get(data, 'account'),
},
}),
...props(step === 'summary', {
value: inputValue,
@ -125,13 +131,13 @@ class Send extends PureComponent<{}, State> {
return (
<Modal
name="send"
name={MODAL_SEND}
onClose={this.handleClose}
render={({ onClose }) => (
render={({ data, onClose }) => (
<Fragment>
<ModalBody>{step}</ModalBody>
<ModalBody onClose={onClose}>
<Step {...this.getStepProps()} />
<Step {...this.getStepProps(data)} />
</ModalBody>
</Fragment>
)}

4
src/constants.js

@ -1,2 +1,6 @@
export const CHECK_UPDATE_TIMEOUT = 5e3
export const SYNC_ACCOUNT_TIMEOUT = 3e3
export const MODAL_ADD_ACCOUNT = 'MODAL_ADD_ACCOUNT'
export const MODAL_SEND = 'MODAL_SEND'
export const MODAL_RECEIVE = 'MODAL_RECEIVE'

3
src/reducers/modals.js

@ -53,6 +53,9 @@ export const closeModal = createAction('MODAL_CLOSE', name => ({ name }))
export const isModalOpened = (state: Object, name: string) =>
state.modals[name] && state.modals[name].isOpened
export const getModalData = (state: Object, name: string) =>
state.modals[name] && state.modals[name].data
// Exporting reducer
export default handleActions(handlers, state)

18
src/styles/global.js

@ -21,6 +21,10 @@ injectGlobal`
flex-shrink: 0;
}
html {
-ms-overflow-style: -ms-autohiding-scrollbar;
}
body {
line-height: 1.5;
font-size: 16px;
@ -40,8 +44,18 @@ injectGlobal`
em {
font-style: italic;
}
::-webkit-scrollbar {
display: none;
background-color: rgba(0, 0, 0, 0);
width: 6px;
}
::-webkit-scrollbar:hover {
background-color: rgba(0, 0, 0, 0.09);
}
::-webkit-scrollbar-thumb:vertical {
background: rgba(0, 0, 0, 0.5);
}
::-webkit-scrollbar-thumb:vertical:active {
background: rgba(0, 0, 0, 0.61);
}
`

2
src/styles/theme.js

@ -5,6 +5,8 @@ export default {
sideBarWidth: 250,
},
colors: {
transparent: 'transparent',
black: '#000000',
white: '#ffffff',

43
yarn.lock

@ -1481,7 +1481,7 @@ babel-plugin-transform-undefined-to-void@^6.8.3:
version "6.8.3"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.8.3.tgz#fc52707f6ee1ddc71bb91b0d314fbefdeef9beb4"
babel-polyfill@^6.23.0:
babel-polyfill@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153"
dependencies:
@ -3138,9 +3138,9 @@ dotenv@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-4.0.0.tgz#864ef1379aced55ce6f95debecdce179f7a0cd1d"
downshift@^1.26.0:
version "1.26.0"
resolved "https://registry.yarnpkg.com/downshift/-/downshift-1.26.0.tgz#1ee954fef129861f977c6b9effe93fb78e7dc363"
downshift@^1.26.1:
version "1.26.1"
resolved "https://registry.yarnpkg.com/downshift/-/downshift-1.26.1.tgz#ae45a016f211d02f8000584d0b466142fde2dd6b"
duplexer3@^0.1.4:
version "0.1.4"
@ -4078,25 +4078,24 @@ flow-bin@^0.64.0:
version "0.64.0"
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.64.0.tgz#ddd3fb3b183ab1ab35a5d5dec9caf5ebbcded167"
flow-typed@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/flow-typed/-/flow-typed-2.2.3.tgz#e7a35915a0f4cfcf8068c1ce291b5c99e6b89efa"
flow-typed@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/flow-typed/-/flow-typed-2.3.0.tgz#0f8604faab60691b885024e16ec0e3256e3b680e"
dependencies:
babel-polyfill "^6.23.0"
babel-polyfill "^6.26.0"
colors "^1.1.2"
fs-extra "^4.0.0"
fs-extra "^5.0.0"
github "0.2.4"
glob "^7.1.2"
got "^7.1.0"
md5 "^2.1.0"
mkdirp "^0.5.1"
request "^2.81.0"
rimraf "^2.6.1"
semver "^5.1.0"
table "^4.0.1"
rimraf "^2.6.2"
semver "^5.5.0"
table "^4.0.2"
through "^2.3.8"
unzip "^0.1.11"
which "^1.2.14"
which "^1.3.0"
yargs "^4.2.0"
flush-write-stream@^1.0.0:
@ -4184,7 +4183,7 @@ fs-extra@^0.30.0:
path-is-absolute "^1.0.0"
rimraf "^2.2.8"
fs-extra@^4.0.0, fs-extra@^4.0.1:
fs-extra@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
dependencies:
@ -7799,7 +7798,7 @@ request@2.81.0:
tunnel-agent "^0.6.0"
uuid "^3.0.0"
request@^2.45.0, request@^2.81.0, request@^2.83.0:
request@^2.45.0, request@^2.83.0:
version "2.83.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356"
dependencies:
@ -7905,7 +7904,7 @@ right-align@^0.1.1:
dependencies:
align-text "^0.1.1"
rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1:
rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
dependencies:
@ -8536,9 +8535,9 @@ style-loader@^0.19.0, style-loader@^0.19.1:
loader-utils "^1.0.2"
schema-utils "^0.3.0"
styled-components@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-3.1.1.tgz#7896819070b2663c6519f428017d6ca7e2a3c7cd"
styled-components@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-3.1.2.tgz#0769655335eb6800dc5f6691425f6f7fe1801e32"
dependencies:
buffer "^5.0.3"
css-to-react-native "^2.0.3"
@ -8631,7 +8630,7 @@ symbol-observable@^1.0.3:
version "1.1.0"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.1.0.tgz#5c68fd8d54115d9dfb72a84720549222e8db9b32"
table@^4.0.1:
table@^4.0.1, table@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36"
dependencies:
@ -9286,7 +9285,7 @@ which-module@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
which@^1.2.10, which@^1.2.14, which@^1.2.9:
which@^1.2.10, which@^1.2.9, which@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
dependencies:

Loading…
Cancel
Save