mirror of
https://github.com/timepill/timepill-app.git
synced 2025-04-30 09:59:31 +08:00
1. 登录,邮箱/手机号账号注册(账号注册未测试)
This commit is contained in:
parent
487aecdf96
commit
d137b41c74
6 changed files with 439 additions and 66 deletions
156
App.js
156
App.js
|
@ -27,7 +27,8 @@ import BottomNav from './src/nav/bottomNav';
|
|||
|
||||
import Loading from './src/component/loading';
|
||||
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 {
|
||||
|
@ -36,26 +37,53 @@ export default class App extends Component {
|
|||
super(props);
|
||||
|
||||
this.state = ({
|
||||
isLoginPage: true,
|
||||
isLoading: false
|
||||
page: App.pageLogin,
|
||||
|
||||
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) {
|
||||
this.setState({isLoading: value});
|
||||
}
|
||||
|
||||
_toWeb() {
|
||||
Linking.openURL("https://timepill.net/home/forgot_password");
|
||||
}
|
||||
|
||||
_switchForm() {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
this.setState({
|
||||
isLoginPage: !this.state.isLoginPage
|
||||
});
|
||||
}
|
||||
|
||||
_onSucc() {
|
||||
Api.getSplashByStore()
|
||||
.then(splash => {
|
||||
|
@ -68,34 +96,97 @@ export default class App extends Component {
|
|||
return (
|
||||
<View style={localStyle.wrap}>
|
||||
<Loading visible={this.state.isLoading}></Loading>
|
||||
<Animated.View style={localStyle.content}>
|
||||
{this.state.isLoginPage
|
||||
? (<LoginForm
|
||||
setLoading={this._setLoading.bind(this)}
|
||||
onLoginSucc={this._onSucc.bind(this)}
|
||||
></LoginForm>)
|
||||
: (<RegisterForm
|
||||
setLoading={this._setLoading.bind(this)}
|
||||
onRegisterSucc={this._onSucc.bind(this)}
|
||||
></RegisterForm>)}
|
||||
<Animated.View style={[localStyle.content, {paddingTop: this.state.paddingAnim}]}>
|
||||
{this.renderForm()}
|
||||
|
||||
<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}>
|
||||
{this.state.isLoginPage ? '没有账号?注册一个' : '已有账号?马上登录'}
|
||||
{this.state.page == App.pageLogin ? '没有账号?注册一个' : '已有账号?马上登录'}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={this._toWeb.bind(this)}>
|
||||
<Text style={localStyle.bottomText}>
|
||||
忘记密码?
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{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>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
const localStyle = StyleSheet.create({
|
||||
|
@ -105,7 +196,6 @@ const localStyle = StyleSheet.create({
|
|||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
paddingTop: '30%',
|
||||
paddingHorizontal: 15
|
||||
},
|
||||
bottom: {
|
||||
|
|
2
index.js
2
index.js
|
@ -15,7 +15,7 @@ import BottomNav from './src/nav/bottomNav';
|
|||
|
||||
|
||||
// for debug
|
||||
// console.disableYellowBox = true;
|
||||
console.disableYellowBox = true;
|
||||
|
||||
|
||||
Navigation.registerComponent('Timepill', () => App);
|
||||
|
|
|
@ -3,9 +3,9 @@ import {Platform, StyleSheet, Text, View, InteractionManager, Alert} from 'react
|
|||
import {FormInput, Button} from "react-native-elements";
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
|
||||
import Color from '../style/color'
|
||||
import Api from '../util/api'
|
||||
import BottomNav from '../nav/bottomNav'
|
||||
import Color from '../style/color';
|
||||
import Api from '../util/api';
|
||||
import Msg from '../util/msg';
|
||||
|
||||
|
||||
export default class LoginForm extends Component {
|
||||
|
@ -53,6 +53,15 @@ export default class LoginForm extends Component {
|
|||
}
|
||||
|
||||
_clickLogin() {
|
||||
if(!this.state.username) {
|
||||
Msg.showMsg('请输入邮箱/手机');
|
||||
return;
|
||||
}
|
||||
if(!this.state.password) {
|
||||
Msg.showMsg('请输入密码');
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.setLoading(true);
|
||||
this.login().then(result => {
|
||||
this.props.setLoading(false);
|
||||
|
@ -60,14 +69,6 @@ export default class LoginForm extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
_usernameSubmit() {
|
||||
this.refs.loginPw.focus();
|
||||
}
|
||||
|
||||
_passwordSubmit() {
|
||||
this._clickLogin();
|
||||
}
|
||||
|
||||
render() {return (
|
||||
<View>
|
||||
<Text style={localStyle.title}>{'欢迎来到胶囊日记'}</Text>
|
||||
|
@ -89,7 +90,7 @@ export default class LoginForm extends Component {
|
|||
returnKeyType="next"
|
||||
|
||||
onChangeText={(text) => this.setState({username: text})}
|
||||
onSubmitEditing={this._usernameSubmit.bind(this)}
|
||||
onSubmitEditing={() => {}}
|
||||
/>
|
||||
|
||||
<FormInput ref="loginPw"
|
||||
|
@ -107,7 +108,7 @@ export default class LoginForm extends Component {
|
|||
returnKeyType='done'
|
||||
|
||||
onChangeText={(text) => this.setState({password: text})}
|
||||
onSubmitEditing={this._passwordSubmit.bind(this)}
|
||||
onSubmitEditing={this._clickLogin.bind(this)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
|
|
|
@ -3,11 +3,12 @@ import {Platform, StyleSheet, Text, View, InteractionManager, Alert} from 'react
|
|||
import {FormInput, Button} from "react-native-elements";
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
|
||||
import Color from '../style/color'
|
||||
import Api from '../util/api'
|
||||
import Color from '../style/color';
|
||||
import Api from '../util/api';
|
||||
import Msg from '../util/msg';
|
||||
|
||||
|
||||
export default class RegisterForm extends Component {
|
||||
export default class RegisterEmailForm extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -37,7 +38,7 @@ export default class RegisterForm extends Component {
|
|||
_checkResult(result) {
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
if(result.isRegisterSucc) {
|
||||
Navigation.setRoot(BottomNav.config());
|
||||
this.props.onRegisterSucc();
|
||||
|
||||
} else {
|
||||
Alert.alert(
|
||||
|
@ -53,6 +54,19 @@ export default class RegisterForm extends Component {
|
|||
}
|
||||
|
||||
_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.register().then(result => {
|
||||
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 (
|
||||
<View>
|
||||
<Text style={localStyle.title}>{'注册胶囊日记账号'}</Text>
|
||||
|
@ -93,7 +95,7 @@ export default class RegisterForm extends Component {
|
|||
returnKeyType='next'
|
||||
|
||||
onChangeText={(text) => this.setState({nickname: text})}
|
||||
onSubmitEditing={this._nicknameSubmit.bind(this)}
|
||||
onSubmitEditing={() => {}}
|
||||
/>
|
||||
|
||||
<FormInput ref='inputEmail'
|
||||
|
@ -115,7 +117,7 @@ export default class RegisterForm extends Component {
|
|||
onSubmitEditing={() => {}}
|
||||
/>
|
||||
|
||||
<FormInput ref='registerPw'
|
||||
<FormInput ref='registerEmailPw'
|
||||
|
||||
selectionColor={Color.primary}
|
||||
underlineColorAndroid='transparent'
|
||||
|
@ -130,7 +132,7 @@ export default class RegisterForm extends Component {
|
|||
returnKeyType='done'
|
||||
|
||||
onChangeText={(text) => this.setState({password: text})}
|
||||
onSubmitEditing={this._passwordSubmit.bind(this)}
|
||||
onSubmitEditing={this._clickRegister.bind(this)}
|
||||
/>
|
||||
</View>
|
||||
|
230
src/component/registerMobileForm.js
Normal file
230
src/component/registerMobileForm.js
Normal 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,
|
||||
}
|
||||
});
|
|
@ -49,6 +49,52 @@ async function logout() {
|
|||
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() {
|
||||
try {
|
||||
let info = await Token.get('splash');
|
||||
|
@ -426,6 +472,10 @@ export default {
|
|||
|
||||
login,
|
||||
logout,
|
||||
sendRegisterVerificationCode,
|
||||
register,
|
||||
mobileRegister,
|
||||
|
||||
getSplashByStore,
|
||||
syncSplash,
|
||||
getSelfInfoByStore,
|
||||
|
|
Loading…
Reference in a new issue