Browse Source

Use react-router for switch tab in SettingsPage

master
Loëck Vézien 7 years ago
committed by meriadec
parent
commit
88862249ce
No known key found for this signature in database GPG Key ID: 1D2FC2305E2CB399
  1. 3
      src/components/SelectAccount/index.js
  2. 60
      src/components/SelectCurrency/index.js
  3. 31
      src/components/SelectCurrency/stories.js
  4. 31
      src/components/SettingsPage/SettingsSection.js
  5. 82
      src/components/SettingsPage/index.js
  6. 21
      src/components/SettingsPage/sections/Currencies.js
  7. 10
      src/components/SideBar/Item.js
  8. 10
      src/components/TopBar.js
  9. 19
      src/components/base/Button/index.js
  10. 1
      src/components/base/CheckBox/index.js
  11. 1
      src/components/layout/Default.js
  12. 1
      static/i18n/en/common.yml

3
src/components/SelectAccount/index.js

@ -3,9 +3,10 @@
import React from 'react' import React from 'react'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import noop from 'lodash/noop'
import { getIconByCoinType } from '@ledgerhq/currencies/react' import { getIconByCoinType } from '@ledgerhq/currencies/react'
import noop from 'lodash/noop'
import type { Account } from '@ledgerhq/wallet-common/lib/types' import type { Account } from '@ledgerhq/wallet-common/lib/types'
import type { T } from 'types/common' import type { T } from 'types/common'

60
src/components/SelectCurrency/index.js

@ -0,0 +1,60 @@
// @flow
import React from 'react'
import { translate } from 'react-i18next'
import { getIconByCoinType } from '@ledgerhq/currencies/react'
import { listCurrencies } from '@ledgerhq/currencies'
import noop from 'lodash/noop'
import type { Currency } from '@ledgerhq/currencies'
import type { T } from 'types/common'
import Select from 'components/base/Select'
import Box from 'components/base/Box'
const renderItem = a => {
const { color, name, coinType } = a
const Icon = getIconByCoinType(coinType)
return (
<Box grow horizontal alignItems="center" flow={2}>
{Icon && (
<Box style={{ width: 16, height: 16, color }}>
<Icon size={16} />
</Box>
)}
<Box grow ff="Open Sans|SemiBold" color="dark" fontSize={4}>
{name}
</Box>
</Box>
)
}
const currencies = listCurrencies()
type Props = {
onChange: Function,
value?: Currency,
t: T,
}
const SelectCurrency = ({ onChange, value, t, ...props }: Props) => (
<Select
{...props}
value={value}
renderSelected={renderItem}
renderItem={renderItem}
keyProp="coinType"
items={currencies.sort((a, b) => (a.name < b.name ? -1 : 1))}
placeholder={t('common:selectCurrency')}
fontSize={4}
onChange={onChange}
/>
)
SelectCurrency.defaultProps = {
onChange: noop,
value: undefined,
}
export default translate()(SelectCurrency)

31
src/components/SelectCurrency/stories.js

@ -0,0 +1,31 @@
// @flow
import React, { Component } from 'react'
import { storiesOf } from '@storybook/react'
import { action } from '@storybook/addon-actions'
import SelectCurrency from 'components/SelectCurrency'
const stories = storiesOf('Components', module)
class Wrapper extends Component<any, any> {
state = {
value: '',
}
handleChange = item => {
this.setState({ value: item })
action('onChange')(item)
}
render() {
const { render } = this.props
const { value } = this.state
return render({ onChange: this.handleChange, value })
}
}
stories.add('SelectCurrency', () => (
<Wrapper render={({ onChange, value }) => <SelectCurrency onChange={onChange} value={value} />} />
))

31
src/components/SettingsPage/SettingsSection.js

