Skip to content

Commit

Permalink
Merge branch 'develop' into dangerous-action-modal-withdrawal-dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
stackchain committed Jul 27, 2021
2 parents 07f181f + a8b17cb commit 99c06c8
Show file tree
Hide file tree
Showing 19 changed files with 484 additions and 533 deletions.
53 changes: 53 additions & 0 deletions src/components/Common/FingerprinScreenBase.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// @flow

import React from 'react'
import {storiesOf} from '@storybook/react-native'
import {action} from '@storybook/addon-actions'

import {Button} from '../UiKit'

import FingerprintScreenBase from './FingerprintScreenBase'

storiesOf('FingerprintScreenBase', module)
.add('Default', () => <FingerprintScreenBase headings={['heading1', 'heading2']} buttons={[]} />)
.add('with onGoBack', () => (
<FingerprintScreenBase headings={['heading1', 'heading2']} buttons={[]} onGoBack={action('goBack')} />
))
.add('with buttons', () => (
<FingerprintScreenBase
headings={['heading1', 'heading2']}
subHeadings={['subheading1', 'subheading2']}
buttons={[
<Button key={'button1'} title={'button1'} onPress={action('button1')} />,
<Button key={'button2'} title={'button2'} onPress={action('button2')} />,
]}
onGoBack={action('goBack')}
addWelcomeMessage
error={'this is the error messaqge'}
/>
))
.add('with error', () => (
<FingerprintScreenBase
headings={['heading1', 'heading2']}
subHeadings={['subheading1', 'subheading2']}
buttons={[
<Button key={'button1'} title={'button1'} onPress={action('button1')} />,
<Button key={'button2'} title={'button2'} onPress={action('button2')} />,
]}
onGoBack={action('goBack')}
error={'this is the error messaqge'}
/>
))
.add('with welcome message', () => (
<FingerprintScreenBase
headings={['heading1', 'heading2']}
subHeadings={['subheading1', 'subheading2']}
buttons={[
<Button key={'button1'} title={'button1'} onPress={action('button1')} />,
<Button key={'button2'} title={'button2'} onPress={action('button2')} />,
]}
onGoBack={action('goBack')}
addWelcomeMessage
error={'this is the error messaqge'}
/>
))
144 changes: 56 additions & 88 deletions src/components/Common/FingerprintScreenBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,14 @@
import React from 'react'
import {View, Image, TouchableOpacity, Platform} from 'react-native'
import {defineMessages, type IntlShape} from 'react-intl'
import {compose} from 'redux'
import {withStateHandlers} from 'recompose'
import DeviceInfo from 'react-native-device-info'

import {Text, StatusBar, ScreenBackground} from '../UiKit'
import fingerprintImage from '../../assets/img/fingerprint.png'
import chevronLeft from '../../assets/img/chevron_left.png'
import {onDidMount} from '../../utils/renderUtils'

import styles from './styles/FingerprintScreenBase.style'

import type {ComponentType} from 'react'

