complete authentication flow and email verification link implementation #232
8
app/package-lock.json
generated
|
@ -3965,6 +3965,14 @@
|
||||||
"reselect": "^3.0.0"
|
"reselect": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lbryinc": {
|
||||||
|
"version": "github:lbryio/lbryinc#8e33473daa56ebe80b12509ac5374c5884efef90",
|
||||||
|
"from": "github:lbryio/lbryinc#authentication-flow",
|
||||||
|
"requires": {
|
||||||
|
"lbry-redux": "github:lbryio/lbry-redux#467e48c77b8004cef738e950bdcc67654748ae9f",
|
||||||
|
"reselect": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lcid": {
|
"lcid": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
"start": "node node_modules/react-native/local-cli/cli.js start"
|
"start": "node node_modules/react-native/local-cli/cli.js start"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"base-64": "^0.1.0",
|
||||||
"lbry-redux": "lbryio/lbry-redux",
|
"lbry-redux": "lbryio/lbry-redux",
|
||||||
|
"lbryinc": "lbryio/lbryinc#authentication-flow",
|
||||||
"moment": "^2.22.1",
|
"moment": "^2.22.1",
|
||||||
"react": "16.2.0",
|
"react": "16.2.0",
|
||||||
"react-native": "0.55.3",
|
"react-native": "0.55.3",
|
||||||
|
|
|
@ -27,8 +27,17 @@ import {
|
||||||
TextInput,
|
TextInput,
|
||||||
ToastAndroid
|
ToastAndroid
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { SETTINGS, doHideNotification, selectNotification } from 'lbry-redux';
|
import { SETTINGS, doHideNotification, doNotify, selectNotification } from 'lbry-redux';
|
||||||
|
import {
|
||||||
|
doUserEmailVerify,
|
||||||
|
doUserEmailVerifyFailure,
|
||||||
|
selectEmailToVerify,
|
||||||
|
selectEmailVerifyIsPending,
|
||||||
|
selectEmailVerifyErrorMessage,
|
||||||
|
selectUser
|
||||||
|
} from 'lbryinc';
|
||||||
import { makeSelectClientSetting } from '../redux/selectors/settings';
|
import { makeSelectClientSetting } from '../redux/selectors/settings';
|
||||||
|
import { decode as atob } from 'base-64';
|
||||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||||
import discoverStyle from '../styles/discover';
|
import discoverStyle from '../styles/discover';
|
||||||
import searchStyle from '../styles/search';
|
import searchStyle from '../styles/search';
|
||||||
|
@ -122,6 +131,13 @@ export const AppNavigator = new StackNavigator({
|
||||||
class AppWithNavigationState extends React.Component {
|
class AppWithNavigationState extends React.Component {
|
||||||
static supportedDisplayTypes = ['toast'];
|
static supportedDisplayTypes = ['toast'];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.state = {
|
||||||
|
emailVerifyDone: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
AppState.addEventListener('change', this._handleAppStateChange);
|
AppState.addEventListener('change', this._handleAppStateChange);
|
||||||
BackHandler.addEventListener('hardwareBackPress', function() {
|
BackHandler.addEventListener('hardwareBackPress', function() {
|
||||||
|
@ -144,7 +160,7 @@ class AppWithNavigationState extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
}
|
}
|
||||||
return false;fo
|
return false;
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +176,14 @@ class AppWithNavigationState extends React.Component {
|
||||||
|
|
||||||
componentWillUpdate(nextProps) {
|
componentWillUpdate(nextProps) {
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
const { notification } = nextProps;
|
const {
|
||||||
|
notification,
|
||||||
|
emailToVerify,
|
||||||
|
emailVerifyPending,
|
||||||
|
emailVerifyErrorMessage,
|
||||||
|
user
|
||||||
|
} = nextProps;
|
||||||
|
|
||||||
if (notification) {
|
if (notification) {
|
||||||
const { displayType, message } = notification;
|
const { displayType, message } = notification;
|
||||||
let currentDisplayType;
|
let currentDisplayType;
|
||||||
|
@ -182,6 +205,16 @@ class AppWithNavigationState extends React.Component {
|
||||||
|
|
||||||
dispatch(doHideNotification());
|
dispatch(doHideNotification());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (user &&
|
||||||
|
!emailVerifyPending &&
|
||||||
|
!this.state.emailVerifyDone &&
|
||||||
|
(emailToVerify || emailVerifyErrorMessage)) {
|
||||||
|
this.setState({ emailVerifyDone: true });
|
||||||
|
const message = emailVerifyErrorMessage ?
|
||||||
|
String(emailVerifyErrorMessage) : 'Your email address was successfully verified.';
|
||||||
|
dispatch(doNotify({ message, displayType: ['toast'] }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleAppStateChange = (nextAppState) => {
|
_handleAppStateChange = (nextAppState) => {
|
||||||
|
@ -200,12 +233,37 @@ class AppWithNavigationState extends React.Component {
|
||||||
_handleUrl = (evt) => {
|
_handleUrl = (evt) => {
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
if (evt.url) {
|
if (evt.url) {
|
||||||
const navigateAction = NavigationActions.navigate({
|
if (evt.url.startsWith('lbry://?verify=')) {
|
||||||
routeName: 'File',
|
this.setState({ emailVerifyDone: false });
|
||||||
key: evt.url,
|
let verification = {};
|
||||||
params: { uri: evt.url }
|
try {
|
||||||
});
|
verification = JSON.parse(atob(evt.url.substring(15)));
|
||||||
dispatch(navigateAction);
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verification.token && verification.recaptcha) {
|
||||||
|
try {
|
||||||
|
dispatch(doUserEmailVerify(verification.token, verification.recaptcha));
|
||||||
|
} catch (error) {
|
||||||
|
const message = 'Invalid Verification Token';
|
||||||
|
dispatch(doUserEmailVerifyFailure(message));
|
||||||
|
dispatch(doNotify({ message, displayType: ['toast'] }));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dispatch(doNotify({
|
||||||
|
message: 'Invalid Verification URI',
|
||||||
|
displayType: ['toast'],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const navigateAction = NavigationActions.navigate({
|
||||||
|
routeName: 'File',
|
||||||
|
key: evt.url,
|
||||||
|
params: { uri: evt.url }
|
||||||
|
});
|
||||||
|
dispatch(navigateAction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,10 +282,14 @@ class AppWithNavigationState extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state),
|
||||||
nav: state.nav,
|
nav: state.nav,
|
||||||
notification: selectNotification(state),
|
notification: selectNotification(state),
|
||||||
keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state),
|
emailToVerify: selectEmailToVerify(state),
|
||||||
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_NSFW)(state)
|
emailVerifyPending: selectEmailVerifyIsPending(state),
|
||||||
|
emailVerifyErrorMessage: selectEmailVerifyErrorMessage(state),
|
||||||
|
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_NSFW)(state),
|
||||||
|
user: selectUser(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps)(AppWithNavigationState);
|
export default connect(mapStateToProps)(AppWithNavigationState);
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
const Constants = {
|
const Constants = {
|
||||||
SETTING_ALPHA_UNDERSTANDS_RISKS: "ALPHA_UNDERSTANDS_RISKS"
|
KEY_FIRST_RUN_EMAIL: "firstRunEmail",
|
||||||
|
|
||||||
Why is this value camel case unlike the others? Why is this value camel case unlike the others?
The value for the The value for the `SETTING_*` key should actually be camel case.
|
|||||||
|
SETTING_ALPHA_UNDERSTANDS_RISKS: "ALPHA_UNDERSTANDS_RISKS",
|
||||||
|
|
||||||
|
ACTION_FIRST_RUN_PAGE_CHANGED: "FIRST_RUN_PAGE_CHANGED",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Constants;
|
export default Constants;
|
||||||
|
|
|
@ -17,6 +17,7 @@ import {
|
||||||
searchReducer,
|
searchReducer,
|
||||||
walletReducer
|
walletReducer
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
|
import { authReducer, userReducer } from 'lbryinc';
|
||||||
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
|
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
|
||||||
import { createLogger } from 'redux-logger';
|
import { createLogger } from 'redux-logger';
|
||||||
import { StackNavigator, addNavigationHelpers } from 'react-navigation';
|
import { StackNavigator, addNavigationHelpers } from 'react-navigation';
|
||||||
|
@ -68,6 +69,7 @@ const navigatorReducer = (state = initialNavState, action) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const reducers = combineReducers({
|
const reducers = combineReducers({
|
||||||
|
auth: authReducer,
|
||||||
claims: claimsReducer,
|
claims: claimsReducer,
|
||||||
costInfo: costInfoReducer,
|
costInfo: costInfoReducer,
|
||||||
fileInfo: fileInfoReducer,
|
fileInfo: fileInfoReducer,
|
||||||
|
@ -75,7 +77,8 @@ const reducers = combineReducers({
|
||||||
search: searchReducer,
|
search: searchReducer,
|
||||||
wallet: walletReducer,
|
wallet: walletReducer,
|
||||||
nav: navigatorReducer,
|
nav: navigatorReducer,
|
||||||
settings: settingsReducer
|
settings: settingsReducer,
|
||||||
|
user: userReducer
|
||||||
});
|
});
|
||||||
|
|
||||||
const bulkThunk = createBulkThunkMiddleware();
|
const bulkThunk = createBulkThunkMiddleware();
|
||||||
|
@ -93,18 +96,20 @@ const store = createStore(
|
||||||
applyMiddleware(...middleware)
|
applyMiddleware(...middleware)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
window.store = store;
|
||||||
|
|
||||||
const compressor = createCompressor();
|
const compressor = createCompressor();
|
||||||
|
const authFilter = createFilter('auth', ['authToken']);
|
||||||
const saveClaimsFilter = createFilter('claims', ['byId', 'claimsByUri']);
|
const saveClaimsFilter = createFilter('claims', ['byId', 'claimsByUri']);
|
||||||
const subscriptionsFilter = createFilter('subscriptions', ['subscriptions']);
|
const subscriptionsFilter = createFilter('subscriptions', ['subscriptions']);
|
||||||
const settingsFilter = createFilter('settings', ['clientSettings']);
|
const settingsFilter = createFilter('settings', ['clientSettings']);
|
||||||
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
||||||
|
|
||||||
const persistOptions = {
|
const persistOptions = {
|
||||||
whitelist: ['claims', 'subscriptions', 'settings', 'wallet'],
|
whitelist: ['auth', 'claims', 'subscriptions', 'settings', 'wallet'],
|
||||||
// Order is important. Needs to be compressed last or other transforms can't
|
// Order is important. Needs to be compressed last or other transforms can't
|
||||||
// read the data
|
// read the data
|
||||||
transforms: [saveClaimsFilter, subscriptionsFilter, settingsFilter, walletFilter, compressor],
|
transforms: [authFilter, saveClaimsFilter, subscriptionsFilter, settingsFilter, walletFilter, compressor],
|
||||||
debounce: 10000,
|
debounce: 10000,
|
||||||
storage: FilesystemStorage
|
storage: FilesystemStorage
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,7 +24,6 @@ class AboutPage extends React.PureComponent {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
Lbry.status().then(info => {
|
Lbry.status().then(info => {
|
||||||
console.log(info);
|
|
||||||
this.setState({
|
this.setState({
|
||||||
lbryId: info.installation_id,
|
lbryId: info.installation_id,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,32 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { doNotify } from 'lbry-redux';
|
||||||
|
import {
|
||||||
|
doGenerateAuthToken,
|
||||||
|
doUserEmailNew,
|
||||||
|
selectAuthToken,
|
||||||
|
selectEmailNewErrorMessage,
|
||||||
|
selectEmailNewIsPending,
|
||||||
|
selectEmailToVerify,
|
||||||
|
selectEmailVerifyErrorMessage,
|
||||||
|
selectEmailVerifyIsPending,
|
||||||
|
selectIsAuthenticating
|
||||||
|
} from 'lbryinc';
|
||||||
import FirstRun from './view';
|
import FirstRun from './view';
|
||||||
|
|
||||||
const perform = dispatch => ({});
|
const select = (state) => ({
|
||||||
|
authenticating: selectIsAuthenticating(state),
|
||||||
|
authToken: selectAuthToken(state),
|
||||||
|
emailToVerify: selectEmailToVerify(state),
|
||||||
|
emailNewErrorMessage: selectEmailNewErrorMessage(state),
|
||||||
|
emailNewPending: selectEmailNewIsPending(state),
|
||||||
|
emailVerifyErrorMessage: selectEmailVerifyErrorMessage(state),
|
||||||
|
emailVerifyPending: selectEmailVerifyIsPending(state)
|
||||||
|
});
|
||||||
|
|
||||||
export default connect(null, perform)(FirstRun);
|
const perform = dispatch => ({
|
||||||
|
addUserEmail: email => dispatch(doUserEmailNew(email)),
|
||||||
|
generateAuthToken: installationId => dispatch(doGenerateAuthToken(installationId)),
|
||||||
|
notify: data => dispatch(doNotify(data))
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, perform)(FirstRun);
|
83
app/src/page/firstRun/internal/email-collect-page.js
Normal file
|
@ -0,0 +1,83 @@
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
import React from 'react';
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
import { Lbry } from 'lbry-redux';
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
import {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
ActivityIndicator,
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
AsyncStorage,
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
Linking,
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
Text,
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
TextInput,
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
View
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
} from 'react-native';
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
import Colors from '../../../styles/colors';
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
import firstRunStyle from '../../../styles/firstRun';
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
class EmailCollectPage extends React.PureComponent {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
constructor() {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
super();
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
this.state = {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
email: null
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
};
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
}
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
componentDidMount() {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
// call user/new
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
const { generateAuthToken, authenticating, authToken } = this.props;
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
if (!authToken && !authenticating) {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
Lbry.status().then(info => {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
generateAuthToken(info.installation_id)
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
});
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
}
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
AsyncStorage.getItem('firstRunEmail').then(email => {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
if (email) {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
this.setState({ email });
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
}
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
});
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
}
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
handleChangeText = (text) => {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
// save the value to the state email
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
this.setState({ email: text });
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
AsyncStorage.setItem('firstRunEmail', text);
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
}
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
render() {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
let authenticationFailed = false;
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
const { authenticating, authToken, onEmailViewLayout, emailToVerify } = this.props;
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
let content;
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
if (!authToken || authenticating) {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
content = (
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
<View>
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
<ActivityIndicator size="large" color={Colors.White} style={firstRunStyle.waiting} />
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
<Text style={firstRunStyle.paragraph}>Please wait while we get some things ready...</Text>
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
</View>
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
)
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
} else if (authenticationFailed) {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
// Ask the user to try again
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
} else {
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
content = (
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
<View onLayout={onEmailViewLayout}>
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
<Text style={firstRunStyle.title}>Rewards.</Text>
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
<Text style={firstRunStyle.paragraph}>You can earn LBRY Credits (LBC) rewards by completing various tasks in the app.</Text>
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
<Text style={firstRunStyle.paragraph}>Please provide a valid email address below to be able to claim your rewards.</Text>
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
<TextInput style={firstRunStyle.emailInput}
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
placeholder="you@example.com"
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
underlineColorAndroid="transparent"
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
value={this.state.email}
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
onChangeText={text => this.handleChangeText(text)}
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
/>
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
<Text style={firstRunStyle.infoParagraph}>This information is disclosed only to LBRY, Inc. and not to the LBRY network. It is only required to earn LBRY rewards and may be used to sync usage data across devices.</Text>
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
</View>
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
)
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
}
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
return (
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
<View style={firstRunStyle.container}>
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
{content}
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
</View>
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
);
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
}
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
}
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|||||||
|
export default EmailCollectPage;
|
||||||
No aliases (or resolves) for paths? No aliases (or resolves) for paths?
*Remove the long relative paths
Don’t need a full constructor (see comment above) Don’t need a full constructor (see comment above)
This is a legacy lifecycle method, should use This is a legacy lifecycle method, should use `getDerivedStateFromProps`
|
|
@ -1,6 +1,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Lbry } from 'lbry-redux';
|
import { Lbry } from 'lbry-redux';
|
||||||
import {
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
AsyncStorage,
|
||||||
Linking,
|
Linking,
|
||||||
NativeModules,
|
NativeModules,
|
||||||
Text,
|
Text,
|
||||||
|
@ -9,19 +11,26 @@ import {
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { NavigationActions } from 'react-navigation';
|
import { NavigationActions } from 'react-navigation';
|
||||||
import Colors from '../../styles/colors';
|
import Colors from '../../styles/colors';
|
||||||
|
import Constants from '../../constants';
|
||||||
import WelcomePage from './internal/welcome-page';
|
import WelcomePage from './internal/welcome-page';
|
||||||
|
import EmailCollectPage from './internal/email-collect-page';
|
||||||
|
//import EmailVerifyPage from '../internal/email-verify-page';
|
||||||
import firstRunStyle from '../../styles/firstRun';
|
import firstRunStyle from '../../styles/firstRun';
|
||||||
|
|
||||||
class FirstRunScreen extends React.PureComponent {
|
class FirstRunScreen extends React.PureComponent {
|
||||||
static pages = ['welcome'];
|
static pages = [
|
||||||
|
'welcome',
|
||||||
|
'email-collect'
|
||||||
|
];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.state = {
|
this.state = {
|
||||||
currentPage: null,
|
currentPage: null,
|
||||||
launchUrl: null,
|
launchUrl: null,
|
||||||
isFirstRun: false
|
isFirstRun: false,
|
||||||
}
|
showBottomContainer: true
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -60,34 +69,92 @@ class FirstRunScreen extends React.PureComponent {
|
||||||
|
|
||||||
handleContinuePressed = () => {
|
handleContinuePressed = () => {
|
||||||
const pageIndex = FirstRunScreen.pages.indexOf(this.state.currentPage);
|
const pageIndex = FirstRunScreen.pages.indexOf(this.state.currentPage);
|
||||||
if (pageIndex === (FirstRunScreen.pages.length - 1)) {
|
if (this.state.currentPage !== 'email-collect' &&
|
||||||
// Final page. Let the app know that first run experience is completed.
|
pageIndex === (FirstRunScreen.pages.length - 1)) {
|
||||||
if (NativeModules.FirstRun) {
|
this.closeFinalPage();
|
||||||
NativeModules.FirstRun.firstRunCompleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Navigate to the splash screen
|
|
||||||
this.launchSplashScreen();
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: Page transition animation?
|
// TODO: Actions and page verification for specific pages
|
||||||
this.state.currentPage = FirstRunScreen.pages[pageIndex + 1];
|
if (this.state.currentPage === 'email-collect') {
|
||||||
|
// handle email collect
|
||||||
|
this.handleEmailCollectPageContinue();
|
||||||
|
} else {
|
||||||
|
this.showNextPage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleEmailCollectPageContinue() {
|
||||||
|
const { notify, addUserEmail } = this.props;
|
||||||
|
// validate the email
|
||||||
|
AsyncStorage.getItem(Constants.KEY_FIRST_RUN_EMAIL).then(email => {
|
||||||
|
if (!email || email.trim().length === 0 || email.indexOf('@') === -1) {
|
||||||
|
return notify({
|
||||||
|
message: 'Please provide a valid email address to continue.',
|
||||||
|
displayType: ['toast'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addUserEmail(email);
|
||||||
|
|
||||||
|
// treat as the final page
|
||||||
|
this.closeFinalPage();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Legacy method, see comment above Legacy method, see comment above
|
|||||||
|
showNextPage() {
|
||||||
|
const pageIndex = FirstRunScreen.pages.indexOf(this.state.currentPage);
|
||||||
|
const nextPage = FirstRunScreen.pages[pageIndex + 1];
|
||||||
|
this.setState({ currentPage: nextPage });
|
||||||
|
if (nextPage === 'email-collect') {
|
||||||
|
// do not show the buttons (because we're waiting to get things ready)
|
||||||
|
this.setState({ showBottomContainer: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closeFinalPage() {
|
||||||
|
// Final page. Let the app know that first run experience is completed.
|
||||||
|
if (NativeModules.FirstRun) {
|
||||||
|
NativeModules.FirstRun.firstRunCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigate to the splash screen
|
||||||
|
this.launchSplashScreen();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const {
|
||||||
|
authenticating,
|
||||||
|
authToken,
|
||||||
|
generateAuthToken,
|
||||||
|
emailNewErrorMessage,
|
||||||
|
emailNewPending,
|
||||||
|
emailToVerify
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
let page = null;
|
let page = null;
|
||||||
if (this.state.currentPage === 'welcome') {
|
if (this.state.currentPage === 'welcome') {
|
||||||
// show welcome page
|
// show welcome page
|
||||||
page = (<WelcomePage />);
|
page = (<WelcomePage />);
|
||||||
|
} else if (this.state.currentPage === 'email-collect') {
|
||||||
|
page = (<EmailCollectPage authenticating={authenticating}
|
||||||
|
authToken={authToken}
|
||||||
|
generateAuthToken={generateAuthToken}
|
||||||
|
onEmailViewLayout={() => this.setState({ showBottomContainer: true })} />);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={firstRunStyle.screenContainer}>
|
<View style={firstRunStyle.screenContainer}>
|
||||||
{page}
|
{page}
|
||||||
{this.state.currentPage &&
|
{this.state.currentPage && this.state.showBottomContainer &&
|
||||||
<TouchableOpacity style={firstRunStyle.button} onPress={this.handleContinuePressed}>
|
<View style={firstRunStyle.bottomContainer}>
|
||||||
<Text style={firstRunStyle.buttonText}>Continue</Text>
|
{emailNewPending &&
|
||||||
</TouchableOpacity>}
|
<ActivityIndicator size="small" color={Colors.White} style={firstRunStyle.pageWaiting} />}
|
||||||
|
|
||||||
|
{!emailNewPending &&
|
||||||
|
<TouchableOpacity style={firstRunStyle.button} onPress={this.handleContinuePressed}>
|
||||||
|
<Text style={firstRunStyle.buttonText}>Continue</Text>
|
||||||
|
</TouchableOpacity>}
|
||||||
|
</View>}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doBalanceSubscribe } from 'lbry-redux';
|
import { doBalanceSubscribe, doNotify } from 'lbry-redux';
|
||||||
|
import { doAuthenticate, doUserEmailVerify, doUserEmailVerifyFailure, selectUser } from 'lbryinc';
|
||||||
import SplashScreen from './view';
|
import SplashScreen from './view';
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const select = state => ({
|
||||||
balanceSubscribe: () => dispatch(doBalanceSubscribe())
|
user: selectUser(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(null, perform)(SplashScreen);
|
const perform = dispatch => ({
|
||||||
|
authenticate: (appVersion, deviceId) => dispatch(doAuthenticate(appVersion, deviceId)),
|
||||||
|
balanceSubscribe: () => dispatch(doBalanceSubscribe()),
|
||||||
|
notify: data => dispatch(doNotify(data)),
|
||||||
|
verifyUserEmail: (token, recaptcha) => dispatch(doUserEmailVerify(token, recaptcha)),
|
||||||
|
verifyUserEmailFailure: error => dispatch(doUserEmailVerifyFailure(error)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, perform)(SplashScreen);
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
View
|
View
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { NavigationActions } from 'react-navigation';
|
import { NavigationActions } from 'react-navigation';
|
||||||
|
import { decode as atob } from 'base-64';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Colors from '../../styles/colors';
|
import Colors from '../../styles/colors';
|
||||||
import splashStyle from '../../styles/splash';
|
import splashStyle from '../../styles/splash';
|
||||||
|
@ -52,6 +53,49 @@ class SplashScreen extends React.PureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUpdate(nextProps) {
|
||||||
|
const { navigation, verifyUserEmail, verifyUserEmailFailure } = this.props;
|
||||||
|
const { user } = nextProps;
|
||||||
|
if (user && user.id) {
|
||||||
|
// user is authenticated, navigate to the main view
|
||||||
|
const resetAction = NavigationActions.reset({
|
||||||
|
index: 0,
|
||||||
|
actions: [
|
||||||
|
NavigationActions.navigate({ routeName: 'Main'})
|
||||||
|
]
|
||||||
|
});
|
||||||
|
navigation.dispatch(resetAction);
|
||||||
|
|
||||||
|
const launchUrl = navigation.state.params.launchUrl || this.state.launchUrl;
|
||||||
|
if (launchUrl) {
|
||||||
|
if (launchUrl.startsWith('lbry://?verify=')) {
|
||||||
|
let verification = {};
|
||||||
|
try {
|
||||||
|
verification = JSON.parse(atob(launchUrl.substring(15)));
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
if (verification.token && verification.recaptcha) {
|
||||||
|
try {
|
||||||
|
verifyUserEmail(verification.token, verification.recaptcha);
|
||||||
|
} catch (error) {
|
||||||
|
const message = 'Invalid Verification Token';
|
||||||
|
verifyUserEmailFailure(message);
|
||||||
|
notify({ message, displayType: ['toast'] });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notify({
|
||||||
|
message: 'Invalid Verification URI',
|
||||||
|
displayType: ['toast'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigation.navigate({ routeName: 'File', key: launchUrl, params: { uri: launchUrl } });
|
||||||
|
}
|
||||||
Legacy lifecycle method, see other comments about this Legacy lifecycle method, see other comments about this
|
|||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_updateStatusCallback(status) {
|
_updateStatusCallback(status) {
|
||||||
const startupStatus = status.startup_status;
|
const startupStatus = status.startup_status;
|
||||||
// At the minimum, wallet should be started and blocks_behind equal to 0 before calling resolve
|
// At the minimum, wallet should be started and blocks_behind equal to 0 before calling resolve
|
||||||
|
@ -70,21 +114,15 @@ class SplashScreen extends React.PureComponent {
|
||||||
|
|
||||||
Lbry.resolve({ uri: 'lbry://one' }).then(() => {
|
Lbry.resolve({ uri: 'lbry://one' }).then(() => {
|
||||||
// Leave the splash screen
|
// Leave the splash screen
|
||||||
const { balanceSubscribe, navigation } = this.props;
|
const {
|
||||||
|
authenticate,
|
||||||
|
balanceSubscribe,
|
||||||
|
navigation,
|
||||||
|
notify
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
authenticate(null);
|
||||||
balanceSubscribe();
|
balanceSubscribe();
|
||||||
|
|
||||||
const resetAction = NavigationActions.reset({
|
|
||||||
index: 0,
|
|
||||||
actions: [
|
|
||||||
NavigationActions.navigate({ routeName: 'Main'})
|
|
||||||
]
|
|
||||||
});
|
|
||||||
navigation.dispatch(resetAction);
|
|
||||||
|
|
||||||
const launchUrl = navigation.state.params.launchUrl || this.state.launchUrl;
|
|
||||||
if (launchUrl) {
|
|
||||||
navigation.navigate({ routeName: 'File', key: launchUrl, params: { uri: launchUrl } });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,3 +9,4 @@ export function doSetClientSetting(key, value) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import { AsyncStorage } from 'react-native';
|
|
||||||
import { ACTIONS } from 'lbry-redux';
|
import { ACTIONS } from 'lbry-redux';
|
||||||
|
|
||||||
|
|
||||||
const reducers = {};
|
const reducers = {};
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
clientSettings: {}
|
clientSettings: {}
|
||||||
|
|
|
@ -28,16 +28,48 @@ const firstRunStyle = StyleSheet.create({
|
||||||
marginBottom: 20,
|
marginBottom: 20,
|
||||||
color: Colors.White
|
color: Colors.White
|
||||||
},
|
},
|
||||||
button: {
|
infoParagraph: {
|
||||||
|
fontFamily: 'Metropolis-Regular',
|
||||||
|
fontSize: 14,
|
||||||
|
lineHeight: 20,
|
||||||
|
marginLeft: 32,
|
||||||
|
marginRight: 32,
|
||||||
|
marginBottom: 20,
|
||||||
|
color: Colors.White
|
||||||
|
},
|
||||||
|
emailInput: {
|
||||||
|
fontFamily: 'Metropolis-Regular',
|
||||||
|
fontSize: 24,
|
||||||
|
lineHeight: 24,
|
||||||
|
marginLeft: 32,
|
||||||
|
marginRight: 32,
|
||||||
|
marginBottom: 20,
|
||||||
|
textAlign: 'center'
|
||||||
|
},
|
||||||
|
leftButton: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
marginLeft: 32,
|
||||||
|
marginRight: 32
|
||||||
|
},
|
||||||
|
bottomContainer: {
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
|
button: {
|
||||||
alignSelf: 'flex-end',
|
alignSelf: 'flex-end',
|
||||||
marginLeft: 32,
|
marginLeft: 32,
|
||||||
marginRight: 32
|
marginRight: 32
|
||||||
},
|
},
|
||||||
buttonText: {
|
buttonText: {
|
||||||
fontFamily: 'Metropolis-Regular',
|
fontFamily: 'Metropolis-Regular',
|
||||||
fontSize: 28,
|
fontSize: 24,
|
||||||
color: Colors.White
|
color: Colors.White
|
||||||
|
},
|
||||||
|
waiting: {
|
||||||
|
marginBottom: 24
|
||||||
|
},
|
||||||
|
pageWaiting: {
|
||||||
|
alignSelf: 'center'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
You can define this without a constructor
https://hackernoon.com/the-constructor-is-dead-long-live-the-constructor-c10871bea599