Skip to content
Permalink
Browse files

feat(wallet): system settings screen

fix #1535
  • Loading branch information...
mrfelton committed May 14, 2019
1 parent 2541703 commit 35aeb04139b83f6a151705a4ce539ba26b7fa3fe
@@ -107,6 +107,10 @@ module.exports = {
defaultValue: '150000',
},

channels: {
viewMode: 'CHANNEL_LIST_VIEW_MODE_CARD',
},

// feature flags to enable/disable experimental functionality
features: {
autopay: false,
@@ -225,8 +225,9 @@ app.on('ready', async () => {
if (!process.env.DISABLE_INIT) {
try {
const settings = await fetchSettings()
locale = getSetting(settings, 'locale')
const themeKey = getSetting(settings, 'theme')
const currentConfig = getSetting(settings, 'config')
locale = currentConfig.locale || config.locale
const themeKey = currentConfig.theme || config.theme
theme = themes[themeKey]
} catch (e) {
mainLog.warn('Unable to determine user locale and theme', e)
@@ -0,0 +1,234 @@
import React from 'react'
import PropTypes from 'prop-types'
import { FormattedMessage, injectIntl, intlShape } from 'react-intl'
import { Box, Flex } from 'rebass'
import {
Bar,
Button,
DataRow,
Form,
Header,
Input,
Label,
Toggle,
Select,
Text,
} from 'components/UI'
import { currencies, locales, getLanguageName } from '@zap/i18n'
import messages from './messages'

const localeItems = locales.map(lang => ({
key: lang,
value: getLanguageName(lang),
}))

const currencyItems = currencies.map(currency => ({
key: currency,
value: currency,
}))

const themeItems = [{ key: 'dark' }, { key: 'light' }]
const themeMessageMapper = key => {
const filters = {
dark: messages.theme_option_dark,
light: messages.theme_option_light,
}
return filters[key]
}

const addressItems = [{ key: 'p2wkh' }, { key: 'np2wkh' }]
const addressMessageMapper = key => {
const filters = {
p2wkh: messages.address_option_p2wkh,
np2wkh: messages.address_option_np2wkh,
}
return filters[key]
}

const FieldLabel = ({ itemKey, ...rest }) => {
const messageKey = itemKey.replace('.', '_')
return (
<Box {...rest}>
<Label htmlFor={itemKey} mb={2}>
<FormattedMessage {...messages[`${messageKey}_label`]} />
</Label>
<Text color="gray" fontWeight="light">
<FormattedMessage {...messages[`${messageKey}_description`]} />
</Text>
</Box>
)
}

FieldLabel.propTypes = {
itemKey: PropTypes.string.isRequired,
}

const NumberField = props => (
<Input
css={{ 'text-align': 'right' }}
highlightOnValid={false}
isRequired
min="1"
step="1"
type="number"
width={80}
{...props}
/>
)

const FormButtons = props => (
<Flex {...props} alignItems="center" justifyContent="space-between">
<Button mx="auto" type="submit">
<FormattedMessage {...messages.save} />
</Button>
</Flex>
)

const Settings = ({
intl,
currentConfig,
onSubmit,
setLocale,
saveConfigOverrides,
showNotification,
}) => {
const handleSubmit = async values => {
// Save the updated settings.
await saveConfigOverrides(values)

// Special handling.
if (values.locale) {
await setLocale(values.locale)
}

// Show a notification.
const message = intl.formatMessage({ ...messages.submit_success })
showNotification(message)

// Finally, run any user supplied submit handler.
if (onSubmit) {
onSubmit(values)
}
}

return (
<Form mx="auto" onSubmit={handleSubmit} width={9 / 16}>
<Header
subtitle={<FormattedMessage {...messages.settings_subtitle} />}
title={<FormattedMessage {...messages.settings_title} />}
/>
<Bar my={1} />

<DataRow
left={<FieldLabel itemKey="locale" />}
right={
<Select
field="locale"
highlightOnValid={false}
initialSelectedItem={currentConfig.locale}
items={localeItems}
/>
}
/>

<Bar variant="light" />

<DataRow
left={<FieldLabel itemKey="currency" />}
right={
<Select
field="currency"
highlightOnValid={false}
initialSelectedItem={currentConfig.currency}
items={currencyItems}
/>
}
/>

<Bar variant="light" />

<DataRow
left={<FieldLabel itemKey="theme" />}
right={
<Select
field="theme"
highlightOnValid={false}
initialSelectedItem={currentConfig.theme}
items={themeItems}
messageMapper={themeMessageMapper}
/>
}
/>

<Bar variant="light" />

<DataRow
left={<FieldLabel itemKey="address" />}
right={
<Select
field="address"
highlightOnValid={false}
initialSelectedItem={currentConfig.address}
items={addressItems}
messageMapper={addressMessageMapper}
/>
}
/>

<Bar variant="light" />

<DataRow
left={<FieldLabel itemKey="lndTargetConfirmations.fastestConfCount" />}
right={
<NumberField
field="lndTargetConfirmations.fastestConfCount"
initialValue={currentConfig.lndTargetConfirmations.fastestConfCount}
/>
}
/>

<Bar variant="light" />

<DataRow
left={<FieldLabel itemKey="lndTargetConfirmations.halfHourConfCount" />}
right={
<NumberField
field="lndTargetConfirmations.halfHourConfCount"
initialValue={currentConfig.lndTargetConfirmations.halfHourConfCount}
/>
}
/>

<Bar variant="light" />

<DataRow
left={<FieldLabel itemKey="lndTargetConfirmations.hourConfCount" />}
right={
<NumberField
field="lndTargetConfirmations.hourConfCount"
initialValue={currentConfig.lndTargetConfirmations.hourConfCount}
/>
}
/>

<Bar variant="light" />

<DataRow
left={<FieldLabel itemKey="autoupdate.active" />}
right={<Toggle field="autoupdate.active" initialValue={currentConfig.autoupdate.active} />}
/>

<FormButtons />
</Form>
)
}

Settings.propTypes = {
currentConfig: PropTypes.object.isRequired,
intl: intlShape.isRequired,
onSubmit: PropTypes.func,
saveConfigOverrides: PropTypes.func.isRequired,
setLocale: PropTypes.func.isRequired,
showNotification: PropTypes.func.isRequired,
}
export default injectIntl(Settings)
@@ -5,7 +5,7 @@ import { FormattedMessage } from 'react-intl'
import { MenuContainer, Menu, MenuItem } from 'components/UI/Dropdown'
import messages from './messages'

const SettingsMenu = ({ history, setActiveSubMenu }) => (
const SettingsMenu = ({ history, setActiveSubMenu, openModal }) => (
<MenuContainer>
<Menu justify="right">
<MenuItem
@@ -26,6 +26,11 @@ const SettingsMenu = ({ history, setActiveSubMenu }) => (
onClick={() => setActiveSubMenu('theme')}
/>

<MenuItem
item={{ key: 'settings', name: <FormattedMessage {...messages.settings} /> }}
onClick={() => openModal('SETTINGS_FORM')}
/>

<MenuItem
item={{ key: 'logout', name: <FormattedMessage {...messages.logout} /> }}
onClick={() => history.push('/logout')}
@@ -36,6 +41,7 @@ const SettingsMenu = ({ history, setActiveSubMenu }) => (

SettingsMenu.propTypes = {
history: PropTypes.object.isRequired,
openModal: PropTypes.func.isRequired,
setActiveSubMenu: PropTypes.func.isRequired,
}

@@ -6,4 +6,5 @@ export default defineMessages({
locale: 'Language',
theme: 'Theme',
logout: 'Logout',
settings: 'Settings',
})
@@ -59,7 +59,14 @@ class SettingsMenu extends React.Component {
}

renderSettingsMenu = () => {
const { activeSubMenu, fiatProps, localeProps, themeProps, setActiveSubMenu } = this.props
const {
activeSubMenu,
fiatProps,
localeProps,
themeProps,
setActiveSubMenu,
openModal,
} = this.props
switch (activeSubMenu) {
case 'fiat':
return <Fiat {...fiatProps} />
@@ -68,7 +75,7 @@ class SettingsMenu extends React.Component {
case 'theme':
return <Theme {...themeProps} />
default:
return <Menu setActiveSubMenu={setActiveSubMenu} />
return <Menu openModal={openModal} setActiveSubMenu={setActiveSubMenu} />
}
}

@@ -104,6 +111,7 @@ SettingsMenu.propTypes = {
fiatProps: PropTypes.object.isRequired,
isSettingsMenuOpen: PropTypes.bool,
localeProps: PropTypes.object.isRequired,
openModal: PropTypes.func.isRequired,
openSettingsMenu: PropTypes.func.isRequired,
setActiveSubMenu: PropTypes.func.isRequired,
themeProps: PropTypes.object.isRequired,
@@ -1 +1,4 @@
import Settings from './Settings'

export default Settings
export SettingsMenu from './SettingsMenu'
@@ -2,12 +2,13 @@ import { defineMessages } from 'react-intl'

/* eslint-disable max-len */
export default defineMessages({
enable: 'Enable',
disable: 'Disable',
settings_title: 'Settings',
settings_subtitle: 'Global settings',
save: 'Save',
cancel: 'Cancel',
submit_success: 'Settings have been updated.',
autoupdate_active_label: 'Autoupdate',
autoupdate_active_description: 'Enable to disable autoupdates.',
autoupdate_active_description: 'Automatically download and install updates.',
locale_label: 'Language',
locale_description: 'Language the app will display in.',
locale_option_en: 'English',
@@ -26,13 +27,13 @@ export default defineMessages({
address_description: 'Your preferred address format.',
address_option_p2wkh: 'Bech 32',
address_option_np2wkh: 'Wrapped Bech 32',
lndTargetConfirmations_hourConfCount_label: 'Target confs (slow)',
lndTargetConfirmations_hourConfCount_label: 'Target confs (slow).',
lndTargetConfirmations_hourConfCount_description:
'Number of blocks to target for "slow" transactions',
lndTargetConfirmations_halfHourConfCount_label: 'Target confs (medium)',
lndTargetConfirmations_halfHourConfCount_label: 'Target confs (medium).',
lndTargetConfirmations_halfHourConfCount_description:
'Number of blocks to target for "medium" transactions',
lndTargetConfirmations_fastestConfCount_label: 'Target confs (fast)',
lndTargetConfirmations_fastestConfCount_label: 'Target confs (fast).',
lndTargetConfirmations_fastestConfCount_description:
'Number of blocks to target for "fast" transactions',
})
@@ -14,13 +14,18 @@ import ChannelDetailModal from 'containers/Channels/ChannelDetailModal'
import ChannelCreate from 'containers/Channels/ChannelCreate'
import ReceiveModal from 'containers/Wallet/ReceiveModal'
import ActivityModal from 'containers/Activity/ActivityModal'
import Settings from 'containers/Settings'

const Container = styled(animated.div)`
${ModalOverlayStyles}
`

const ModalContent = ({ type, closeModal }) => {
const doCloseModal = () => closeModal()
switch (type) {
case 'SETTINGS_FORM':
return <Settings onSubmit={doCloseModal} />

case 'AUTOPAY':
return <Autopay mx={-4} />

@@ -40,7 +45,7 @@ const ModalContent = ({ type, closeModal }) => {
return <Channels mx={-4} />

case 'CHANNEL_CREATE':
return <ChannelCreate mx={-4} onSubmit={() => closeModal()} />
return <ChannelCreate mx={-4} onSubmit={doCloseModal} />

case 'CHANNEL_DETAIL':
return <ChannelDetailModal type="CHANNEL_DETAIL" />

0 comments on commit 35aeb04

Please sign in to comment.
You can’t perform that action at this time.