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 { SETTINGS, doDismissToast, doToast, selectToast } from 'lbry-redux';
import {
doUserCheckEmailVerified,
doUserEmailVerify,
doUserEmailVerifyFailure,
selectEmailToVerify,
@ -235,8 +236,10 @@ class AppWithNavigationState extends React.Component {
constructor() {
super();
this.emailVerifyCheckInterval = null;
this.state = {
emailVerifyDone: false
emailVerifyDone: false,
verifyPending: false
};
}
@ -262,15 +265,37 @@ class AppWithNavigationState extends React.Component {
}
componentDidMount() {
this.emailVerifyCheckInterval = setInterval(() => this.checkEmailVerification(), 5000);
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() {
AppState.removeEventListener('change', this._handleAppStateChange);
BackHandler.removeEventListener('hardwareBackPress');
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) {
const { dispatch } = this.props;
const {

View file

@ -1,9 +1,10 @@
import { connect } from 'react-redux';
import {
doUserEmailNew,
doUserResendVerificationEmail,
selectEmailNewErrorMessage,
selectEmailNewIsPending,
selectEmailToVerify
selectEmailToVerify,
} from 'lbryinc';
import { doToast } from 'lbry-redux';
import EmailRewardSubcard from './view';
@ -16,7 +17,8 @@ const select = state => ({
const perform = dispatch => ({
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);

View file

@ -18,6 +18,8 @@ import rewardStyle from '../../styles/reward';
class EmailRewardSubcard extends React.PureComponent {
state = {
email: null,
emailAlreadySet: false,
previousEmail: null,
verfiyStarted: false
};
@ -25,9 +27,9 @@ class EmailRewardSubcard extends React.PureComponent {
const { emailToVerify } = this.props;
AsyncStorage.getItem(Constants.KEY_FIRST_RUN_EMAIL).then(email => {
if (email && email.trim().length > 0) {
this.setState({ email });
this.setState({ email, emailAlreadySet: true, previousEmail: email });
} 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 });
this.setState({ verifyStarted: false });
} else {
notify({
message: 'Please follow the instructions in the email sent to your address to continue.',
});
notify({ 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;
}
const { addUserEmail, notify } = this.props;
const { addUserEmail, notify, resendVerificationEmail } = this.props;
const { email } = this.state;
if (!email || email.trim().length === 0 || email.indexOf('@') === -1) {
return notify({
@ -68,6 +69,14 @@ class EmailRewardSubcard extends React.PureComponent {
}
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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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