1. 登录,邮箱/手机号账号注册(账号注册未测试)

This commit is contained in:
xuwenyang 2019-06-06 20:56:35 +08:00
parent 487aecdf96
commit d137b41c74
6 changed files with 439 additions and 66 deletions

154
App.js
View file

@ -27,7 +27,8 @@ import BottomNav from './src/nav/bottomNav';
import Loading from './src/component/loading'; import Loading from './src/component/loading';
import LoginForm from './src/component/loginForm'; import LoginForm from './src/component/loginForm';
import RegisterForm from './src/component/registerForm'; import RegisterEmailForm from './src/component/registerEmailForm';
import RegisterMobileForm from './src/component/registerMobileForm';
export default class App extends Component { export default class App extends Component {
@ -36,26 +37,53 @@ export default class App extends Component {
super(props); super(props);
this.state = ({ this.state = ({
isLoginPage: true, page: App.pageLogin,
isLoading: false
isLoading: false,
paddingAnim: new Animated.Value(100)
}); });
} }
componentWillMount () {
this.keyboardDidShowListener =
Keyboard.addListener(Api.IS_IOS ? 'keyboardWillShow' : 'keyboardDidShow', this._keyboardDidShow);
this.keyboardDidHideListener =
Keyboard.addListener(Api.IS_IOS ? 'keyboardWillHide' : 'keyboardDidHide', this._keyboardDidHide);
}
componentWillUnmount () {
this.keyboardDidShowListener.remove();
this.keyboardDidHideListener.remove();
}
_keyboardDidShow = () => {
Animated.timing(
this.state.paddingAnim,
{
toValue: Api.IS_IOS ? 65 : 35,
duration: 250
}
).start();
};
_keyboardDidHide = () => {
InteractionManager.runAfterInteractions(() => {
Animated.timing(
this.state.paddingAnim,
{toValue: 100, duration: 250 }
).start();
});
};
static pageLogin = 1;
static pageRegisterMobile = 2;
static pageRegisterEmail = 3;
_setLoading(value) { _setLoading(value) {
this.setState({isLoading: value}); this.setState({isLoading: value});
} }
_toWeb() {
Linking.openURL("https://timepill.net/home/forgot_password");
}
_switchForm() {
LayoutAnimation.easeInEaseOut();
this.setState({
isLoginPage: !this.state.isLoginPage
});
}
_onSucc() { _onSucc() {
Api.getSplashByStore() Api.getSplashByStore()
.then(splash => { .then(splash => {
@ -68,33 +96,96 @@ export default class App extends Component {
return ( return (
<View style={localStyle.wrap}> <View style={localStyle.wrap}>
<Loading visible={this.state.isLoading}></Loading> <Loading visible={this.state.isLoading}></Loading>
<Animated.View style={localStyle.content}> <Animated.View style={[localStyle.content, {paddingTop: this.state.paddingAnim}]}>
{this.state.isLoginPage {this.renderForm()}
? (<LoginForm
setLoading={this._setLoading.bind(this)}
onLoginSucc={this._onSucc.bind(this)}
></LoginForm>)
: (<RegisterForm
setLoading={this._setLoading.bind(this)}
onRegisterSucc={this._onSucc.bind(this)}
></RegisterForm>)}
<View style={localStyle.bottom}> <View style={localStyle.bottom}>
<TouchableOpacity onPress={this._switchForm.bind(this)}> <TouchableOpacity onPress={() => {
LayoutAnimation.easeInEaseOut();
if(this.state.page == App.pageLogin) {
this.setState({page: App.pageRegisterMobile});
} else {
this.setState({page: App.pageLogin});
}
}}>
<Text style={localStyle.bottomText}> <Text style={localStyle.bottomText}>
{this.state.isLoginPage ? '没有账号?注册一个' : '已有账号?马上登录'} {this.state.page == App.pageLogin ? '没有账号?注册一个' : '已有账号?马上登录'}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity onPress={this._toWeb.bind(this)}>
{this.renderActionLink()}
</View>
</Animated.View>
</View>
);
}
renderForm() {
if(this.state.page == App.pageLogin) {
return (
<LoginForm
setLoading={this._setLoading.bind(this)}
onLoginSucc={this._onSucc.bind(this)}
></LoginForm>
);
} else if(this.state.page == App.pageRegisterMobile) {
return (
<RegisterMobileForm
setLoading={this._setLoading.bind(this)}
onRegisterSucc={this._onSucc.bind(this)}
></RegisterMobileForm>
);
} else if(this.state.page == App.pageRegisterEmail) {
return (
<RegisterEmailForm
setLoading={this._setLoading.bind(this)}
onRegisterSucc={this._onSucc.bind(this)}
></RegisterEmailForm>
);
}
return null;
}
renderActionLink() {
if(this.state.page == App.pageLogin) {
return (
<TouchableOpacity onPress={() => {
Linking.openURL("https://timepill.net/home/forgot_password");
}}>
<Text style={localStyle.bottomText}> <Text style={localStyle.bottomText}>
忘记密码 忘记密码
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</View>
</Animated.View>
</View>
); );
} else if(this.state.page == App.pageRegisterMobile) {
return (
<TouchableOpacity onPress={() => {
LayoutAnimation.easeInEaseOut();
this.setState({page: App.pageRegisterEmail});
}}>
<Text style={localStyle.bottomText}>
邮箱注册
</Text>
</TouchableOpacity>
);
} else if(this.state.page == App.pageRegisterEmail){
return (
<TouchableOpacity onPress={() => {
LayoutAnimation.easeInEaseOut();
this.setState({page: App.pageRegisterMobile});
}}>
<Text style={localStyle.bottomText}>
手机注册
</Text>
</TouchableOpacity>
);
}
return null;
} }
} }
@ -105,7 +196,6 @@ const localStyle = StyleSheet.create({
}, },
content: { content: {
flex: 1, flex: 1,
paddingTop: '30%',
paddingHorizontal: 15 paddingHorizontal: 15
}, },
bottom: { bottom: {

View file

@ -15,7 +15,7 @@ import BottomNav from './src/nav/bottomNav';
// for debug // for debug
// console.disableYellowBox = true; console.disableYellowBox = true;
Navigation.registerComponent('Timepill', () => App); Navigation.registerComponent('Timepill', () => App);

View file

@ -3,9 +3,9 @@ import {Platform, StyleSheet, Text, View, InteractionManager, Alert} from 'react
import {FormInput, Button} from "react-native-elements"; import {FormInput, Button} from "react-native-elements";
import {Navigation} from 'react-native-navigation'; import {Navigation} from 'react-native-navigation';
import Color from '../style/color' import Color from '../style/color';
import Api from '../util/api' import Api from '../util/api';
import BottomNav from '../nav/bottomNav' import Msg from '../util/msg';
export default class LoginForm extends Component { export default class LoginForm extends Component {
@ -53,6 +53,15 @@ export default class LoginForm extends Component {
} }
_clickLogin() { _clickLogin() {
if(!this.state.username) {
Msg.showMsg('请输入邮箱/手机');
return;
}
if(!this.state.password) {
Msg.showMsg('请输入密码');
return;
}
this.props.setLoading(true); this.props.setLoading(true);
this.login().then(result => { this.login().then(result => {
this.props.setLoading(false); this.props.setLoading(false);
@ -60,14 +69,6 @@ export default class LoginForm extends Component {
}); });
} }
_usernameSubmit() {
this.refs.loginPw.focus();
}
_passwordSubmit() {
this._clickLogin();
}
render() {return ( render() {return (
<View> <View>
<Text style={localStyle.title}>{'欢迎来到胶囊日记'}</Text> <Text style={localStyle.title}>{'欢迎来到胶囊日记'}</Text>
@ -89,7 +90,7 @@ export default class LoginForm extends Component {
returnKeyType="next" returnKeyType="next"
onChangeText={(text) => this.setState({username: text})} onChangeText={(text) => this.setState({username: text})}
onSubmitEditing={this._usernameSubmit.bind(this)} onSubmitEditing={() => {}}
/> />
<FormInput ref="loginPw" <FormInput ref="loginPw"
@ -107,7 +108,7 @@ export default class LoginForm extends Component {
returnKeyType='done' returnKeyType='done'
onChangeText={(text) => this.setState({password: text})} onChangeText={(text) => this.setState({password: text})}
onSubmitEditing={this._passwordSubmit.bind(this)} onSubmitEditing={this._clickLogin.bind(this)}
/> />
</View> </View>

View file

@ -3,11 +3,12 @@ import {Platform, StyleSheet, Text, View, InteractionManager, Alert} from 'react
import {FormInput, Button} from "react-native-elements"; import {FormInput, Button} from "react-native-elements";
import {Navigation} from 'react-native-navigation'; import {Navigation} from 'react-native-navigation';
import Color from '../style/color' import Color from '../style/color';
import Api from '../util/api' import Api from '../util/api';
import Msg from '../util/msg';
export default class RegisterForm extends Component { export default class RegisterEmailForm extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -37,7 +38,7 @@ export default class RegisterForm extends Component {
_checkResult(result) { _checkResult(result) {
InteractionManager.runAfterInteractions(() => { InteractionManager.runAfterInteractions(() => {
if(result.isRegisterSucc) { if(result.isRegisterSucc) {
Navigation.setRoot(BottomNav.config()); this.props.onRegisterSucc();
} else { } else {
Alert.alert( Alert.alert(
@ -53,6 +54,19 @@ export default class RegisterForm extends Component {
} }
_clickRegister() { _clickRegister() {
if(!this.state.nickname) {
Msg.showMsg('请输入名字');
return;
}
if(!this.state.username) {
Msg.showMsg('请输入邮箱');
return;
}
if(!this.state.password) {
Msg.showMsg('请输入密码');
return;
}
this.props.setLoading(true); this.props.setLoading(true);
this.register().then(result => { this.register().then(result => {
this.props.setLoading(false); this.props.setLoading(false);
@ -60,18 +74,6 @@ export default class RegisterForm extends Component {
}); });
} }
_nicknameSubmit() {
this.refs.inputEmail.focus();
}
_usernameSubmit() {
this.refs.registerPw.focus();
}
_passwordSubmit() {
this._clickRegister();
}
render() {return ( render() {return (
<View> <View>
<Text style={localStyle.title}>{'注册胶囊日记账号'}</Text> <Text style={localStyle.title}>{'注册胶囊日记账号'}</Text>
@ -93,7 +95,7 @@ export default class RegisterForm extends Component {
returnKeyType='next' returnKeyType='next'
onChangeText={(text) => this.setState({nickname: text})} onChangeText={(text) => this.setState({nickname: text})}
onSubmitEditing={this._nicknameSubmit.bind(this)} onSubmitEditing={() => {}}
/> />
<FormInput ref='inputEmail' <FormInput ref='inputEmail'
@ -115,7 +117,7 @@ export default class RegisterForm extends Component {
onSubmitEditing={() => {}} onSubmitEditing={() => {}}
/> />
<FormInput ref='registerPw' <FormInput ref='registerEmailPw'
selectionColor={Color.primary} selectionColor={Color.primary}
underlineColorAndroid='transparent' underlineColorAndroid='transparent'
@ -130,7 +132,7 @@ export default class RegisterForm extends Component {
returnKeyType='done' returnKeyType='done'
onChangeText={(text) => this.setState({password: text})} onChangeText={(text) => this.setState({password: text})}
onSubmitEditing={this._passwordSubmit.bind(this)} onSubmitEditing={this._clickRegister.bind(this)}
/> />
</View> </View>

View file

@ -0,0 +1,230 @@
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, InteractionManager, Alert} from 'react-native';
import {FormInput, Button} from "react-native-elements";
import {Navigation} from 'react-native-navigation';
import Color from '../style/color';
import Api from '../util/api';
import Msg from '../util/msg';
export default class RegisterMobileForm extends Component {
constructor(props) {
super(props);
this.state = ({
nickname: '',
mobile: '',
mobileSendTime: 0,
code: '',
password: ''
});
this.timer = setInterval(() => {
if(this.state.mobileSendTime > 0) {
this.setState({mobileSendTime: this.state.mobileSendTime - 1})
}
}, 1000)
}
componentWillUnmount () {
clearInterval(this.timer)
}
requestCode() {
if (!this.state.mobile) {
Msg.showMsg('请输入手机');
return;
}
Api.sendRegisterVerificationCode(this.state.mobile)
.then(() => {
this.setState({mobileSendTime: 60});
Msg.showMsg('验证码已发送');
})
.catch(e => {
Msg.showMsg('验证码发送失败');
})
.done();
};
async register() {
let isRegisterSucc, errMsg = '注册失败';
try {
isRegisterSucc = await Api.mobileRegister(this.state.nickname, this.state.mobile, this.state.password, this.state.code)
} catch (err) {
errMsg = err.message;
}
return {
isRegisterSucc,
errMsg
}
}
_checkResult(result) {
InteractionManager.runAfterInteractions(() => {
if(result.isRegisterSucc) {
this.props.onRegisterSucc();
} else {
Alert.alert(
result.errMsg,
'',
[
{text: '确定', onPress: () => {}},
],
{cancelable: false}
)
}
})
}
_clickRegister() {
if(!this.state.nickname) {
Msg.showMsg('请输入名字');
return;
}
if(!this.state.mobile) {
Msg.showMsg('请输入手机');
return;
}
if(!this.state.code) {
Msg.showMsg('请输入验证码');
return;
}
if(!this.state.password) {
Msg.showMsg('请输入密码');
return;
}
this.props.setLoading(true);
this.register().then(result => {
this.props.setLoading(false);
this._checkResult(result);
});
}
render() {return (
<View>
<Text style={localStyle.title}>{'注册胶囊日记账号'}</Text>
<View style={localStyle.form}>
<FormInput
selectionColor={Color.primary}
underlineColorAndroid='transparent'
keyboardType='email-address'
value={this.state.nickname}
autoCorrect={false}
autoFocus={false}
autoCapitalize='none'
placeholderTextColor={Color.inactiveText}
placeholder='名字'
returnKeyType='next'
onChangeText={(text) => this.setState({nickname: text})}
onSubmitEditing={() => {}}
/>
<View style={{flexDirection:"row"}}>
<FormInput ref='inputMobile'
containerStyle={{flex: 1}}
underlineColorAndroid='transparent'
selectionColor={Color.primary}
keyboardType='phone-pad'
value={this.state.mobile}
autoCorrect={false}
autoFocus={false}
autoCapitalize='none'
placeholder='手机号'
placeholderTextColor={Color.inactiveText}
returnKeyType='next'
onChangeText={(text) => this.setState({mobile: text})}
onSubmitEditing={() => {}}
/>
<Button title={this.state.mobileSendTime == 0 ? "发送验证码" : (this.state.mobileSendTime) + '秒后重发'}
disabled={this.state.mobileSendTime > 0}
large={false}
borderRadius={999}
backgroundColor={Color.primary}
style={{marginBottom: 0, marginTop:5, marginRight:5, marginLeft:-15}}
buttonStyle={Platform.OS === 'ios' ? {
paddingVertical:8,
paddingHorizontal:12,
width: 90
} : { width: 90 }}
textStyle={{fontWeight: 'bold', fontSize: 12, fontFamily:"Helvetica"}}
onPress={this.requestCode.bind(this)}
/>
</View>
<FormInput ref='inputCode'
underlineColorAndroid='transparent'
selectionColor={Color.primary}
keyboardType='phone-pad'
value={this.state.code}
autoCorrect={false}
autoFocus={false}
autoCapitalize='none'
placeholder='验证码'
placeholderTextColor={Color.inactiveText}
returnKeyType='next'
onChangeText={(text) => this.setState({code: text})}
onSubmitEditing={() => {}}
/>
<FormInput ref='registerMobilePw'
selectionColor={Color.primary}
underlineColorAndroid='transparent'
value={this.state.password}
secureTextEntry={true}
selectTextOnFocus={true}
autoCorrect={false}
placeholder='登录密码'
placeholderTextColor={Color.inactiveText}
returnKeyType='done'
onChangeText={(text) => this.setState({password: text})}
onSubmitEditing={this._clickRegister.bind(this)}
/>
</View>
<Button borderRadius={999} title={'注册'}
backgroundColor={Color.primary}
onPress={this._clickRegister.bind(this)}
/>
</View>
);}
}
const localStyle = StyleSheet.create({
title: {
fontSize: 26,
paddingBottom: 35,
color: '#222',
textAlign: 'center'
},
form: {
paddingBottom: 20,
}
});

View file

@ -49,6 +49,52 @@ async function logout() {
Token.setLoginPassword(''); Token.setLoginPassword('');
} }
async function sendRegisterVerificationCode(mobile) {
return callV2('POST', '/verification/register', {
'type': 'mobile',
'sendTo': mobile
});
}
async function register(nickname, username, password) {
const result = await call('POST', '/users', {
name: nickname,
email: username,
password: password
});
if(result) {
const token = Token.generateToken(username, password);
await Token.setUserToken(token);
const userInfo = await getSelfInfo();
await Token.setUserInfo(userInfo);
}
return result;
}
async function mobileRegister(nickname, mobile, password, code) {
const result = await callV2('POST', '/users', {
type: 'mobile',
name: nickname,
mobile: mobile,
password: password,
code: code
});
if(result) {
const token = Token.generateToken(mobile, password);
await Token.setUserToken(token);
const userInfo = await getSelfInfo();
await Token.setUserInfo(userInfo);
}
return result;
}
async function getSplashByStore() { async function getSplashByStore() {
try { try {
let info = await Token.get('splash'); let info = await Token.get('splash');
@ -426,6 +472,10 @@ export default {
login, login,
logout, logout,
sendRegisterVerificationCode,
register,
mobileRegister,
getSplashByStore, getSplashByStore,
syncSplash, syncSplash,
getSelfInfoByStore, getSelfInfoByStore,