Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 6 commits into from Feb 8, 2019
@@ -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 (this.props.notificationLog !== newProps.notificationLog) {
This conversation was marked as resolved by cvarley100

This comment has been minimized.

Copy link
@laumair

laumair Feb 8, 2019

Member

notificationLog is an array. Perhaps we should be comparing size here (Also considering that there could be previous error logs).

This comment has been minimized.

Copy link
@rajivshah3

rajivshah3 Feb 8, 2019

Collaborator

Would this trigger if the user cleared the error logs?

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, 1));
This conversation was marked as resolved by cvarley100

This comment has been minimized.

Copy link
@laumair

laumair Feb 8, 2019

Member

sample takes a single parameter. Perhaps you meant to use sampleSize here?

}

/**
* 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()}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.