Skip to content
Permalink
Browse files

Mobile: Add retry button, error log and change node to Realm migration (

#1041)

* Mobile: Add ability to change node and retry during migration

* Mobile: Address comments

* Mobile: Fix notification button import and padding

* Mobile: Disable iOS pop gesture
  • Loading branch information...
cvarley100 committed Feb 8, 2019
1 parent c4b1d83 commit a3ce40e454419ba13e395d3382f19df13e728c01
@@ -1,4 +1,5 @@
import size from 'lodash/size';
import sample from 'lodash/sampleSize';
import React, { Component } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import PropTypes from 'prop-types';
@@ -8,13 +9,16 @@ import { startTrackingProgress } from 'shared-modules/actions/progress';
import { connect } from 'react-redux';
import { Styling } from 'ui/theme/general';
import { migrate } from 'shared-modules/actions/migrations';
import { setFullNode } from 'shared-modules/actions/settings';
import { reduxPersistStorageAdapter } from 'libs/store';
import ProgressSteps from 'libs/progressSteps';
import { getThemeFromState } from 'shared-modules/selectors/global';
import Header from 'ui/components/Header';
import InfoBox from 'ui/components/InfoBox';
import NotificationButtonComponent from 'ui/components/NotificationButton';
import ProgressBar from 'ui/components/OldProgressBar';
import { height } from 'libs/dimensions';
import DualFooterButtons from './DualFooterButtons';

const styles = StyleSheet.create({
container: {
@@ -29,15 +33,25 @@ const styles = StyleSheet.create({
paddingTop: height / 16,
},
midContainer: {
flex: 2.6,
flex: 1.9,
alignItems: 'center',
},
bottomContainer: {
flex: 0.7,
alignItems: 'center',
justifyContent: 'flex-end',
},
infoText: {
fontFamily: 'SourceSansPro-Light',
fontSize: Styling.fontSize3,
textAlign: 'left',
backgroundColor: 'transparent',
},
notificationButton: {
position: 'absolute',
top: height / 30 + Styling.statusBarHeight,
left: height / 30,
},
});

/**
@@ -59,18 +73,37 @@ class Migration extends Component {
startTrackingProgress: PropTypes.func.isRequired,
/** @ignore */
completedMigration: PropTypes.bool.isRequired,
/** @ignore */
notificationLog: PropTypes.array.isRequired,
/** @ignore */
nodes: PropTypes.array.isRequired,
/** @ignore */
setFullNode: PropTypes.func.isRequired,
/** @ignore */
isChangingNode: PropTypes.bool.isRequired,
};

constructor() {
super();
this.state = {
hasFailedMigration: false,
};
this.changeNode = this.changeNode.bind(this);
this.retryMigration = this.retryMigration.bind(this);
}

componentDidMount() {
this.props.startTrackingProgress(ProgressSteps.migration);

this.props.migrate(reduxPersistStorageAdapter);
}

componentWillReceiveProps(newProps) {
if (!this.props.completedMigration && newProps.completedMigration) {
this.navigateToLoadingScreen();
}
if (size(this.props.notificationLog) !== size(newProps.notificationLog)) {
this.setState({ hasFailedMigration: true });
}
}

/**
@@ -107,6 +140,25 @@ class Migration extends Component {
});
}

/**
* Changes to a random node
*
* @method changeNode
*/
changeNode() {
this.props.setFullNode(...sample(this.props.nodes));
}

/**
* Retries migration in case of failure
*
* @method retryMigration
*/
retryMigration() {
this.setState({ hasFailedMigration: false });
this.props.migrate(reduxPersistStorageAdapter);
}

/**
* Renders progress bar textual information
*
@@ -119,7 +171,7 @@ class Migration extends Component {
}

render() {
const { t, theme: { body, primary }, activeSteps, activeStepIndex } = this.props;
const { t, theme: { body, primary }, activeSteps, activeStepIndex, isChangingNode } = this.props;
const textColor = { color: body.color };
const sizeOfActiveSteps = size(activeSteps) - 1;

@@ -135,18 +187,36 @@ class Migration extends Component {
</View>
</InfoBox>
<View style={{ flex: 0.4 }} />
<ProgressBar
style={{
textWrapper: { flex: 0.3 },
}}
indeterminate={activeStepIndex === -1}
progress={activeStepIndex / sizeOfActiveSteps}
color={primary.color}
textColor={body.color}
>
{t(this.renderProgressBarChildren())}
</ProgressBar>
{activeStepIndex > -1 && (
<ProgressBar
style={{
textWrapper: { flex: 0.3 },
}}
indeterminate={activeStepIndex === -1}
progress={activeStepIndex / sizeOfActiveSteps}
color={primary.color}
textColor={body.color}
>
{t(this.renderProgressBarChildren())}
</ProgressBar>
)}
</View>
<View style={styles.bottomContainer}>
{this.state.hasFailedMigration && (
<DualFooterButtons
onLeftButtonPress={this.changeNode}
onRightButtonPress={this.retryMigration}
leftButtonText={t('login:changeNode')}
rightButtonText={t('retry')}
isLeftButtonLoading={isChangingNode}
/>
)}
</View>
{this.state.hasFailedMigration && (
<View style={styles.notificationButton}>
<NotificationButtonComponent displayTopBar={false} />
</View>
)}
</View>
);
}
@@ -157,11 +227,15 @@ const mapStateToProps = (state) => ({
activeStepIndex: state.progress.activeStepIndex,
activeSteps: state.progress.activeSteps,
completedMigration: state.settings.completedMigration,
notificationLog: state.alerts.notificationLog,
nodes: state.settings.nodes,
isChangingNode: state.ui.isChangingNode,
});

const mapDispatchToProps = {
migrate,
startTrackingProgress,
setFullNode,
};

export default withNamespaces(['migration'])(connect(mapStateToProps, mapDispatchToProps)(Migration));
@@ -0,0 +1,104 @@
import size from 'lodash/size';
import React, { Component } from 'react';
import { StyleSheet, View, TouchableOpacity } from 'react-native';
import { getThemeFromState } from 'shared-modules/selectors/global';
import { clearLog } from 'shared-modules/actions/alerts';
import { toggleModalActivity } from 'shared-modules/actions/ui';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { withNamespaces } from 'react-i18next';
import { width } from 'libs/dimensions';
import { Icon } from 'ui/theme/icons';

const styles = StyleSheet.create({
container: {
width: width / 9,
height: width / 9,
},
innerContainer: {
justifyContent: 'center',
alignItems: 'center',
width: width / 9,
flex: 1,
},
disabled: {
color: '#a9a9a9',
},
});

export class NotificationButton extends Component {
static propTypes = {
/** @ignore */
theme: PropTypes.object.isRequired,
/** @ignore */
isModalActive: PropTypes.bool.isRequired,
/** @ignore */
clearLog: PropTypes.func.isRequired,
/** @ignore */
toggleModalActivity: PropTypes.func.isRequired,
/** @ignore */
isTransitioning: PropTypes.bool.isRequired,
/** @ignore */
notificationLog: PropTypes.array.isRequired,
/** Determines whether to display topBar when modal is open */
displayTopBar: PropTypes.bool,
};

static defaultProps = {
displayTopBar: true,
};

/**
* Displays error log
*
* @method showModal
*/
showModal() {
const { isTransitioning, theme, notificationLog, displayTopBar } = this.props;
if (!isTransitioning) {
this.props.toggleModalActivity('notificationLog', {
hideModal: this.props.toggleModalActivity,
theme,
notificationLog,
clearLog: this.props.clearLog,
displayTopBar,
});
}
}

render() {
const { theme: { bar }, isModalActive, notificationLog } = this.props;
const hasNotifications = size(notificationLog) && notificationLog.length > 0;

return (
<View style={styles.container}>
{(hasNotifications && (
<TouchableOpacity onPress={() => this.showModal()} style={styles.innerContainer}>
<Icon
name="notification"
size={width / 18}
color={bar.color}
style={isModalActive && styles.disabled && { opacity: 0.5 }}
/>
</TouchableOpacity>
)) || <View style={styles.innerContainer} />}
</View>
);
}
}

const mapStateToProps = (state) => ({
theme: getThemeFromState(state),
isModalActive: state.ui.isModalActive,
isTransitioning: state.ui.isTransitioning,
notificationLog: state.alerts.notificationLog,
});

const mapDispatchToProps = {
clearLog,
toggleModalActivity,
};

export default withNamespaces(['enterSeed', 'global'])(
connect(mapStateToProps, mapDispatchToProps)(NotificationButton),
);
@@ -52,6 +52,12 @@ export class NotificationLogModal extends PureComponent {
clearLog: PropTypes.func.isRequired,
/** @ignore */
t: PropTypes.func.isRequired,
/** Deteremines whether to display the topbar */
displayTopBar: PropTypes.bool,
};

static defaultProps = {
displayTopBar: true,
};

constructor() {
@@ -84,7 +90,7 @@ export class NotificationLogModal extends PureComponent {

return (
<ModalView
displayTopBar
displayTopBar={this.props.displayTopBar}
dualButtons
onLeftButtonPress={() => this.clearNotificationLog()}
onRightButtonPress={() => this.props.hideModal()}

0 comments on commit a3ce40e

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