const messages = defineMessages({
welcomeMessage: {
id: 'components.common.fingerprintscreenbase.welcomeMessage',
Expand All @@ -31,93 +26,66 @@ type Props = {
error?: null | false | string,
addWelcomeMessage?: boolean,
intl?: IntlShape,
showImage: boolean,
}

const FingerprintScreenBase = ({
headings,
subHeadings,
buttons,
onGoBack,
error,
addWelcomeMessage,
intl,
showImage,
}: Props) => (
<ScreenBackground style={styles.container}>
<StatusBar type="dark" />

<View style={[styles.main, onGoBack ? null : styles.mainPadded]}>
{onGoBack && (
<TouchableOpacity onPress={onGoBack} style={styles.goBack}>
<Image source={chevronLeft} style={styles.chevron} />
</TouchableOpacity>
)}

{headings.map((txt) => (
<Text key={txt} style={styles.heading}>
{txt}
</Text>
))}

{subHeadings && subHeadings.length > 0 ? (
<View style={styles.subHeadingContainer}>
{subHeadings.map((txt) => (
<Text key={txt} style={styles.subHeading}>
{txt}
</Text>
))}
</View>
) : null}

{
/* eslint-disable indent */
addWelcomeMessage === true && intl != null && (
<View style={styles.welcomeMessageContainer}>
<Text style={styles.welcomeMessageText}>{intl.formatMessage(messages.welcomeMessage)}</Text>
const FingerprintScreenBase = ({headings, subHeadings, buttons, onGoBack, error, addWelcomeMessage, intl}: Props) => {
const [showImage, setShowImage] = React.useState(false)

React.useEffect(() => {
DeviceInfo.getApiLevel().then((sdk) => {
setShowImage(Platform.OS === 'android' && sdk < 28)
})
}, [])

return (
<ScreenBackground style={styles.container}>
<StatusBar type="dark" />

<View style={[styles.main, onGoBack ? null : styles.mainPadded]}>
{onGoBack && (
<TouchableOpacity onPress={onGoBack} style={styles.goBack}>
<Image source={chevronLeft} style={styles.chevron} />
</TouchableOpacity>
)}

{headings.map((txt) => (
<Text key={txt} style={styles.heading}>
{txt}
</Text>
))}

{subHeadings && subHeadings.length > 0 ? (
<View style={styles.subHeadingContainer}>
{subHeadings.map((txt) => (
<Text key={txt} style={styles.subHeading}>
{txt}
</Text>
))}
</View>
)
/* eslint-enable indent */
}

{showImage === true && (
<View style={styles.imageContainer}>
<Image source={fingerprintImage} style={styles.image} />
</View>
)}
</View>

{error != null && error !== false ? <Text style={styles.error}>{error}</Text> : null}
) : null}

{
/* eslint-disable indent */
addWelcomeMessage === true && intl != null && (
<View style={styles.welcomeMessageContainer}>
<Text style={styles.welcomeMessageText}>{intl.formatMessage(messages.welcomeMessage)}</Text>
</View>
)
/* eslint-enable indent */
}

{showImage === true && (
<View style={styles.imageContainer}>
<Image source={fingerprintImage} style={styles.image} />
</View>
)}
</View>

<View style={styles.controls}>{buttons}</View>
</ScreenBackground>
)
{error != null && error !== false ? <Text style={styles.error}>{error}</Text> : null}

type ExternalProps = {
headings: Array<string>,
subHeadings?: Array<string>,
buttons: Array<any>,
onGoBack?: () => any,
error?: null | false | string,
addWelcomeMessage?: boolean,
intl?: IntlShape,
<View style={styles.controls}>{buttons}</View>
</ScreenBackground>
)
}

export default (compose(
withStateHandlers(
{
showImage: false,
},
{
shouldShowImage:
() =>
(sdk: number): {showImage: boolean} => {
// note(v-almonacid): the decrypt with biometrics prompt only appears
// for API level >= 28
const showImage = Platform.OS === 'android' && sdk < 28
return {showImage}
},
},
),
onDidMount(({shouldShowImage}) => DeviceInfo.getApiLevel().then((sdk) => shouldShowImage(sdk))),
)(FingerprintScreenBase): ComponentType<ExternalProps>)
export default FingerprintScreenBase
131 changes: 52 additions & 79 deletions src/components/Settings/ChangeWalletName.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
// @flow

import React from 'react'
import {compose} from 'redux'
import {connect} from 'react-redux'
import {withStateHandlers, withHandlers} from 'recompose'
import {View, ScrollView, KeyboardAvoidingView, Platform} from 'react-native'
import {useSelector, useDispatch} from 'react-redux'
import {View, ScrollView} from 'react-native'
import {SafeAreaView} from 'react-native-safe-area-context'
import {injectIntl, defineMessages, type IntlShape} from 'react-intl'
import _ from 'lodash'

import {Button, ValidatedTextInput, StatusBar} from '../UiKit'
import {Button, TextInput} from '../UiKit'
import {walletNameSelector, walletNamesSelector} from '../../selectors'
import {changeWalletName} from '../../actions'
import {getWalletNameError, validateWalletName} from '../../utils/validators'
import globalMessages from '../../i18n/global-messages'

import styles from './styles/ChangeWalletName.style'

import type {WalletNameValidationErrors} from '../../utils/validators'
import type {ComponentType} from 'react'
import type {Navigation} from '../../types/navigation'

const WalletNameInput = TextInput

const messages = defineMessages({
changeButton: {
id: 'components.settings.changewalletname.changeButton',
Expand All @@ -33,83 +30,59 @@ const messages = defineMessages({
})

type Props = {
walletName: string,
setWalletName: (string) => any,
changeAndNavigate: () => any,
intl: IntlShape,
validateWalletName: () => WalletNameValidationErrors,
navigation: Navigation,
}

const ChangeWalletName = ({walletName, setWalletName, changeAndNavigate, intl, validateWalletName}: Props) => {
const validationErrors = validateWalletName()
const ChangeWalletName = ({intl, navigation}: Props) => {
const oldWalletName = useSelector(walletNameSelector)
const walletNames = useSelector(walletNamesSelector)
const [newWalletName, setNewWalletName] = React.useState(oldWalletName)
const validationErrors = validateWalletName(newWalletName, oldWalletName, walletNames)
const hasErrors = Object.keys(validationErrors).length > 0

const errorText =
getWalletNameError(
{
tooLong: intl.formatMessage(globalMessages.walletNameErrorTooLong),
nameAlreadyTaken: intl.formatMessage(globalMessages.walletNameErrorNameAlreadyTaken),
mustBeFilled: intl.formatMessage(globalMessages.walletNameErrorMustBeFilled),
},
validationErrors,
) || undefined

const dispatch = useDispatch()
const changeAndNavigate = async () => {
if (hasErrors) return

await dispatch(changeWalletName(newWalletName))
navigation.goBack()
}

return (
<KeyboardAvoidingView enabled={Platform.OS === 'ios'} behavior="padding" style={styles.keyboardAvoidingView}>
<StatusBar type="dark" />
<SafeAreaView style={styles.safeAreaView} edges={['left', 'right', 'bottom']}>
<ScrollView
keyboardDismissMode="on-drag"
keyboardShouldPersistTaps={'always'}
contentContainerStyle={styles.scrollContentContainer}
>
<WalletNameInput
returnKeyType={'done'}
errorDelay={0}
enablesReturnKeyAutomatically
autoFocus
label={intl.formatMessage(messages.walletNameInputLabel)}
value={newWalletName}
onChangeText={setNewWalletName}
errorText={errorText}
/>
</ScrollView>

<SafeAreaView style={styles.safeAreaView}>
<ScrollView keyboardDismissMode="on-drag">
<ValidatedTextInput
label={intl.formatMessage(messages.walletNameInputLabel)}
value={walletName}
onChangeText={setWalletName}
error={getWalletNameError(
{
tooLong: intl.formatMessage(globalMessages.walletNameErrorTooLong),
nameAlreadyTaken: intl.formatMessage(globalMessages.walletNameErrorNameAlreadyTaken),
},
validationErrors,
)}
/>
</ScrollView>
<View style={styles.action}>
<Button
onPress={changeAndNavigate}
title={intl.formatMessage(messages.changeButton)}
disabled={!_.isEmpty(validationErrors)}
/>
</View>
</SafeAreaView>
</KeyboardAvoidingView>
<View style={styles.action}>
<Button onPress={changeAndNavigate} title={intl.formatMessage(messages.changeButton)} disabled={hasErrors} />
</View>
</SafeAreaView>
)
}

export default injectIntl(
(compose(
connect(
(state) => ({
oldName: walletNameSelector(state),
walletNames: walletNamesSelector(state),
}),
{changeWalletName},
),
withStateHandlers(
({oldName}) => ({
walletName: oldName,
}),
{
setWalletName: () => (value) => ({walletName: value}),
},
),
withHandlers({
validateWalletName:
({walletName, oldName, walletNames}) =>
() =>
validateWalletName(walletName, oldName, walletNames),
}),
withHandlers({
changeAndNavigate:
({navigation, walletName, changeWalletName, validateWalletName}) =>
async () => {
if (!_.isEmpty(validateWalletName())) return

await changeWalletName(walletName)
navigation.goBack()
},
}),
)(ChangeWalletName): ComponentType<{|
navigation: Navigation,
route: any,
intl: IntlShape,
|}>),
)
export default injectIntl(ChangeWalletName)
9 changes: 9 additions & 0 deletions src/components/Settings/ChangeWalletName.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @flow

import React from 'react'

import {storiesOf} from '@storybook/react-native'

import ChangeWalletName from './ChangeWalletName'

storiesOf('ChangeWalletName', module).add('Default', ({navigation}) => <ChangeWalletName navigation={navigation} />)
Loading

0 comments on commit 99c06c8

Please sign in to comment.