@ -31,7 +31,16 @@ const RoundIconContainer = styled(Box).attrs({
export const SettingsSectionBody = styled(Box)` export const SettingsSectionBody = styled(Box)`
> * + * { > * + * {
border-top: 1px solid ${p => p.theme.colors.lightFog}; &:after {
background: ${p => p.theme.colors.lightFog};
content: '';
display: block;
height: 1px;
left: ${p => p.theme.space[4]}px;
position: absolute;
right: ${p => p.theme.space[4]}px;
top: 0;
}
} }
` `
@ -39,15 +48,17 @@ export function SettingsSectionHeader({
title, title,
desc, desc,
icon, icon,
renderRight,
}: { }: {
title: string, title: string,
desc: string, desc: string,
icon: any, icon: any,
renderRight?: any,
}) { }) {
return ( return (
<SettingsSectionHeaderContainer> <SettingsSectionHeaderContainer>
<RoundIconContainer mr={3}>{icon}</RoundIconContainer> <RoundIconContainer mr={3}>{icon}</RoundIconContainer>
<Box> <Box grow>
<Box ff="Museo Sans|Regular" color="dark"> <Box ff="Museo Sans|Regular" color="dark">
{title} {title}
</Box> </Box>
@ -55,11 +66,25 @@ export function SettingsSectionHeader({
{desc} {desc}
</Box> </Box>
</Box> </Box>
{renderRight && (
<Box alignItems="center" justifyContent="flex-end">
{renderRight}
</Box>
)}
</SettingsSectionHeaderContainer> </SettingsSectionHeaderContainer>
) )
} }
const SettingsSectionRowContainer = styled(Box).attrs({ p: 4, horizontal: true, align: 'center' })` SettingsSectionHeader.defaultProps = {
renderRight: undefined,
}
const SettingsSectionRowContainer = styled(Box).attrs({
p: 4,
horizontal: true,
align: 'center',
relative: true,
})`
cursor: ${p => (p.onClick ? 'pointer' : '')}; cursor: ${p => (p.onClick ? 'pointer' : '')};
` `

82
src/components/SettingsPage/index.js

@ -4,7 +4,9 @@ import React, { PureComponent } from 'react'
import { compose } from 'redux' import { compose } from 'redux'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import { Switch, Route } from 'react-router'
import type { RouterHistory, Match } from 'react-router'
import type { Settings, T } from 'types/common' import type { Settings, T } from 'types/common'
import type { SaveSettings } from 'actions/settings' import type { SaveSettings } from 'actions/settings'
import type { FetchCounterValues } from 'actions/counterValues' import type { FetchCounterValues } from 'actions/counterValues'
@ -30,27 +32,57 @@ const mapDispatchToProps = {
} }
type Props = { type Props = {
fetchCounterValues: FetchCounterValues,
history: RouterHistory,
i18n: Object, i18n: Object,
match: Match,
saveSettings: SaveSettings, saveSettings: SaveSettings,
settings: Settings, settings: Settings,
fetchCounterValues: FetchCounterValues,
t: T, t: T,
} }
type State = { type State = {
tab: number, tab: Object,
} }
class SettingsPage extends PureComponent<Props, State> { class SettingsPage extends PureComponent<Props, State> {
state = { constructor(props) {
tab: 0, super(props)
this._items = [
{
key: 'display',
label: props.t('settings:tabs.display'),
value: p => () => <SectionDisplay {...p} />,
},
{
key: 'currencies',
label: props.t('settings:tabs.currencies'),
value: p => () => <SectionCurrencies {...p} />,
},
{
key: 'profile',
label: props.t('settings:tabs.profile'),
value: p => () => <SectionProfile {...p} />,
},
{
key: 'about',
label: props.t('settings:tabs.about'),
value: p => () => <SectionAbout {...p} />,
},
]
this.state = {
tab: this._items[0],
}
} }
_items = [] _items = []
handleChangeTab = (item: any) => { handleChangeTab = (item: any) => {
const tab = this._items.indexOf(item) const { match, history } = this.props
this.setState({ tab }) history.push(`${match.url}/${item.key}`)
this.setState({ tab: item })
} }
handleSaveSettings = newSettings => { handleSaveSettings = newSettings => {
@ -64,47 +96,29 @@ class SettingsPage extends PureComponent<Props, State> {
} }
render() { render() {
const { settings, t, i18n, saveSettings } = this.props const { match, settings, t, i18n, saveSettings } = this.props
const { tab } = this.state const { tab } = this.state
const props = { const props = {
t, t,
settings, settings,
saveSettings, saveSettings,
i18n,
} }
this._items = [ const defaultItem = this._items[0]
{
key: 'display',
label: t('settings:tabs.display'),
value: () => <SectionDisplay {...props} i18n={i18n} />,
},
{
key: 'currencies',
label: t('settings:tabs.currencies'),
value: () => <SectionCurrencies {...props} />,
},
{
key: 'profile',
label: t('settings:tabs.profile'),
value: () => <SectionProfile {...props} />,
},
{
key: 'about',
label: t('settings:tabs.about'),
value: () => <SectionAbout {...props} />,
},
]
const item = this._items[tab]
return ( return (
<Box> <Box>
<Box ff="Museo Sans|Regular" color="dark" fontSize={7} mb={5}> <Box ff="Museo Sans|Regular" color="dark" fontSize={7} mb={5}>
{t('settings:title')} {t('settings:title')}
</Box> </Box>
<Pills mb={4} items={this._items} activeKey={item.key} onChange={this.handleChangeTab} /> <Pills mb={4} items={this._items} activeKey={tab.key} onChange={this.handleChangeTab} />
{item.value && item.value()} <Switch>
{this._items.map(i => (
<Route key={i.key} path={`${match.url}/${i.key}`} render={i.value && i.value(props)} />
))}
<Route render={defaultItem.value && defaultItem.value(props)} />
</Switch>
</Box> </Box>
) )
} }

21
src/components/SettingsPage/sections/Currencies.js

@ -2,8 +2,13 @@
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import { listCurrencies } from '@ledgerhq/currencies'
import type { Currency } from '@ledgerhq/currencies'
import type { T } from 'types/common' import type { T } from 'types/common'
import SelectCurrency from 'components/SelectCurrency'
import IconCurrencies from 'icons/Currencies' import IconCurrencies from 'icons/Currencies'
import { import {
@ -17,15 +22,29 @@ type Props = {
t: T, t: T,
} }
class TabCurrencies extends PureComponent<Props> { type State = {
currency: Currency,
}
class TabCurrencies extends PureComponent<Props, State> {
state = {
currency: listCurrencies()[0],
}
handleChangeCurrency = currency => this.setState({ currency })
render() { render() {
const { t } = this.props const { t } = this.props
const { currency } = this.state
return ( return (
<Section> <Section>
<Header <Header
icon={<IconCurrencies size={16} />} icon={<IconCurrencies size={16} />}
title={t('settings:tabs.currencies')} title={t('settings:tabs.currencies')}
desc="Lorem ipsum dolor sit amet" desc="Lorem ipsum dolor sit amet"
renderRight={
<SelectCurrency small value={currency} onChange={this.handleChangeCurrency} />
}
/> />
<Body> <Body>
<Row <Row

10
src/components/SideBar/Item.js

@ -3,7 +3,7 @@
import React from 'react' import React from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { compose } from 'redux' import { compose } from 'redux'
import { withRouter } from 'react-router' import { matchPath, withRouter } from 'react-router'
import { push } from 'react-router-redux' import { push } from 'react-router-redux'
import { connect } from 'react-redux' import { connect } from 'react-redux'
@ -77,7 +77,13 @@ function Item({
openModal, openModal,
}: Props) { }: Props) {
const { pathname } = location const { pathname } = location
const isActive = pathname === linkTo const isActive = linkTo
? linkTo === '/'
? linkTo === pathname
: matchPath(pathname, {
path: linkTo,
})
: false
return ( return (
<Container <Container
big={big} big={big}

10
src/components/TopBar.js

@ -5,8 +5,10 @@ import { compose } from 'redux'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import styled from 'styled-components' import styled from 'styled-components'
import { withRouter } from 'react-router'
import { ipcRenderer } from 'electron' import { ipcRenderer } from 'electron'
import type { RouterHistory } from 'react-router'
import type { T } from 'types/common' import type { T } from 'types/common'
import { rgba } from 'styles/helpers' import { rgba } from 'styles/helpers'
@ -85,6 +87,7 @@ const mapDispatchToProps = {
} }
type Props = { type Props = {
history: RouterHistory,
t: T, t: T,
hasAccounts: boolean, hasAccounts: boolean,
hasPassword: boolean, hasPassword: boolean,
@ -147,7 +150,7 @@ class TopBar extends PureComponent<Props, State> {
handleLock = () => this.props.lock() handleLock = () => this.props.lock()
render() { render() {
const { hasPassword, hasAccounts, username, t } = this.props const { hasPassword, history, hasAccounts, username, t } = this.props
const { sync } = this.state const { sync } = this.state
return ( return (
@ -173,6 +176,7 @@ class TopBar extends PureComponent<Props, State> {
key: 'profile', key: 'profile',
label: t('common:editProfile'), label: t('common:editProfile'),
icon: <IconUser size={16} />, icon: <IconUser size={16} />,
onClick: () => history.push('/settings/profile'),
}, },
...(hasPassword ...(hasPassword
? [ ? [
@ -209,4 +213,6 @@ class TopBar extends PureComponent<Props, State> {
} }
} }
export default compose(connect(mapStateToProps, mapDispatchToProps), translate())(TopBar) export default compose(withRouter, connect(mapStateToProps, mapDispatchToProps), translate())(
TopBar,
)

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

@ -12,26 +12,26 @@ import fontFamily from 'styles/styled/fontFamily'
const buttonStyles = { const buttonStyles = {
primary: { primary: {
default: p => ` default: p => `
background: ${p.disabled ? lighten(p.theme.colors.wallet, 0.1) : p.theme.colors.wallet}; background: ${p.disabled ? p.theme.colors.lightFog : p.theme.colors.wallet};
color: white; color: ${p.disabled ? p.theme.colors.grey : p.theme.colors.white};
`, `,
hover: p => ` hover: p => `
background: ${lighten(p.theme.colors.wallet, 0.05)}; background: ${darken(p.theme.colors.wallet, 0.05)};
`, `,
active: p => ` active: p => `
background: ${darken(p.theme.colors.wallet, 0.1)}; background: ${darken(p.theme.colors.wallet, 0.05)};
`, `,
}, },
danger: { danger: {
default: p => ` default: p => `
background: ${p.disabled ? lighten(p.theme.colors.alertRed, 0.3) : p.theme.colors.alertRed}; background: ${p.disabled ? p.theme.colors.lightFog : p.theme.colors.alertRed};
color: white; color: ${p.disabled ? p.theme.colors.grey : p.theme.colors.white};
`, `,
hover: p => ` hover: p => `
background: ${lighten(p.theme.colors.alertRed, 0.1)}; background: ${lighten(p.theme.colors.alertRed, 0.2)};
`, `,
active: p => ` active: p => `
background: ${darken(p.theme.colors.alertRed, 0.1)}; background: ${lighten(p.theme.colors.alertRed, 0.2)};
`, `,
}, },
outline: { outline: {
@ -87,7 +87,8 @@ const Base = styled.button.attrs({
outline: none; outline: none;
${p => getStyles(p, 'default')}; ${p => getStyles(p, 'default')};
&:hover { &:hover,
&:focus {
${p => getStyles(p, 'hover')}; ${p => getStyles(p, 'hover')};
} }
&:active { &:active {

1
src/components/base/CheckBox/index.js

@ -18,7 +18,6 @@ const Base = styled(Tabbable).attrs({
transition: 250ms linear background-color; transition: 250ms linear background-color;
cursor: pointer; cursor: pointer;
&:focus { &:focus {
box-shadow: rgba(0, 0, 0, 0.1) 0 2px 2px;
outline: none; outline: none;
} }
` `

1
src/components/layout/Default.js

@ -6,6 +6,7 @@ import { ipcRenderer } from 'electron'
import styled from 'styled-components' import styled from 'styled-components'
import { Route, withRouter } from 'react-router' import { Route, withRouter } from 'react-router'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import type { Location } from 'react-router' import type { Location } from 'react-router'
import * as modals from 'components/modals' import * as modals from 'components/modals'

1
static/i18n/en/common.yml

@ -4,6 +4,7 @@ cancel: Cancel
chooseWalletPlaceholder: Choose a wallet... chooseWalletPlaceholder: Choose a wallet...
currency: Currency currency: Currency
selectAccount: Select an account selectAccount: Select an account
selectCurrency: Select an currency
sortBy: Sort by sortBy: Sort by
search: Search search: Search
save: Save save: Save

Loading…
Cancel
Save