Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

Commit

Permalink
feat(ui): allow changing and toggling app password via dialogs
Browse files Browse the repository at this point in the history
  • Loading branch information
korhaliv committed Oct 11, 2019
1 parent 32ff953 commit 892d592
Show file tree
Hide file tree
Showing 10 changed files with 281 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const DialogWrapper = ({ loginError, clearLoginError, isOpen, onChange, onCancel
const formApiRef = useRef(null)
useEffect(() => {
const { current: formApi } = formApiRef
if (loginError) {
if (loginError && formApi) {
formApi.setFormError(loginError)
clearLoginError()
}
Expand Down
57 changes: 40 additions & 17 deletions renderer/components/Settings/Security/PasswordPromptDialog.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import React from 'react'
import React, { useEffect, useRef } from 'react'
import PropTypes from 'prop-types'
import { Flex } from 'rebass/styled-components'
import { FormattedMessage, useIntl } from 'react-intl'
import { Dialog, Heading, Button, DialogOverlay } from 'components/UI'
import { Dialog, Heading, Button, DialogOverlay, Message } from 'components/UI'
import { PasswordInput, Form } from 'components/Form'
import messages from './messages'

const DialogWrapper = ({ isOpen, onOk, onCancel, isPromptMode }) => {
const DialogWrapper = ({ loginError, clearLoginError, isOpen, onOk, onCancel, isPromptMode }) => {
const intl = useIntl()
const formApiRef = useRef(null)
useEffect(() => {
const { current: formApi } = formApiRef
if (loginError && formApi) {
formApi.setFormError(loginError)
clearLoginError()
}
}, [loginError, clearLoginError])

if (!isOpen) {
return null
}
Expand Down Expand Up @@ -43,20 +52,32 @@ const DialogWrapper = ({ isOpen, onOk, onCancel, isPromptMode }) => {

return (
<DialogOverlay alignItems="center" justifyContent="center" position="fixed">
<Form onSubmit={handleSubmit}>
<Dialog buttons={buttons} header={header} onClose={onCancel} width={640}>
<Flex alignItems="center" flexDirection="column" width={350}>
<PasswordInput
description={intl.formatMessage(inputDesc)}
field="password"
hasMessageSpacer
isRequired
minLength={6}
width={1}
willAutoFocus
/>
</Flex>
</Dialog>
<Form getApi={api => (formApiRef.current = api)} onSubmit={handleSubmit}>
{({ formState: { submits, error } }) => {
const willValidateInline = submits > 0
return (
<Dialog buttons={buttons} header={header} onClose={onCancel} width={640}>
{error && (
<Message mb={3} variant="error">
{error}
</Message>
)}
<Flex alignItems="center" flexDirection="column" width={350}>
<PasswordInput
description={intl.formatMessage(inputDesc)}
field="password"
hasMessageSpacer
isRequired
minLength={6}
validateOnBlur={willValidateInline}
validateOnChange={willValidateInline}
width={1}
willAutoFocus
/>
</Flex>
</Dialog>
)
}}
</Form>
</DialogOverlay>
)
Expand All @@ -67,9 +88,11 @@ DialogWrapper.defaultProps = {
}

DialogWrapper.propTypes = {
clearLoginError: PropTypes.func.isRequired,
isOpen: PropTypes.bool.isRequired,
isPromptMode: PropTypes.bool,
isRestoreMode: PropTypes.bool,
loginError: PropTypes.string,
onCancel: PropTypes.func.isRequired,
onOk: PropTypes.func.isRequired,
}
Expand Down
52 changes: 21 additions & 31 deletions renderer/components/Settings/SettingsFieldsSecurity.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,38 @@
import React from 'react'
import PropTypes from 'prop-types'
import { useFieldState, useFormState } from 'informed'
import { useIntl } from 'react-intl'
import { DataRow } from 'components/UI'
import { PasswordInput, FieldLabelFactory, Toggle } from 'components/Form'
import { FieldLabelFactory } from 'components/Form'
import messages from './messages'
import PasswordState from './Security/PasswordState'

const FieldLabel = FieldLabelFactory(messages)

const SettingsFieldsSecurity = ({ currentConfig }) => {
const { value: isPasswordActive } = useFieldState('password.active')
const { submits } = useFormState()
const willValidateInline = submits > 0
const intl = useIntl()

const SettingsFieldsSecurity = ({
currentConfig,
changePassword,
enablePassword,
disablePassword,
}) => {
return (
<>
<DataRow
left={<FieldLabel itemKey="password.active" tooltip="password_tooltip" />}
right={<Toggle field="password.active" initialValue={currentConfig.password.active} />}
/>
{isPasswordActive && (
<DataRow
pt={0}
right={
<PasswordInput
description={intl.formatMessage({ ...messages.password_value_description })}
field="password.value"
initialValue={currentConfig.password.value}
isRequired
minLength={6}
validateOnBlur={willValidateInline}
validateOnChange={willValidateInline}
width={200}
/>
}
<DataRow
left={<FieldLabel itemKey="password.active" tooltip="password_tooltip" />}
right={
<PasswordState
onChange={changePassword}
onDisable={disablePassword}
onEnable={enablePassword}
value={currentConfig.password.active}
/>
)}
</>
}
/>
)
}

SettingsFieldsSecurity.propTypes = {
changePassword: PropTypes.func.isRequired,
currentConfig: PropTypes.object.isRequired,
disablePassword: PropTypes.func.isRequired,
enablePassword: PropTypes.func.isRequired,
}

export default SettingsFieldsSecurity
6 changes: 0 additions & 6 deletions renderer/components/Settings/SettingsForm.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react'
import PropTypes from 'prop-types'
import get from 'lodash/get'
import { injectIntl } from 'react-intl'
import { intlShape } from '@zap/i18n'
import { Form } from 'components/Form'
Expand All @@ -19,11 +18,6 @@ const SettingsForm = ({
}) => {
const handleSubmit = async values => {
try {
// If password feature has been disabled, reset the password to null.
if (!get(values, 'password.value')) {
values.password.value = null
}

// Save the updated settings.
await saveConfigOverrides(values)

Expand Down
54 changes: 31 additions & 23 deletions renderer/components/Settings/SettingsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import ZapLogo from 'components/Icon/ZapLogo'
import SettingsForm from 'containers/Settings/SettingsForm'
import SettingsFieldsWallet from './SettingsFieldsWallet'
import SettingsFieldsGeneral from './SettingsFieldsGeneral'
import SettingsFieldsSecurity from './SettingsFieldsSecurity'
import SettingsFieldsSecurity from 'containers/Settings/SettingsFieldsSecurity'
import ChangePasswordDialog from 'containers/Settings/ChangePasswordDialog'
import PasswordPromptDialog from 'containers/Settings/PasswordPromptDialog'
import PasswordSetDialog from 'containers/Settings/PasswordSetDialog'
import messages from './messages'

const SettingsMenu = ({ group, setGroup, isLoggedIn, ...rest }) => {
Expand Down Expand Up @@ -117,28 +120,33 @@ const SettingsPage = ({ currentConfig, isLoggedIn, ...rest }) => {
}

return (
<Flex width={1} {...rest}>
<Sidebar.medium pt={40}>
<Panel>
<Panel.Header mb={40} px={4}>
<ZapLogo height={28} width={28} />
</Panel.Header>
<Panel.Body sx={{ overflowY: 'overlay' }}>
<SettingsMenu group={group} isLoggedIn={isLoggedIn} setGroup={setGroup} />
</Panel.Body>
</Panel>
</Sidebar.medium>
<MainContent pb={2} pl={5} pr={6} pt={4}>
<Heading.h1 fontSize={60}>
<FormattedMessage {...messages.settings_title} />
</Heading.h1>

<SettingsForm>
<FieldGroup currentConfig={currentConfig} />
<SettingsActions currentConfig={currentConfig} />
</SettingsForm>
</MainContent>
</Flex>
<>
<Flex width={1} {...rest}>
<Sidebar.medium pt={40}>
<Panel>
<Panel.Header mb={40} px={4}>
<ZapLogo height={28} width={28} />
</Panel.Header>
<Panel.Body sx={{ overflowY: 'overlay' }}>
<SettingsMenu group={group} isLoggedIn={isLoggedIn} setGroup={setGroup} />
</Panel.Body>
</Panel>
</Sidebar.medium>
<MainContent pb={2} pl={5} pr={6} pt={4}>
<Heading.h1 fontSize={60}>
<FormattedMessage {...messages.settings_title} />
</Heading.h1>

<SettingsForm>
<FieldGroup currentConfig={currentConfig} />
<SettingsActions currentConfig={currentConfig} />
</SettingsForm>
</MainContent>
</Flex>
<ChangePasswordDialog />
<PasswordPromptDialog />
<PasswordSetDialog />
</>
)
}

Expand Down
27 changes: 27 additions & 0 deletions renderer/containers/Settings/ChangePasswordDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { connect } from 'react-redux'
import ChangePasswordDialog from 'components/Settings/Security/ChangePasswordDialog'
import {
changePassword as onChange,
accountSelectors,
clearLoginError,
CHANGE_PASSWORD_DIALOG_ID,
} from 'reducers/account'
import { modalSelectors, closeDialog } from 'reducers/modal'

const onCancel = () => closeDialog(CHANGE_PASSWORD_DIALOG_ID)

const mapStateToProps = state => ({
isOpen: modalSelectors.isDialogOpen(state, CHANGE_PASSWORD_DIALOG_ID),
loginError: accountSelectors.loginError(state),
})

const mapDispatchToProps = {
onChange,
onCancel,
clearLoginError,
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(ChangePasswordDialog)
27 changes: 27 additions & 0 deletions renderer/containers/Settings/PasswordPromptDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { connect } from 'react-redux'
import PasswordPromptDialog from 'components/Settings/Security/PasswordPromptDialog'
import {
accountSelectors,
clearLoginError,
disablePassword as onOk,
PASSWORD_PROMPT_DIALOG_ID,
} from 'reducers/account'
import { modalSelectors, closeDialog } from 'reducers/modal'

const onCancel = () => closeDialog(PASSWORD_PROMPT_DIALOG_ID)

const mapStateToProps = state => ({
isOpen: modalSelectors.isDialogOpen(state, PASSWORD_PROMPT_DIALOG_ID),
loginError: accountSelectors.loginError(state),
})

const mapDispatchToProps = {
onOk,
onCancel,
clearLoginError,
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(PasswordPromptDialog)
21 changes: 21 additions & 0 deletions renderer/containers/Settings/PasswordSetDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { connect } from 'react-redux'
import PasswordPromptDialog from 'components/Settings/Security/PasswordPromptDialog'
import { enablePassword as onOk, PASSWORD_SET_DIALOG_ID } from 'reducers/account'
import { modalSelectors, closeDialog } from 'reducers/modal'

const onCancel = () => closeDialog(PASSWORD_SET_DIALOG_ID)

const mapStateToProps = state => ({
isOpen: modalSelectors.isDialogOpen(state, PASSWORD_SET_DIALOG_ID),
isPromptMode: false,
})

const mapDispatchToProps = {
onOk,
onCancel,
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(PasswordPromptDialog)
23 changes: 23 additions & 0 deletions renderer/containers/Settings/SettingsFieldsSecurity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { connect } from 'react-redux'
import SettingsFieldsSecurity from 'components/Settings/SettingsFieldsSecurity'
import { openDialog } from 'reducers/modal'
import {
CHANGE_PASSWORD_DIALOG_ID,
PASSWORD_PROMPT_DIALOG_ID,
PASSWORD_SET_DIALOG_ID,
} from 'reducers/account'

const changePassword = () => openDialog(CHANGE_PASSWORD_DIALOG_ID)
const disablePassword = () => openDialog(PASSWORD_PROMPT_DIALOG_ID)
const enablePassword = () => openDialog(PASSWORD_SET_DIALOG_ID)

const mapDispatchToProps = {
changePassword,
enablePassword,
disablePassword,
}

export default connect(
null,
mapDispatchToProps
)(SettingsFieldsSecurity)
Loading

0 comments on commit 892d592

Please sign in to comment.