handle new email verification links (#426)

* handle new email verification links
* some updates to work with new auth flow
This commit is contained in:
Akinwale Ariwodola 2019-02-18 07:50:32 +01:00 committed by GitHub
parent c8de700460
commit 9638ad4f06
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 78 additions and 32 deletions

View file

@ -38,6 +38,7 @@ import { doDeleteCompleteBlobs } from 'redux/actions/file';
import { selectDrawerStack } from 'redux/selectors/drawer'; import { selectDrawerStack } from 'redux/selectors/drawer';
import { SETTINGS, doDismissToast, doToast, selectToast } from 'lbry-redux'; import { SETTINGS, doDismissToast, doToast, selectToast } from 'lbry-redux';
import { import {
doUserCheckEmailVerified,
doUserEmailVerify, doUserEmailVerify,
doUserEmailVerifyFailure, doUserEmailVerifyFailure,
selectEmailToVerify, selectEmailToVerify,
@ -235,8 +236,10 @@ class AppWithNavigationState extends React.Component {
constructor() { constructor() {
super(); super();
this.emailVerifyCheckInterval = null;
this.state = { this.state = {
emailVerifyDone: false emailVerifyDone: false,
verifyPending: false
}; };
} }
@ -262,15 +265,37 @@ class AppWithNavigationState extends React.Component {
} }
componentDidMount() { componentDidMount() {
this.emailVerifyCheckInterval = setInterval(() => this.checkEmailVerification(), 5000);
Linking.addEventListener('url', this._handleUrl); Linking.addEventListener('url', this._handleUrl);
} }
checkEmailVerification = () => {
const { dispatch } = this.props;
AsyncStorage.getItem(Constants.KEY_EMAIL_VERIFY_PENDING).then(pending => {
this.setState({ verifyPending: ('true' === pending) });
if ('true' === pending) {
dispatch(doUserCheckEmailVerified());
}
});
}
componentWillUnmount() { componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange); AppState.removeEventListener('change', this._handleAppStateChange);
BackHandler.removeEventListener('hardwareBackPress'); BackHandler.removeEventListener('hardwareBackPress');
Linking.removeEventListener('url', this._handleUrl); Linking.removeEventListener('url', this._handleUrl);
} }
componentDidUpdate() {
const { user } = this.props;
if (this.state.verifyPending && this.emailVerifyCheckInterval > 0 && user && user.has_verified_email) {
clearInterval(this.emailVerifyCheckInterval);
AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'false');
this.setState({ verifyPending: false });
ToastAndroid.show('Your email address was successfully verified.', ToastAndroid.LONG);
}
}
componentWillUpdate(nextProps) { componentWillUpdate(nextProps) {
const { dispatch } = this.props; const { dispatch } = this.props;
const { const {

View file

@ -1,9 +1,10 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
doUserEmailNew, doUserEmailNew,
doUserResendVerificationEmail,
selectEmailNewErrorMessage, selectEmailNewErrorMessage,
selectEmailNewIsPending, selectEmailNewIsPending,
selectEmailToVerify selectEmailToVerify,
} from 'lbryinc'; } from 'lbryinc';
import { doToast } from 'lbry-redux'; import { doToast } from 'lbry-redux';
import EmailRewardSubcard from './view'; import EmailRewardSubcard from './view';
@ -16,7 +17,8 @@ const select = state => ({
const perform = dispatch => ({ const perform = dispatch => ({
addUserEmail: email => dispatch(doUserEmailNew(email)), addUserEmail: email => dispatch(doUserEmailNew(email)),
notify: data => dispatch(doToast(data)) notify: data => dispatch(doToast(data)),
resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email))
}); });
export default connect(select, perform)(EmailRewardSubcard); export default connect(select, perform)(EmailRewardSubcard);

View file

@ -18,6 +18,8 @@ import rewardStyle from '../../styles/reward';
class EmailRewardSubcard extends React.PureComponent { class EmailRewardSubcard extends React.PureComponent {
state = { state = {
email: null, email: null,
emailAlreadySet: false,
previousEmail: null,
verfiyStarted: false verfiyStarted: false
}; };
@ -25,9 +27,9 @@ class EmailRewardSubcard extends React.PureComponent {
const { emailToVerify } = this.props; const { emailToVerify } = this.props;
AsyncStorage.getItem(Constants.KEY_FIRST_RUN_EMAIL).then(email => { AsyncStorage.getItem(Constants.KEY_FIRST_RUN_EMAIL).then(email => {
if (email && email.trim().length > 0) { if (email && email.trim().length > 0) {
this.setState({ email }); this.setState({ email, emailAlreadySet: true, previousEmail: email });
} else { } else {
this.setState({ email: emailToVerify }); this.setState({ email: emailToVerify, previousEmail: emailToVerify });
} }
}); });
} }
@ -41,9 +43,8 @@ class EmailRewardSubcard extends React.PureComponent {
notify({ message: String(emailNewErrorMessage), isError: true }); notify({ message: String(emailNewErrorMessage), isError: true });
this.setState({ verifyStarted: false }); this.setState({ verifyStarted: false });
} else { } else {
notify({ notify({ message: 'Please follow the instructions in the email sent to your address to continue.' });
message: 'Please follow the instructions in the email sent to your address to continue.', AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'true');
});
} }
} }
} }
@ -59,7 +60,7 @@ class EmailRewardSubcard extends React.PureComponent {
return; return;
} }
const { addUserEmail, notify } = this.props; const { addUserEmail, notify, resendVerificationEmail } = this.props;
const { email } = this.state; const { email } = this.state;
if (!email || email.trim().length === 0 || email.indexOf('@') === -1) { if (!email || email.trim().length === 0 || email.indexOf('@') === -1) {
return notify({ return notify({
@ -68,6 +69,14 @@ class EmailRewardSubcard extends React.PureComponent {
} }
this.setState({ verifyStarted: true }); this.setState({ verifyStarted: true });
if (this.state.emailAlreadySet && this.state.previousEmail === email) {
// resend verification email if there was one previously set (and it wasn't changed)
resendVerificationEmail(email);
AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'true');
notify({ message: 'Please follow the instructions in the email sent to your address to continue.' });
return;
}
addUserEmail(email); addUserEmail(email);
} }

View file

@ -44,6 +44,10 @@ class RewardSummary extends React.Component {
render() { render() {
const { fetching, navigation, unclaimedRewardAmount, user } = this.props; const { fetching, navigation, unclaimedRewardAmount, user } = this.props;
if (!user) {
return null;
}
if (this.state.dismissed || if (this.state.dismissed ||
(user && user.is_reward_approved) || (user && user.is_reward_approved) ||
this.state.actionsLeft === 0 || this.state.actionsLeft === 0 ||

View file

@ -22,12 +22,12 @@ class SuggestedSubscriptions extends React.PureComponent {
return suggested ? ( return suggested ? (
<SectionList style={subscriptionsStyle.scrollContainer} <SectionList style={subscriptionsStyle.scrollContainer}
renderItem={ ({item, index, section}) => { console.log(item); return ( renderItem={ ({item, index, section}) => (
<SuggestedSubscriptionItem <SuggestedSubscriptionItem
key={item} key={item}
categoryLink={normalizeURI(item)} categoryLink={normalizeURI(item)}
navigation={navigation} /> navigation={navigation} />
); } )
} }
renderSectionHeader={ renderSectionHeader={
({section: {title}}) => { ({section: {title}}) => {

View file

@ -1,6 +1,7 @@
const Constants = { const Constants = {
KEY_FIRST_RUN_EMAIL: "firstRunEmail", KEY_FIRST_RUN_EMAIL: "firstRunEmail",
KEY_SHOULD_VERIFY_EMAIL: "shouldVerifyEmail", KEY_SHOULD_VERIFY_EMAIL: "shouldVerifyEmail",
KEY_EMAIL_VERIFY_PENDING: "emailVerifyPending",
SETTING_ALPHA_UNDERSTANDS_RISKS: "alphaUnderstandRisks", SETTING_ALPHA_UNDERSTANDS_RISKS: "alphaUnderstandRisks",

View file

@ -117,8 +117,8 @@ class DiscoverPage extends React.PureComponent {
<Text style={discoverStyle.title}>Fetching content...</Text> <Text style={discoverStyle.title}>Fetching content...</Text>
</View> </View>
)} )}
{hasContent && {(!!hasContent) &&
<SectionList style={discoverStyle.scrollContainer} (<SectionList style={discoverStyle.scrollContainer}
renderItem={ ({item, index, section}) => ( renderItem={ ({item, index, section}) => (
<FileItem <FileItem
style={discoverStyle.fileItem} style={discoverStyle.fileItem}
@ -135,7 +135,7 @@ class DiscoverPage extends React.PureComponent {
} }
sections={Object.keys(featuredUris).map(category => ({ title: category, data: featuredUris[category] }))} sections={Object.keys(featuredUris).map(category => ({ title: category, data: featuredUris[category] }))}
keyExtractor={(item, index) => item} keyExtractor={(item, index) => item}
/> />)
} }
<FloatingWalletBalance navigation={navigation} /> <FloatingWalletBalance navigation={navigation} />
<UriBar navigation={navigation} /> <UriBar navigation={navigation} />

View file

@ -1,18 +1,18 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doToast } from 'lbry-redux'; import { doToast } from 'lbry-redux';
import { import {
doGenerateAuthToken, doAuthenticate,
doUserEmailNew, doUserEmailNew,
selectAuthToken, selectAuthToken,
selectEmailNewErrorMessage, selectEmailNewErrorMessage,
selectEmailNewIsPending, selectEmailNewIsPending,
selectEmailToVerify, selectEmailToVerify,
selectIsAuthenticating selectAuthenticationIsPending
} from 'lbryinc'; } from 'lbryinc';
import FirstRun from './view'; import FirstRun from './view';
const select = (state) => ({ const select = (state) => ({
authenticating: selectIsAuthenticating(state), authenticating: selectAuthenticationIsPending(state),
authToken: selectAuthToken(state), authToken: selectAuthToken(state),
emailToVerify: selectEmailToVerify(state), emailToVerify: selectEmailToVerify(state),
emailNewErrorMessage: selectEmailNewErrorMessage(state), emailNewErrorMessage: selectEmailNewErrorMessage(state),
@ -21,7 +21,7 @@ const select = (state) => ({
const perform = dispatch => ({ const perform = dispatch => ({
addUserEmail: email => dispatch(doUserEmailNew(email)), addUserEmail: email => dispatch(doUserEmailNew(email)),
generateAuthToken: installationId => dispatch(doGenerateAuthToken(installationId)), authenticate: (appVersion, os) => dispatch(doAuthenticate(appVersion, os)),
notify: data => dispatch(doToast(data)) notify: data => dispatch(doToast(data))
}); });

View file

@ -4,6 +4,8 @@ import {
ActivityIndicator, ActivityIndicator,
AsyncStorage, AsyncStorage,
Linking, Linking,
NativeModules,
Platform,
Text, Text,
TextInput, TextInput,
View View
@ -46,19 +48,21 @@ class EmailCollectPage extends React.PureComponent {
} }
startAuthenticating = () => { startAuthenticating = () => {
const { generateAuthToken } = this.props; const { authenticate } = this.props;
this.setState({ authenticationStarted: true, authenticationFailed: false }); this.setState({ authenticationStarted: true, authenticationFailed: false });
Lbry.status().then(info => { NativeModules.VersionInfo.getAppVersion().then(appVersion => {
generateAuthToken(info.installation_id) Lbry.status().then(info => {
}).catch(error => { authenticate(appVersion, Platform.OS)
if (this.state.statusTries >= EmailCollectPage.MAX_STATUS_TRIES) { }).catch(error => {
this.setState({ authenticationFailed: true }); if (this.state.statusTries >= EmailCollectPage.MAX_STATUS_TRIES) {
} else { this.setState({ authenticationFailed: true });
setTimeout(() => { } else {
this.startAuthenticating(); setTimeout(() => {
this.setState({ statusTries: this.state.statusTries + 1 }); this.startAuthenticating();
}, 1000); // Retry every second for a maximum of MAX_STATUS_TRIES tries (30 seconds) this.setState({ statusTries: this.state.statusTries + 1 });
} }, 1000); // Retry every second for a maximum of MAX_STATUS_TRIES tries (30 seconds)
}
});
}); });
} }
@ -70,6 +74,7 @@ class EmailCollectPage extends React.PureComponent {
onEmailChanged(text); onEmailChanged(text);
} }
AsyncStorage.setItem(Constants.KEY_FIRST_RUN_EMAIL, text); AsyncStorage.setItem(Constants.KEY_FIRST_RUN_EMAIL, text);
AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'true');
} }
render() { render() {

View file

@ -160,9 +160,9 @@ class FirstRunScreen extends React.PureComponent {
render() { render() {
const { const {
authenticate,
authenticating, authenticating,
authToken, authToken,
generateAuthToken,
emailNewErrorMessage, emailNewErrorMessage,
emailNewPending, emailNewPending,
emailToVerify emailToVerify
@ -175,7 +175,7 @@ class FirstRunScreen extends React.PureComponent {
} else if (this.state.currentPage === 'email-collect') { } else if (this.state.currentPage === 'email-collect') {
page = (<EmailCollectPage authenticating={authenticating} page = (<EmailCollectPage authenticating={authenticating}
authToken={authToken} authToken={authToken}
generateAuthToken={generateAuthToken} authenticate={authenticate}
onEmailChanged={this.onEmailChanged} onEmailChanged={this.onEmailChanged}
onEmailViewLayout={this.onEmailViewLayout} />); onEmailViewLayout={this.onEmailViewLayout} />);
} }