Add scene + action for login (#24)
This commit is contained in:
parent
829972694b
commit
5bdc432f71
8 changed files with 170 additions and 2 deletions
18
src/actions/login.js
Normal file
18
src/actions/login.js
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {LoginTypes as types} from 'constants';
|
||||
import Client from 'client/client_instance';
|
||||
import {bindClientFunc} from 'actions/helpers.js';
|
||||
|
||||
export function login(loginId, password, mfaToken = '') {
|
||||
return bindClientFunc(
|
||||
Client.login,
|
||||
types.LOGIN_REQUEST,
|
||||
types.LOGIN_SUCCESS,
|
||||
types.LOGIN_FAILURE,
|
||||
loginId,
|
||||
password,
|
||||
mfaToken
|
||||
);
|
||||
}
|
||||
105
src/components/login.js
Normal file
105
src/components/login.js
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React, {Component, PropTypes} from 'react';
|
||||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
import {Image, StyleSheet, Text, TextInput, View} from 'react-native';
|
||||
import {Actions as Routes} from 'react-native-router-flux';
|
||||
|
||||
import * as loginActions from 'actions/login';
|
||||
import Button from 'components/button';
|
||||
import ErrorText from 'components/error_text';
|
||||
import {GlobalStyles} from 'styles';
|
||||
import logo from 'images/logo.png';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
paddingTop: 200,
|
||||
backgroundColor: 'white'
|
||||
},
|
||||
logo: {
|
||||
marginBottom: 10
|
||||
}
|
||||
});
|
||||
|
||||
const propTypes = {
|
||||
login: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
class Login extends Component {
|
||||
static propTypes = propTypes;
|
||||
state = {
|
||||
loginId: '',
|
||||
password: ''
|
||||
};
|
||||
|
||||
componentWillReceiveProps(props) {
|
||||
if (this.props.login.status === 'fetching' &&
|
||||
props.login.status === 'fetched') {
|
||||
Routes.SelectTeam(); // eslint-disable-line new-cap
|
||||
}
|
||||
}
|
||||
|
||||
signIn() {
|
||||
if (this.props.login.status !== 'fetching') {
|
||||
const {loginId, password} = this.state;
|
||||
this.props.actions.login(loginId, password);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Image
|
||||
style={styles.logo}
|
||||
source={logo}
|
||||
/>
|
||||
<Text>{'Mattermost'}</Text>
|
||||
<Text>
|
||||
{'All team communication in one place, searchable and accessible anywhere'}
|
||||
</Text>
|
||||
<TextInput
|
||||
value={this.state.loginId}
|
||||
onChangeText={(loginId) => this.setState({loginId})}
|
||||
style={GlobalStyles.inputBox}
|
||||
placeholder='Email or Username'
|
||||
autoCorrect={false}
|
||||
autoCapitalize='none'
|
||||
/>
|
||||
<TextInput
|
||||
value={this.state.password}
|
||||
onChangeText={(password) => this.setState({password})}
|
||||
style={GlobalStyles.inputBox}
|
||||
placeholder='Password'
|
||||
autoCorrect={false}
|
||||
autoCapitalize='none'
|
||||
/>
|
||||
<Button
|
||||
onPress={() => this.signIn()}
|
||||
text='Sign in'
|
||||
/>
|
||||
<ErrorText error={this.props.login.error}/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
login: state.views.login
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(loginActions, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Login);
|
||||
|
|
@ -49,7 +49,7 @@ class SelectServerView extends Component {
|
|||
|
||||
onClick = () => {
|
||||
Client.setUrl(this.state.serverUrl);
|
||||
Routes.SelectTeam(); // eslint-disable-line new-cap
|
||||
Routes.Login(); // eslint-disable-line new-cap
|
||||
|
||||
// this.props.getPing().then(() => {
|
||||
// AsyncStorage.setItem('serverUrl', this.state.serverUrl, () => {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import * as ChannelsTypes from './channels';
|
||||
import * as DeviceTypes from './device';
|
||||
import * as GeneralTypes from './general';
|
||||
import * as LoginTypes from './login';
|
||||
import * as TeamsTypes from './teams';
|
||||
|
||||
export {
|
||||
DeviceTypes,
|
||||
GeneralTypes,
|
||||
LoginTypes,
|
||||
TeamsTypes,
|
||||
ChannelsTypes
|
||||
};
|
||||
|
|
|
|||
3
src/constants/login.js
Normal file
3
src/constants/login.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export const LOGIN_REQUEST = 'LOGIN_REQUEST';
|
||||
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
|
||||
export const LOGIN_FAILURE = 'LOGIN_FAILURE';
|
||||
|
|
@ -6,6 +6,7 @@ import {combineReducers} from 'redux';
|
|||
import channels from './channels';
|
||||
import device from './device.js';
|
||||
import general from './general.js';
|
||||
import login from './login';
|
||||
import teams from './teams';
|
||||
|
||||
const entities = combineReducers({
|
||||
|
|
@ -15,7 +16,8 @@ const entities = combineReducers({
|
|||
});
|
||||
|
||||
const views = combineReducers({
|
||||
device
|
||||
device,
|
||||
login
|
||||
});
|
||||
|
||||
export default combineReducers({
|
||||
|
|
|
|||
32
src/reducers/login.js
Normal file
32
src/reducers/login.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {LoginTypes as types} from 'constants';
|
||||
|
||||
const initState = {
|
||||
status: 'not fetched',
|
||||
error: null
|
||||
};
|
||||
|
||||
export default function reduceLogin(state = initState, action) {
|
||||
switch (action.type) {
|
||||
|
||||
case types.LOGIN_REQUEST:
|
||||
return {...state,
|
||||
status: 'fetching',
|
||||
error: null
|
||||
};
|
||||
case types.LOGIN_SUCCESS:
|
||||
return {...state,
|
||||
status: 'fetched'
|
||||
};
|
||||
case types.LOGIN_FAILURE:
|
||||
return {...state,
|
||||
status: 'failed',
|
||||
error: action.error
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import React, {Component} from 'react';
|
|||
import {Scene, Router} from 'react-native-router-flux';
|
||||
|
||||
import ChannelsList from 'components/channels_list';
|
||||
import Login from 'components/login';
|
||||
import SelectServerView from 'components/select_server_view';
|
||||
import SelectTeam from 'components/select_team';
|
||||
|
||||
|
|
@ -19,6 +20,11 @@ export default class Routes extends Component {
|
|||
component={ChannelsList}
|
||||
title='Channels'
|
||||
/>
|
||||
<Scene
|
||||
key='Login'
|
||||
component={Login}
|
||||
title='Login'
|
||||
/>
|
||||
<Scene
|
||||
key='SelectServerView'
|
||||
component={SelectServerView}
|
||||
|
|
|
|||
Loading…
Reference in a new issue