finish phone number verification and styling

This commit is contained in:
Akinwale Ariwodola 2019-05-10 09:14:50 +01:00
parent 2c9c822784
commit a3bbe8a419
6 changed files with 331 additions and 150 deletions

View file

@ -25,7 +25,7 @@ class RewardsPage extends React.PureComponent {
isIdentityVerified: false,
isRewardApproved: false,
verifyRequestStarted: false,
revealVerification: false
revealVerification: true
};
scrollView = null;
@ -71,23 +71,12 @@ class RewardsPage extends React.PureComponent {
return null;
}
if (!this.state.isEmailVerified || !this.state.isIdentityVerified) {
return (
<View style={[rewardStyle.card, rewardStyle.verification]}>
<Text style={rewardStyle.title}>Humans Only</Text>
<Text style={rewardStyle.text}>Rewards are for human beings only. You'll have to prove you're one of us before you can claim any rewards.</Text>
{!this.state.isEmailVerified && <EmailRewardSubcard />}
{this.state.isEmailVerified && !this.state.isIdentityVerified && <PhoneNumberRewardSubcard />}
</View>
);
}
if (this.state.isEmailVerified && this.state.isIdentityVerified && !this.state.isRewardApproved) {
return (
<View style={[rewardStyle.card, rewardStyle.verification]}>
<Text style={rewardStyle.title}>Manual Reward Verification</Text>
<Text style={rewardStyle.text}>
You need to be manually verified before you can start claiming rewards. Please request to be verified on the <Link style={rewardStyle.textLink} href="https://discordapp.com/invite/Z3bERWA" text="LBRY Discord server" />.
You need to be manually verified before you can start claiming rewards. Please request to be verified on the <Link style={rewardStyle.greenLink} href="https://discordapp.com/invite/Z3bERWA" text="LBRY Discord server" />.
</Text>
</View>
);
@ -154,15 +143,13 @@ class RewardsPage extends React.PureComponent {
return (
<View style={rewardStyle.container}>
<UriBar navigation={navigation} />
{!this.state.isRewardApproved && <RewardEnrolment navigation={navigation} />}
{(!this.state.isEmailVerified || !this.state.isIdentityVerified) && <RewardEnrolment navigation={navigation} />}
{this.state.isRewardApproved && <ScrollView
{(this.state.isEmailVerified && this.state.isIdentityVerified) && <ScrollView
ref={ref => this.scrollView = ref}
keyboardShouldPersistTaps={'handled'}
style={rewardStyle.scrollContainer}
contentContainerStyle={rewardStyle.scrollContentContainer}>
<RewardSummary navigation={navigation} showVerification={this.showVerification} />
{this.state.revealVerification && this.renderVerification()}
{this.renderUnclaimedRewards()}
{this.renderClaimedRewards()}

View file

@ -3,10 +3,18 @@ import { doToast } from 'lbry-redux';
import {
doUserEmailNew,
doUserEmailToVerify,
doUserResendVerificationEmail,
doUserPhoneNew,
doUserPhoneVerify,
selectPhoneNewErrorMessage,
selectPhoneNewIsPending,
selectPhoneToVerify,
selectPhoneVerifyIsPending,
selectPhoneVerifyErrorMessage,
selectEmailNewErrorMessage,
selectEmailNewIsPending,
selectEmailToVerify,
doUserResendVerificationEmail,
selectUser,
} from 'lbryinc';
import Verification from './view';
@ -14,10 +22,18 @@ const select = (state) => ({
emailToVerify: selectEmailToVerify(state),
emailNewErrorMessage: selectEmailNewErrorMessage(state),
emailNewPending: selectEmailNewIsPending(state),
user: selectUser(state),
phoneVerifyErrorMessage: selectPhoneVerifyErrorMessage(state),
phoneVerifyIsPending: selectPhoneVerifyIsPending(state),
phone: selectPhoneToVerify(state),
phoneNewErrorMessage: selectPhoneNewErrorMessage(state),
phoneNewIsPending: selectPhoneNewIsPending(state),
});
const perform = dispatch => ({
addUserEmail: email => dispatch(doUserEmailNew(email)),
addUserPhone: (phone, country_code) => dispatch(doUserPhoneNew(phone, country_code)),
verifyPhone: (verificationCode) => dispatch(doUserPhoneVerify(verificationCode)),
notify: data => dispatch(doToast(data)),
setEmailToVerify: email => dispatch(doUserEmailToVerify(email)),
resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email))

View file

@ -116,7 +116,7 @@ class EmailVerifyPage extends React.PureComponent {
{(Constants.PHASE_VERIFICATION === this.state.phase) &&
<View>
<Text style={firstRunStyle.paragraph}>An email has been sent to {this.state.email}.</Text>
<Text style={firstRunStyle.paragraph}>An email has been sent to {this.state.email}. Please follow the instructions in the message to verify your email address.</Text>
<View style={rewardStyle.buttonContainer}>
<Button style={rewardStyle.verificationButton} theme={"light"} text={"Resend"} onPress={this.onResendPressed} />

View file

@ -0,0 +1,235 @@
// @flow
import React from 'react';
import {
ActivityIndicator,
DeviceEventEmitter,
NativeModules,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View
} from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import Button from 'component/button';
import Colors from 'styles/colors';
import Constants from 'constants';
import CountryPicker from 'react-native-country-picker-modal';
import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link';
import PhoneInput from 'react-native-phone-input';
import firstRunStyle from 'styles/firstRun';
import rewardStyle from 'styles/reward';
class PhoneVerifyPage extends React.PureComponent {
phoneInput = null;
picker = null;
constructor(props) {
super(props);
this.state = {
canReceiveSms: false,
cca2: 'US',
codeVerifyStarted: false,
codeVerifySuccessful: false,
countryCode: null,
newPhoneAdded: false,
number: null,
phoneVerifyFailed: false,
verificationCode: null,
phase: Constants.PHASE_COLLECTION
};
}
componentDidMount() {
const { phone } = this.props;
if (phone && String(phone).trim().length > 0) {
this.setState({ newPhoneAdded: true, phase: Constants.PHASE_VERIFICATION });
}
}
componentDidUpdate(prevProps) {
const {
phoneVerifyIsPending,
phoneVerifyErrorMessage,
notify,
phoneNewErrorMessage,
phoneNewIsPending,
onPhoneVerifySuccessful
} = this.props;
if (!phoneNewIsPending && (phoneNewIsPending !== prevProps.phoneNewIsPending)) {
if (phoneNewErrorMessage) {
notify({ message: String(phoneNewErrorMessage) });
this.setState({ phoneVerifyFailed: true });
} else {
this.setState({ newPhoneAdded: true, phase: Constants.PHASE_VERIFICATION, phoneVerifyFailed: false });
}
}
if (!phoneVerifyIsPending && (phoneVerifyIsPending !== prevProps.phoneVerifyIsPending)) {
if (phoneVerifyErrorMessage) {
notify({ message: String(phoneVerifyErrorMessage) });
this.setState({ codeVerifyStarted: false, phoneVerifyFailed: true });
} else {
notify({ message: 'Your phone number was successfully verified.' });
this.setState({ codeVerifySuccessful: true, phoneVerifyFailed: false });
if (onPhoneVerifySuccessful) {
onPhoneVerifySuccessful();
}
}
}
}
onEditPressed = () => {
this.setState({ newPhoneAdded: false, phase: Constants.PHASE_COLLECTION, phoneVerifyFailed: false });
}
receiveVerificationCode = (evt) => {
if (!this.state.newPhoneAdded || this.state.codeVerifySuccessful) {
return;
}
const { verifyPhone } = this.props;
this.setState({ codeVerifyStarted: true });
verifyPhone(evt.code);
}
onSendTextPressed = () => {
const { addUserPhone, notify } = this.props;
if (!this.phoneInput.isValidNumber()) {
return notify({
message: 'Please provide a valid telephone number.',
});
}
this.setState({ phoneVerifyFailed: false });
const countryCode = this.phoneInput.getCountryCode();
const number = this.phoneInput.getValue().replace('+' + countryCode, '');
this.setState({ countryCode, number });
addUserPhone(number, countryCode);
}
onVerifyPressed = () => {
if (this.state.codeVerifyStarted) {
return;
}
const { verifyPhone } = this.props;
this.setState({ codeVerifyStarted: true, phoneVerifyFailed: false });
verifyPhone(this.state.verificationCode);
}
onPressFlag = () => {
if (this.picker) {
this.picker.openModal();
}
}
selectCountry(country) {
this.phoneInput.selectCountry(country.cca2.toLowerCase());
this.setState({ cca2: country.cca2 });
}
handleChangeText = (text) => {
this.setState({ verificationCode: text });
};
render() {
const {
phoneVerifyIsPending,
phoneVerifyErrorMessage,
phone,
phoneErrorMessage,
phoneNewIsPending
} = this.props;
return (
<View style={firstRunStyle.container}>
<Text style={rewardStyle.verificationTitle}>{this.state.phase === Constants.PHASE_VERIFICATION ? 'Verify ' : '' }Phone Number</Text>
<View style={rewardStyle.phoneVerificationContainer}>
{this.state.phase == Constants.PHASE_COLLECTION &&
<View>
<Text style={[rewardStyle.bottomMarginMedium, firstRunStyle.paragraph]}>Please provide a phone number to prevent fraud.</Text>
<PhoneInput
ref={(ref) => { this.phoneInput = ref; }}
style={StyleSheet.flatten(rewardStyle.phoneInput)}
textProps={{ placeholder: '(phone number)' }}
textStyle={StyleSheet.flatten(rewardStyle.phoneInputText)}
onPressFlag={this.onPressFlag} />
<View style={rewardStyle.buttonContainer}>
{!phoneNewIsPending &&
<Button
style={[rewardStyle.verificationButton, rewardStyle.topMarginMedium]}
theme={"light"}
text={"Send verification text"}
onPress={this.onSendTextPressed} />}
{phoneNewIsPending &&
<ActivityIndicator
style={[rewardStyle.loading, rewardStyle.topMarginMedium]}
size="small"
color={Colors.White} />}
</View>
</View>}
{this.state.phase === Constants.PHASE_VERIFICATION &&
<View>
{!phoneVerifyIsPending && !this.codeVerifyStarted &&
<View>
<Text style={[rewardStyle.bottomMarginSmall, firstRunStyle.paragraph]}>
Please enter the verification code sent to {phone}.
</Text>
<TextInput
style={rewardStyle.verificationCodeInput}
keyboardType="numeric"
placeholder="0000"
underlineColorAndroid="transparent"
value={this.state.verificationCode}
onChangeText={text => this.handleChangeText(text)}
/>
<View style={rewardStyle.buttonContainer}>
<Button
style={[rewardStyle.verificationButton, rewardStyle.topMarginSmall]}
theme={"light"}
text={"Verify"}
onPress={this.onVerifyPressed} />
<Link style={rewardStyle.verificationLink} text={"Edit"} onPress={this.onEditPressed} />
</View>
</View>
}
{phoneVerifyIsPending &&
<View>
<Text style={firstRunStyle.paragraph}>Verifying your phone number...</Text>
<ActivityIndicator
color={Colors.White}
size="small"
style={[rewardStyle.loading, rewardStyle.topMarginMedium, rewardStyle.leftRightMargin]} />
</View>}
</View>
}
{this.state.phoneVerifyFailed &&
<View style={rewardStyle.failureFootnote}>
<Text style={rewardStyle.paragraphText}>
Sorry, we were unable to verify your phone number. Please go to <Link style={rewardStyle.textLink} href="http://chat.lbry.com" text="chat.lbry.com" /> for manual verification if this keeps happening.
</Text>
</View>}
</View>
<CountryPicker
ref={(picker) => { this.picker = picker; }}
cca2={this.state.cca2}
filterable={true}
onChange={value => this.selectCountry(value)}
showCallingCode={true}
translation="eng">
<View />
</CountryPicker>
</View>
);
}
};
export default PhoneVerifyPage;

View file

@ -13,6 +13,7 @@ import AsyncStorage from '@react-native-community/async-storage';
import Colors from 'styles/colors';
import Constants from 'constants';
import EmailVerifyPage from './internal/email-verify-page';
import PhoneVerifyPage from './internal/phone-verify-page';
import firstRunStyle from 'styles/firstRun';
class VerificationScreen extends React.PureComponent {
@ -24,128 +25,41 @@ class VerificationScreen extends React.PureComponent {
showSkip: false,
skipAccountConfirmed: false,
showBottomContainer: true,
walletPassword: null
walletPassword: null,
isEmailVerified: false,
isIdentityVerified: false
};
componentDidMount() {
const { user } = this.props;
this.checkVerificationStatus(user);
}
checkVerificationStatus = (user) => {
const { navigation } = this.props;
this.setState({ currentPage: 'emailVerify' });
this.setState({
isEmailVerified: (user && user.primary_email && user.has_verified_email),
isIdentityVerified: (user && user.is_identity_verified)
}, () => {
if (!this.state.isEmailVerified) {
this.setState({ currentPage: 'emailVerify' });
}
if (this.state.isEmailVerified && !this.state.isIdentityVerified) {
this.setState({ currentPage: 'phoneVerify' });
}
if (this.state.isEmailVerified && this.state.isIdentityVerified) {
// verification steps already completed
// simply navigate back to the rewards page
navigation.goBack();
}
});
}
componentWillReceiveProps(nextProps) {
const { emailNewErrorMessage, emailNewPending } = nextProps;
const { notify } = this.props;
/*if (this.state.emailSubmitted && !emailNewPending) {
this.setState({ emailSubmitted: false });
if (emailNewErrorMessage) {
notify ({ message: String(emailNewErrorMessage), isError: true });
} else {
// Request successful. Navigate to next page (wallet).
this.showNextPage();
}
}*/
}
handleLeftButtonPressed = () => {
/*// Go to setup account page when "Setup account" is pressed
if (Constants.FIRST_RUN_PAGE_SKIP_ACCOUNT === this.state.currentPage) {
return this.showPage(Constants.FIRST_RUN_PAGE_EMAIL_COLLECT);
}
// Go to skip account page when "No, thanks" is pressed
if (Constants.FIRST_RUN_PAGE_EMAIL_COLLECT === this.state.currentPage) {
this.showPage(Constants.FIRST_RUN_PAGE_SKIP_ACCOUNT);
}*/
}
handleContinuePressed = () => {
/*const { notify } = this.props;
const pageIndex = FirstRunScreen.pages.indexOf(this.state.currentPage);
if (Constants.FIRST_RUN_PAGE_WALLET === this.state.currentPage) {
if (!this.state.walletPassword || this.state.walletPassword.trim().length < 6) {
return notify({ message: 'Your wallet password should be at least 6 characters long' });
}
this.closeFinalPage();
return;
}
if (Constants.FIRST_RUN_PAGE_SKIP_ACCOUNT === this.state.currentPage && !this.state.skipAccountConfirmed) {
notify({ message: 'Please confirm that you want to use LBRY without creating an account.' });
return;
}
if (Constants.FIRST_RUN_PAGE_EMAIL_COLLECT !== this.state.currentPage && pageIndex === (FirstRunScreen.pages.length - 1)) {
this.closeFinalPage();
} else {
// TODO: Actions and page verification for specific pages
if (Constants.FIRST_RUN_PAGE_EMAIL_COLLECT === this.state.currentPage) {
// handle email collect
this.handleEmailCollectPageContinue();
} else {
this.showNextPage();
}
}*/
}
handleEmailCollectPageContinue() {
/*const { notify, addUserEmail } = this.props;
AsyncStorage.getItem(Constants.KEY_FIRST_RUN_EMAIL).then(email => {
// validate the email
if (!email || email.indexOf('@') === -1) {
return notify({
message: 'Please provide a valid email address to continue.',
});
}
addUserEmail(email);
this.setState({ emailSubmitted: true });
});*/
}
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 });
}
}
showPage(pageName) {
const pageIndex = FirstRunScreen.pages.indexOf(pageName);
if (pageIndex > -1) {
this.setState({ currentPage: pageName });
}
}
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();
}
onEmailChanged = (email) => {
if (Constants.FIRST_RUN_PAGE_EMAIL_COLLECT == this.state.currentPage) {
this.setState({ showSkip: (!email || email.trim().length === 0) });
} else {
this.setState({ showSkip: false });
}
}
onEmailViewLayout = () => {
this.setState({ showBottomContainer: true });
AsyncStorage.getItem('firstRunEmail').then(email => {
this.setState({ showSkip: !email || email.trim().length === 0 });
});
const { user } = nextProps;
this.checkVerificationStatus(user);
}
onCloseButtonPressed = () => {
@ -153,18 +67,6 @@ class VerificationScreen extends React.PureComponent {
navigation.goBack();
}
onWalletPasswordChanged = (password) => {
this.setState({ walletPassword: password });
}
onWalletViewLayout = () => {
this.setState({ showBottomContainer: true });
}
onSkipSwitchChanged = (checked) => {
this.setState({ skipAccountConfirmed: checked });
}
render() {
const {
addUserEmail,
@ -172,7 +74,14 @@ class VerificationScreen extends React.PureComponent {
emailNewPending,
emailToVerify,
notify,
resendVerificationEmail
addUserPhone,
phone,
phoneVerifyIsPending,
phoneVerifyErrorMessage,
phoneNewIsPending,
phoneNewErrorMessage,
resendVerificationEmail,
verifyPhone
} = this.props;
let page = null;
@ -189,6 +98,20 @@ class VerificationScreen extends React.PureComponent {
/>
);
break;
case 'phoneVerify':
page = (
<PhoneVerifyPage
addUserPhone={addUserPhone}
phone={phone}
phoneVerifyIsPending={phoneVerifyIsPending}
phoneVerifyErrorMessage={phoneVerifyErrorMessage}
phoneNewIsPending={phoneNewIsPending}
phoneNewErrorMessage={phoneNewErrorMessage}
notify={notify}
verifyPhone={verifyPhone}
/>
);
break;
}
return (

View file

@ -119,12 +119,19 @@ const rewardStyle = StyleSheet.create({
bottomMarginLarge: {
marginBottom: 24
},
leftRightMargin: {
marginLeft: 32,
marginRight: 32
},
link: {
color: Colors.LbryGreen,
fontFamily: 'Inter-UI-Regular',
fontSize: 14,
},
textLink: {
color: Colors.White
},
greenLink: {
color: Colors.LbryGreen
},
leftCol: {
@ -196,12 +203,14 @@ const rewardStyle = StyleSheet.create({
paddingRight: 4
},
phoneInput: {
marginLeft: 8
marginLeft: 32,
marginRight: 32
},
phoneInputText: {
fontFamily: 'Inter-UI-Regular',
fontSize: 16,
letterSpacing: 1.3
letterSpacing: 1.3,
color: Colors.White
},
verifyingText: {
fontFamily: 'Inter-UI-Regular',
@ -211,8 +220,11 @@ const rewardStyle = StyleSheet.create({
},
verificationCodeInput: {
fontFamily: 'Inter-UI-Regular',
color: Colors.White,
fontSize: 24,
letterSpacing: 12
letterSpacing: 12,
marginLeft: 32,
marginRight: 32
},
loading: {
alignSelf: 'flex-start'
@ -251,7 +263,9 @@ const rewardStyle = StyleSheet.create({
backgroundColor: Colors.LbryGreen
},
failureFootnote: {
marginTop: 12
marginTop: 32,
marginLeft: 32,
marginRight: 32
},
buttonContainer: {
flexDirection: 'row',
@ -278,6 +292,12 @@ const rewardStyle = StyleSheet.create({
verificationLink: {
color: Colors.White,
fontSize: 14
},
paragraphText: {
fontFamily: 'Inter-UI-Regular',
color: Colors.White,
fontSize: 12,
lineHeight: 16
}
});