handle new email verification links (#426)
* handle new email verification links * some updates to work with new auth flow
This commit is contained in:
parent
c8de700460
commit
9638ad4f06
10 changed files with 78 additions and 32 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 ||
|
||||||
|
|
|
@ -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}}) => {
|
||||||
|
|
|
@ -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",
|
||||||
|
|
||||||
|
|
|
@ -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} />
|
||||||
|
|
|
@ -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))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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} />);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue