Register user (#44)
* Added feature to register a new user * login after register working * Removed username from register and placed on a new view * loading indicator on username submit * register/username logo layout issue * - login and register background white * - logo removed from logo and register
This commit is contained in:
parent
335f299d6d
commit
125b880760
|
@ -9,7 +9,17 @@ function createRequestTypes(base, types = defaultTypes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Login events
|
// Login events
|
||||||
export const LOGIN = createRequestTypes('LOGIN', [...defaultTypes, 'SET_TOKEN', 'SUBMIT']);
|
export const LOGIN = createRequestTypes('LOGIN', [
|
||||||
|
...defaultTypes,
|
||||||
|
'SET_TOKEN',
|
||||||
|
'SUBMIT',
|
||||||
|
'REGISTER_SUBMIT',
|
||||||
|
'REGISTER_REQUEST',
|
||||||
|
'REGISTER_SUCCESS',
|
||||||
|
'SET_USERNAME_SUBMIT',
|
||||||
|
'SET_USERNAME_REQUEST',
|
||||||
|
'SET_USERNAME_SUCCESS'
|
||||||
|
]);
|
||||||
export const ROOMS = createRequestTypes('ROOMS');
|
export const ROOMS = createRequestTypes('ROOMS');
|
||||||
export const APP = createRequestTypes('APP', ['READY', 'INIT']);
|
export const APP = createRequestTypes('APP', ['READY', 'INIT']);
|
||||||
export const MESSAGES = createRequestTypes('MESSAGES');
|
export const MESSAGES = createRequestTypes('MESSAGES');
|
||||||
|
|
|
@ -13,6 +13,46 @@ export function loginRequest(credentials) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function registerSubmit(credentials) {
|
||||||
|
return {
|
||||||
|
type: types.LOGIN.REGISTER_SUBMIT,
|
||||||
|
credentials
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export function registerRequest(credentials) {
|
||||||
|
return {
|
||||||
|
type: types.LOGIN.REGISTER_REQUEST,
|
||||||
|
credentials
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export function registerSuccess(credentials) {
|
||||||
|
return {
|
||||||
|
type: types.LOGIN.REGISTER_SUCCESS,
|
||||||
|
credentials
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setUsernameSubmit(credentials) {
|
||||||
|
return {
|
||||||
|
type: types.LOGIN.SET_USERNAME_SUBMIT,
|
||||||
|
credentials
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setUsernameRequest(credentials) {
|
||||||
|
return {
|
||||||
|
type: types.LOGIN.SET_USERNAME_REQUEST,
|
||||||
|
credentials
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setUsernameSuccess() {
|
||||||
|
return {
|
||||||
|
type: types.LOGIN.SET_USERNAME_SUCCESS
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function loginSuccess(user) {
|
export function loginSuccess(user) {
|
||||||
return {
|
return {
|
||||||
type: types.LOGIN.SUCCESS,
|
type: types.LOGIN.SUCCESS,
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View, Image } from 'react-native';
|
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as Animatable from 'react-native-animatable';
|
|
||||||
import { appInit } from '../actions';
|
import { appInit } from '../actions';
|
||||||
|
|
||||||
import styles from '../views/Styles';
|
|
||||||
|
|
||||||
import AuthRoutes from './routes/AuthRoutes';
|
import AuthRoutes from './routes/AuthRoutes';
|
||||||
import PublicRoutes from './routes/PublicRoutes';
|
import PublicRoutes from './routes/PublicRoutes';
|
||||||
|
import Loading from '../presentation/Loading';
|
||||||
|
|
||||||
@connect(
|
@connect(
|
||||||
state => ({
|
state => ({
|
||||||
|
@ -34,21 +31,10 @@ export default class Routes extends React.Component {
|
||||||
const { login, app } = this.props;
|
const { login, app } = this.props;
|
||||||
|
|
||||||
if (app.starting) {
|
if (app.starting) {
|
||||||
return (
|
return (<Loading />);
|
||||||
<View style={styles.logoContainer}>
|
|
||||||
<Animatable.Text
|
|
||||||
animation='pulse'
|
|
||||||
easing='ease-out'
|
|
||||||
iterationCount='infinite'
|
|
||||||
style={{ textAlign: 'center' }}
|
|
||||||
>
|
|
||||||
<Image style={styles.logo} source={require('../images/logo.png')} />
|
|
||||||
</Animatable.Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((login.token && !login.failure) || app.ready) {
|
if ((login.token && !login.failure && !login.isRegistering) || app.ready) {
|
||||||
return (<AuthRoutes />);
|
return (<AuthRoutes />);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button } from 'react-native';
|
import { StackNavigator, DrawerNavigator, NavigationActions, HeaderBackButton } from 'react-navigation';
|
||||||
import { StackNavigator, DrawerNavigator, NavigationActions } from 'react-navigation';
|
|
||||||
// import { Platform } from 'react-native';
|
|
||||||
|
|
||||||
import Sidebar from '../../containers/Sidebar';
|
import Sidebar from '../../containers/Sidebar';
|
||||||
import DrawerMenuButton from '../../presentation/DrawerMenuButton';
|
import DrawerMenuButton from '../../presentation/DrawerMenuButton';
|
||||||
|
@ -39,7 +37,10 @@ const AuthRoutes = StackNavigator(
|
||||||
return {
|
return {
|
||||||
title: navigation.state.params.title || 'Room',
|
title: navigation.state.params.title || 'Room',
|
||||||
headerLeft: (
|
headerLeft: (
|
||||||
<Button title={'Back'} onPress={() => backToScreen(navigation, 'RoomsList')} />
|
<HeaderBackButton
|
||||||
|
title={'Back'}
|
||||||
|
onPress={() => backToScreen(navigation, 'RoomsList')}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
// [drawerIconPosition]: (<DrawerMenuButton navigation={navigation} />)÷
|
// [drawerIconPosition]: (<DrawerMenuButton navigation={navigation} />)÷
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@ import Icon from 'react-native-vector-icons/FontAwesome';
|
||||||
import ListServerView from '../../views/ListServerView';
|
import ListServerView from '../../views/ListServerView';
|
||||||
import NewServerView from '../../views/NewServerView';
|
import NewServerView from '../../views/NewServerView';
|
||||||
import LoginView from '../../views/LoginView';
|
import LoginView from '../../views/LoginView';
|
||||||
|
import RegisterView from '../../views/RegisterView';
|
||||||
|
|
||||||
const PublicRoutes = StackNavigator(
|
const PublicRoutes = StackNavigator(
|
||||||
{
|
{
|
||||||
|
@ -36,6 +37,12 @@ const PublicRoutes = StackNavigator(
|
||||||
navigationOptions: {
|
navigationOptions: {
|
||||||
title: 'Login'
|
title: 'Login'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
Register: {
|
||||||
|
screen: RegisterView,
|
||||||
|
navigationOptions: {
|
||||||
|
title: 'Register'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
|
@ -122,6 +122,28 @@ const RocketChat = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
register({ credentials }) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
Meteor.call('registerUser', credentials, (err, userId) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve(userId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setUsername({ credentials }) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
Meteor.call('setUsername', credentials.username, (err, result) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
loginWithPassword({ username, password, code }, callback) {
|
loginWithPassword({ username, password, code }, callback) {
|
||||||
let params = {};
|
let params = {};
|
||||||
const state = reduxStore.getState();
|
const state = reduxStore.getState();
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { KeyboardAvoidingView } from 'react-native';
|
import { ViewPropTypes } from 'react-native';
|
||||||
|
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
|
||||||
|
|
||||||
export default class KeyboardView extends React.PureComponent {
|
export default class KeyboardView extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
style: KeyboardAvoidingView.propTypes.style,
|
style: ViewPropTypes.style,
|
||||||
|
contentContainerStyle: ViewPropTypes.style,
|
||||||
keyboardVerticalOffset: PropTypes.number,
|
keyboardVerticalOffset: PropTypes.number,
|
||||||
|
scrollEnabled: PropTypes.bool,
|
||||||
children: PropTypes.oneOfType([
|
children: PropTypes.oneOfType([
|
||||||
PropTypes.arrayOf(PropTypes.node),
|
PropTypes.arrayOf(PropTypes.node),
|
||||||
PropTypes.node
|
PropTypes.node
|
||||||
|
@ -14,9 +17,18 @@ export default class KeyboardView extends React.PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<KeyboardAvoidingView style={this.props.style} behavior='padding' keyboardVerticalOffset={this.props.keyboardVerticalOffset}>
|
<KeyboardAwareScrollView
|
||||||
|
keyboardDismissMode='interactive'
|
||||||
|
keyboardShouldPersistTaps='always'
|
||||||
|
style={this.props.style}
|
||||||
|
contentContainerStyle={this.props.contentContainerStyle}
|
||||||
|
scrollEnabled={this.props.scrollEnabled}
|
||||||
|
alwaysBounceVertical={false}
|
||||||
|
extraHeight={this.props.keyboardVerticalOffset}
|
||||||
|
behavior='position'
|
||||||
|
>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</KeyboardAvoidingView>
|
</KeyboardAwareScrollView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { View, StyleSheet, Animated, Dimensions } from 'react-native';
|
||||||
|
|
||||||
|
const logo = require('../images/logo.png');
|
||||||
|
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
width: '100%',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
width: Dimensions.get('window').width,
|
||||||
|
height: Dimensions.get('window').height,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
},
|
||||||
|
logo: {
|
||||||
|
width: Dimensions.get('window').width - 100,
|
||||||
|
height: Dimensions.get('window').width - 100,
|
||||||
|
resizeMode: 'contain'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default class Loading extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.scale = new Animated.Value(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.animate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
animate = () => {
|
||||||
|
Animated.sequence([
|
||||||
|
Animated.timing(
|
||||||
|
this.scale,
|
||||||
|
{
|
||||||
|
toValue: 0.8,
|
||||||
|
duration: 1000,
|
||||||
|
useNativeDriver: true
|
||||||
|
}),
|
||||||
|
Animated.timing(
|
||||||
|
this.scale,
|
||||||
|
{
|
||||||
|
toValue: 1,
|
||||||
|
duration: 1000,
|
||||||
|
useNativeDriver: true
|
||||||
|
})
|
||||||
|
]).start(() => {
|
||||||
|
this.animate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Animated.Image
|
||||||
|
style={[
|
||||||
|
styles.logo,
|
||||||
|
{
|
||||||
|
transform: [
|
||||||
|
{ scale: this.scale }
|
||||||
|
]
|
||||||
|
}]}
|
||||||
|
source={logo}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,19 +3,20 @@ import * as types from '../actions/actionsTypes';
|
||||||
const initialState = {
|
const initialState = {
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
|
isRegistering: false,
|
||||||
token: '',
|
token: '',
|
||||||
user: {},
|
user: {},
|
||||||
errorMessage: ''
|
error: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function login(state = initialState, action) {
|
export default function login(state = initialState, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case types.LOGIN.REQUEST:
|
case types.LOGIN.REQUEST:
|
||||||
console.log('types.LOGIN.REQUEST', action);
|
|
||||||
return { ...state,
|
return { ...state,
|
||||||
isFetching: true,
|
isFetching: true,
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
failure: false
|
failure: false,
|
||||||
|
error: ''
|
||||||
};
|
};
|
||||||
case types.LOGIN.SUCCESS:
|
case types.LOGIN.SUCCESS:
|
||||||
return { ...state,
|
return { ...state,
|
||||||
|
@ -23,15 +24,15 @@ export default function login(state = initialState, action) {
|
||||||
isAuthenticated: true,
|
isAuthenticated: true,
|
||||||
user: action.user,
|
user: action.user,
|
||||||
token: action.user.token,
|
token: action.user.token,
|
||||||
failure: false
|
failure: false,
|
||||||
// user: action.user
|
error: ''
|
||||||
};
|
};
|
||||||
case types.LOGIN.FAILURE:
|
case types.LOGIN.FAILURE:
|
||||||
return { ...state,
|
return { ...state,
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
failure: true,
|
failure: true,
|
||||||
errorMessage: action.err
|
error: action.err
|
||||||
};
|
};
|
||||||
case types.LOGOUT:
|
case types.LOGOUT:
|
||||||
return initialState;
|
return initialState;
|
||||||
|
@ -40,6 +41,34 @@ export default function login(state = initialState, action) {
|
||||||
token: action.token,
|
token: action.token,
|
||||||
user: action.user
|
user: action.user
|
||||||
};
|
};
|
||||||
|
case types.LOGIN.REGISTER_SUBMIT:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isFetching: true,
|
||||||
|
isAuthenticated: false,
|
||||||
|
isRegistering: true,
|
||||||
|
failure: false,
|
||||||
|
error: ''
|
||||||
|
};
|
||||||
|
case types.LOGIN.REGISTER_SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isFetching: false,
|
||||||
|
isAuthenticated: false,
|
||||||
|
failure: false,
|
||||||
|
error: ''
|
||||||
|
};
|
||||||
|
case types.LOGIN.SET_USERNAME_SUBMIT:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isFetching: true
|
||||||
|
};
|
||||||
|
case types.LOGIN.SET_USERNAME_SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isFetching: false,
|
||||||
|
isRegistering: false
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,26 @@
|
||||||
import { AsyncStorage } from 'react-native';
|
import { AsyncStorage } from 'react-native';
|
||||||
import { take, put, call, takeEvery, select, all, race } from 'redux-saga/effects';
|
import { take, put, call, takeEvery, takeLatest, select, all } from 'redux-saga/effects';
|
||||||
import * as types from '../actions/actionsTypes';
|
import * as types from '../actions/actionsTypes';
|
||||||
import { loginRequest, loginSuccess, loginFailure, setToken, logout } from '../actions/login';
|
import {
|
||||||
|
loginRequest,
|
||||||
|
loginSubmit,
|
||||||
|
registerRequest,
|
||||||
|
loginSuccess,
|
||||||
|
loginFailure,
|
||||||
|
setToken,
|
||||||
|
logout,
|
||||||
|
registerSuccess,
|
||||||
|
setUsernameRequest,
|
||||||
|
setUsernameSuccess
|
||||||
|
} from '../actions/login';
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
|
|
||||||
const TOKEN_KEY = 'reactnativemeteor_usertoken';
|
const TOKEN_KEY = 'reactnativemeteor_usertoken';
|
||||||
const getUser = state => state.login;
|
const getUser = state => state.login;
|
||||||
const getServer = state => state.server.server;
|
const getServer = state => state.server.server;
|
||||||
const loginCall = args => (args.resume ? RocketChat.login(args) : RocketChat.loginWithPassword(args));
|
const loginCall = args => (args.resume ? RocketChat.login(args) : RocketChat.loginWithPassword(args));
|
||||||
|
const registerCall = args => RocketChat.register(args);
|
||||||
|
const setUsernameCall = args => RocketChat.setUsername(args);
|
||||||
|
|
||||||
const getToken = function* getToken() {
|
const getToken = function* getToken() {
|
||||||
const currentServer = yield select(getServer);
|
const currentServer = yield select(getServer);
|
||||||
|
@ -77,19 +90,57 @@ const handleLoginRequest = function* handleLoginRequest({ credentials }) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLoginSubmit = function* handleLoginSubmit({ credentials }) {
|
const handleLoginSubmit = function* handleLoginSubmit({ credentials }) {
|
||||||
// put a login request
|
|
||||||
yield put(loginRequest(credentials));
|
yield put(loginRequest(credentials));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRegisterSubmit = function* handleRegisterSubmit({ credentials }) {
|
||||||
|
// put a login request
|
||||||
|
yield put(registerRequest(credentials));
|
||||||
// wait for a response
|
// wait for a response
|
||||||
yield race({
|
// yield race({
|
||||||
success: take(types.LOGIN.SUCCESS),
|
// success: take(types.LOGIN.REGISTER_SUCCESS),
|
||||||
error: take(types.LOGIN.FAILURE)
|
// error: take(types.LOGIN.FAILURE)
|
||||||
});
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRegisterRequest = function* handleRegisterRequest({ credentials }) {
|
||||||
|
try {
|
||||||
|
yield call(registerCall, { credentials });
|
||||||
|
yield put(registerSuccess(credentials));
|
||||||
|
} catch (err) {
|
||||||
|
yield put(loginFailure(err));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRegisterSuccess = function* handleRegisterSuccess({ credentials }) {
|
||||||
|
yield put(loginSubmit({
|
||||||
|
username: credentials.email,
|
||||||
|
password: credentials.pass
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSetUsernameSubmit = function* handleSetUsernameSubmit({ credentials }) {
|
||||||
|
yield put(setUsernameRequest(credentials));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSetUsernameRequest = function* handleSetUsernameRequest({ credentials }) {
|
||||||
|
try {
|
||||||
|
yield call(setUsernameCall, { credentials });
|
||||||
|
yield put(setUsernameSuccess());
|
||||||
|
} catch (err) {
|
||||||
|
yield put(loginFailure(err));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const root = function* root() {
|
const root = function* root() {
|
||||||
yield takeEvery(types.SERVER.CHANGED, handleLoginWhenServerChanges);
|
yield takeEvery(types.SERVER.CHANGED, handleLoginWhenServerChanges);
|
||||||
yield takeEvery(types.LOGIN.REQUEST, handleLoginRequest);
|
yield takeLatest(types.LOGIN.REQUEST, handleLoginRequest);
|
||||||
yield takeEvery(types.LOGIN.SUCCESS, saveToken);
|
yield takeLatest(types.LOGIN.SUCCESS, saveToken);
|
||||||
yield takeEvery(types.LOGIN.SUBMIT, handleLoginSubmit);
|
yield takeLatest(types.LOGIN.SUBMIT, handleLoginSubmit);
|
||||||
|
yield takeLatest(types.LOGIN.REGISTER_REQUEST, handleRegisterRequest);
|
||||||
|
yield takeLatest(types.LOGIN.REGISTER_SUBMIT, handleRegisterSubmit);
|
||||||
|
yield takeLatest(types.LOGIN.REGISTER_SUCCESS, handleRegisterSuccess);
|
||||||
|
yield takeLatest(types.LOGIN.SET_USERNAME_SUBMIT, handleSetUsernameSubmit);
|
||||||
|
yield takeLatest(types.LOGIN.SET_USERNAME_REQUEST, handleSetUsernameRequest);
|
||||||
};
|
};
|
||||||
export default root;
|
export default root;
|
||||||
|
|
|
@ -32,7 +32,7 @@ const validateServer = function* validateServer({ server }) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const addServer = function* addServer({ server }) {
|
const addServer = function* addServer({ server }) {
|
||||||
yield call(serverRequest, server);
|
yield put(serverRequest(server));
|
||||||
|
|
||||||
const { error } = yield race({
|
const { error } = yield race({
|
||||||
error: take(SERVER.FAILURE),
|
error: take(SERVER.FAILURE),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { TextInput, View, Text, Switch, TouchableOpacity, ScrollView } from 'react-native';
|
import { TextInput, View, Text, Switch, TouchableOpacity } from 'react-native';
|
||||||
import { createChannelRequest } from '../actions/createChannel';
|
import { createChannelRequest } from '../actions/createChannel';
|
||||||
import styles from './Styles';
|
import styles from './Styles';
|
||||||
import KeyboardView from '../presentation/KeyboardView';
|
import KeyboardView from '../presentation/KeyboardView';
|
||||||
|
@ -90,8 +90,10 @@ export default class CreateChannelView extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<KeyboardView style={[styles.view_white, { flex: 1, justifyContent: 'flex-start' }]}>
|
<KeyboardView
|
||||||
<ScrollView>
|
style={[styles.defaultViewBackground, { flex: 1 }]}
|
||||||
|
contentContainerStyle={styles.defaultView}
|
||||||
|
>
|
||||||
<View style={styles.formContainer}>
|
<View style={styles.formContainer}>
|
||||||
<Text style={styles.label_white}>Channel Name</Text>
|
<Text style={styles.label_white}>Channel Name</Text>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
@ -138,7 +140,6 @@ export default class CreateChannelView extends React.Component {
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
|
||||||
</KeyboardView>
|
</KeyboardView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
import Spinner from 'react-native-loading-spinner-overlay';
|
import Spinner from 'react-native-loading-spinner-overlay';
|
||||||
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Keyboard, Text, TextInput, View, Image, TouchableOpacity } from 'react-native';
|
import { Keyboard, Text, TextInput, View, TouchableOpacity } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
// import * as actions from '../actions';
|
// import * as actions from '../actions';
|
||||||
|
@ -18,7 +18,8 @@ class LoginView extends React.Component {
|
||||||
loginSubmit: PropTypes.func.isRequired,
|
loginSubmit: PropTypes.func.isRequired,
|
||||||
Accounts_EmailOrUsernamePlaceholder: PropTypes.string,
|
Accounts_EmailOrUsernamePlaceholder: PropTypes.string,
|
||||||
Accounts_PasswordPlaceholder: PropTypes.string,
|
Accounts_PasswordPlaceholder: PropTypes.string,
|
||||||
login: PropTypes.object
|
login: PropTypes.object,
|
||||||
|
navigation: PropTypes.object.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
static navigationOptions = () => ({
|
static navigationOptions = () => ({
|
||||||
|
@ -44,6 +45,10 @@ class LoginView extends React.Component {
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
register = () => {
|
||||||
|
this.props.navigation.navigate('Register');
|
||||||
|
}
|
||||||
|
|
||||||
renderTOTP = () => {
|
renderTOTP = () => {
|
||||||
if (this.props.login.errorMessage && this.props.login.errorMessage.error === 'totp-required') {
|
if (this.props.login.errorMessage && this.props.login.errorMessage.error === 'totp-required') {
|
||||||
return (
|
return (
|
||||||
|
@ -65,48 +70,47 @@ class LoginView extends React.Component {
|
||||||
// {this.props.login.isFetching && <Text> LOGANDO</Text>}
|
// {this.props.login.isFetching && <Text> LOGANDO</Text>}
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<KeyboardView style={styles.container} keyboardVerticalOffset={128}>
|
<KeyboardView
|
||||||
<View style={{ alignItems: 'center' }}>
|
contentContainerStyle={styles.container}
|
||||||
<Image
|
keyboardVerticalOffset={128}
|
||||||
style={styles.logo}
|
>
|
||||||
source={require('../images/logo.png')}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<View style={styles.loginView}>
|
<View style={styles.loginView}>
|
||||||
<View style={styles.formContainer}>
|
<View style={styles.formContainer}>
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholderTextColor={'rgba(255,255,255,.2)'}
|
style={styles.input_white}
|
||||||
style={styles.input}
|
|
||||||
onChangeText={username => this.setState({ username })}
|
onChangeText={username => this.setState({ username })}
|
||||||
keyboardType='email-address'
|
keyboardType='email-address'
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
returnKeyType='next'
|
returnKeyType='next'
|
||||||
autoCapitalize='none'
|
autoCapitalize='none'
|
||||||
autoFocus
|
|
||||||
|
|
||||||
underlineColorAndroid='transparent'
|
underlineColorAndroid='transparent'
|
||||||
onSubmitEditing={() => { this.password.focus(); }}
|
onSubmitEditing={() => { this.password.focus(); }}
|
||||||
placeholder={this.props.Accounts_EmailOrUsernamePlaceholder || 'Email or username'}
|
placeholder={this.props.Accounts_EmailOrUsernamePlaceholder || 'Email or username'}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
ref={(e) => { this.password = e; }}
|
ref={(e) => { this.password = e; }}
|
||||||
placeholderTextColor={'rgba(255,255,255,.2)'}
|
style={styles.input_white}
|
||||||
style={styles.input}
|
|
||||||
onChangeText={password => this.setState({ password })}
|
onChangeText={password => this.setState({ password })}
|
||||||
secureTextEntry
|
secureTextEntry
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
returnKeyType='done'
|
returnKeyType='done'
|
||||||
autoCapitalize='none'
|
autoCapitalize='none'
|
||||||
|
|
||||||
underlineColorAndroid='transparent'
|
underlineColorAndroid='transparent'
|
||||||
onSubmitEditing={this.submit}
|
onSubmitEditing={this.submit}
|
||||||
placeholder={this.props.Accounts_PasswordPlaceholder || 'Password'}
|
placeholder={this.props.Accounts_PasswordPlaceholder || 'Password'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{this.renderTOTP()}
|
{this.renderTOTP()}
|
||||||
|
|
||||||
<TouchableOpacity style={styles.buttonContainer}>
|
<TouchableOpacity style={styles.buttonContainer}>
|
||||||
<Text style={styles.button} onPress={this.submit}>LOGIN</Text>
|
<Text style={styles.button} onPress={this.submit}>LOGIN</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
{this.props.login.error && <Text style={styles.error}>{this.props.login.error}</Text>}
|
|
||||||
|
<TouchableOpacity style={[styles.buttonContainer, styles.registerContainer]}>
|
||||||
|
<Text style={styles.button} onPress={this.register}>REGISTER</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
{this.props.login.failure && <Text style={styles.error}>{this.props.login.error.reason}</Text>}
|
||||||
</View>
|
</View>
|
||||||
<Spinner visible={this.props.login.isFetching} textContent={'Loading...'} textStyle={{ color: '#FFF' }} />
|
<Spinner visible={this.props.login.isFetching} textContent={'Loading...'} textStyle={{ color: '#FFF' }} />
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Text, TextInput, View, StyleSheet } from 'react-native';
|
import { Text, TextInput, View, StyleSheet, Dimensions } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { serverRequest, addServer } from '../actions/server';
|
import { serverRequest, addServer } from '../actions/server';
|
||||||
import KeyboardView from '../presentation/KeyboardView';
|
import KeyboardView from '../presentation/KeyboardView';
|
||||||
|
@ -148,7 +148,11 @@ export default class NewServerView extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<KeyboardView style={styles.view} keyboardVerticalOffset={64}>
|
<KeyboardView
|
||||||
|
scrollEnabled={false}
|
||||||
|
contentContainerStyle={[styles.view, { height: Dimensions.get('window').height }]}
|
||||||
|
keyboardVerticalOffset={128}
|
||||||
|
>
|
||||||
<View style={styles.spaceView} />
|
<View style={styles.spaceView} />
|
||||||
<TextInput
|
<TextInput
|
||||||
ref={ref => this.inputElement = ref}
|
ref={ref => this.inputElement = ref}
|
||||||
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Spinner from 'react-native-loading-spinner-overlay';
|
||||||
|
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Keyboard, Text, TextInput, View, TouchableOpacity } from 'react-native';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
import * as loginActions from '../actions/login';
|
||||||
|
import KeyboardView from '../presentation/KeyboardView';
|
||||||
|
|
||||||
|
import styles from './Styles';
|
||||||
|
|
||||||
|
const placeholderTextColor = 'rgba(255,255,255,.2)';
|
||||||
|
|
||||||
|
class RegisterView extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
registerSubmit: PropTypes.func.isRequired,
|
||||||
|
setUsernameSubmit: PropTypes.func,
|
||||||
|
Accounts_UsernamePlaceholder: PropTypes.string,
|
||||||
|
Accounts_NamePlaceholder: PropTypes.string,
|
||||||
|
Accounts_EmailOrUsernamePlaceholder: PropTypes.string,
|
||||||
|
Accounts_PasswordPlaceholder: PropTypes.string,
|
||||||
|
Accounts_RepeatPasswordPlaceholder: PropTypes.string,
|
||||||
|
login: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
name: '',
|
||||||
|
email: '',
|
||||||
|
password: '',
|
||||||
|
confirmPassword: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_valid() {
|
||||||
|
const { name, email, password, confirmPassword } = this.state;
|
||||||
|
return name.trim() && email.trim() &&
|
||||||
|
password && confirmPassword && password === confirmPassword;
|
||||||
|
}
|
||||||
|
_invalidEmail() {
|
||||||
|
return this.props.login.failure && /Email/.test(this.props.login.error.reason);
|
||||||
|
}
|
||||||
|
submit = () => {
|
||||||
|
const { name, email, password, code } = this.state;
|
||||||
|
if (!this._valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.registerSubmit({ name, email, pass: password, code });
|
||||||
|
Keyboard.dismiss();
|
||||||
|
}
|
||||||
|
usernameSubmit = () => {
|
||||||
|
const { username } = this.state;
|
||||||
|
if (!username) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.setUsernameSubmit({ username });
|
||||||
|
Keyboard.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderRegister() {
|
||||||
|
if (this.props.login.token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<View style={styles.formContainer}>
|
||||||
|
<TextInput
|
||||||
|
ref={(e) => { this.name = e; }}
|
||||||
|
style={styles.input_white}
|
||||||
|
onChangeText={name => this.setState({ name })}
|
||||||
|
autoCorrect={false}
|
||||||
|
autoFocus
|
||||||
|
returnKeyType='next'
|
||||||
|
autoCapitalize='none'
|
||||||
|
underlineColorAndroid='transparent'
|
||||||
|
onSubmitEditing={() => { this.email.focus(); }}
|
||||||
|
placeholder={this.props.Accounts_NamePlaceholder || 'Name'}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
ref={(e) => { this.email = e; }}
|
||||||
|
style={[styles.input_white, this._invalidEmail() ? { borderColor: 'red' } : {}]}
|
||||||
|
onChangeText={email => this.setState({ email })}
|
||||||
|
keyboardType='email-address'
|
||||||
|
autoCorrect={false}
|
||||||
|
returnKeyType='next'
|
||||||
|
autoCapitalize='none'
|
||||||
|
underlineColorAndroid='transparent'
|
||||||
|
onSubmitEditing={() => { this.password.focus(); }}
|
||||||
|
placeholder={this.props.Accounts_EmailOrUsernamePlaceholder || 'Email'}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
ref={(e) => { this.password = e; }}
|
||||||
|
style={styles.input_white}
|
||||||
|
onChangeText={password => this.setState({ password })}
|
||||||
|
secureTextEntry
|
||||||
|
autoCorrect={false}
|
||||||
|
returnKeyType='next'
|
||||||
|
autoCapitalize='none'
|
||||||
|
underlineColorAndroid='transparent'
|
||||||
|
onSubmitEditing={() => { this.confirmPassword.focus(); }}
|
||||||
|
placeholder={this.props.Accounts_PasswordPlaceholder || 'Password'}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
ref={(e) => { this.confirmPassword = e; }}
|
||||||
|
style={[styles.input_white, this.state.password && this.state.confirmPassword && this.state.confirmPassword !== this.state.password ? { borderColor: 'red' } : {}]}
|
||||||
|
onChangeText={confirmPassword => this.setState({ confirmPassword })}
|
||||||
|
secureTextEntry
|
||||||
|
autoCorrect={false}
|
||||||
|
returnKeyType='done'
|
||||||
|
autoCapitalize='none'
|
||||||
|
underlineColorAndroid='transparent'
|
||||||
|
onSubmitEditing={this.submit}
|
||||||
|
placeholder={this.props.Accounts_RepeatPasswordPlaceholder || 'Repeat Password'}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TouchableOpacity style={[styles.buttonContainer, styles.registerContainer]}>
|
||||||
|
<Text
|
||||||
|
style={[styles.button, this._valid() ? {}
|
||||||
|
: { color: placeholderTextColor }
|
||||||
|
]}
|
||||||
|
onPress={this.submit}
|
||||||
|
>REGISTER</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
{this.props.login.failure && <Text style={styles.error}>{this.props.login.error.reason}</Text>}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderUsername() {
|
||||||
|
if (!this.props.login.token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<View style={styles.formContainer}>
|
||||||
|
<TextInput
|
||||||
|
ref={(e) => { this.username = e; }}
|
||||||
|
style={styles.input_white}
|
||||||
|
onChangeText={username => this.setState({ username })}
|
||||||
|
autoCorrect={false}
|
||||||
|
returnKeyType='next'
|
||||||
|
autoCapitalize='none'
|
||||||
|
underlineColorAndroid='transparent'
|
||||||
|
onSubmitEditing={() => { this.usernameSubmit(); }}
|
||||||
|
placeholder={this.props.Accounts_UsernamePlaceholder || 'Username'}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TouchableOpacity style={[styles.buttonContainer, styles.registerContainer]}>
|
||||||
|
<Text
|
||||||
|
style={styles.button}
|
||||||
|
onPress={this.usernameSubmit}
|
||||||
|
>REGISTER</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
{this.props.login.failure && <Text style={styles.error}>{this.props.login.error.reason}</Text>}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<KeyboardView contentContainerStyle={styles.container}>
|
||||||
|
<View style={styles.loginView}>
|
||||||
|
{this._renderRegister()}
|
||||||
|
{this._renderUsername()}
|
||||||
|
<Spinner visible={this.props.login.isFetching} textContent={'Loading...'} textStyle={{ color: '#FFF' }} />
|
||||||
|
</View>
|
||||||
|
</KeyboardView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state) {
|
||||||
|
return {
|
||||||
|
server: state.server.server,
|
||||||
|
Accounts_NamePlaceholder: state.settings.Accounts_NamePlaceholder,
|
||||||
|
Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder,
|
||||||
|
Accounts_PasswordPlaceholder: state.settings.Accounts_PasswordPlaceholder,
|
||||||
|
Accounts_RepeatPasswordPlaceholder: state.settings.Accounts_RepeatPasswordPlaceholder,
|
||||||
|
login: state.login
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch) {
|
||||||
|
return bindActionCreators(loginActions, dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(RegisterView);
|
|
@ -193,7 +193,7 @@ export default class RoomView extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<KeyboardView style={styles.container} keyboardVerticalOffset={64}>
|
<KeyboardView contentContainerStyle={styles.container} keyboardVerticalOffset={64}>
|
||||||
{this.renderBanner()}
|
{this.renderBanner()}
|
||||||
<ListView
|
<ListView
|
||||||
enableEmptySections
|
enableEmptySections
|
||||||
|
|
|
@ -2,11 +2,8 @@ import { StyleSheet, Dimensions } from 'react-native';
|
||||||
|
|
||||||
export default StyleSheet.create({
|
export default StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
backgroundColor: 'white',
|
||||||
backgroundColor: '#2f343d',
|
flex: 1
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'stretch'
|
|
||||||
},
|
},
|
||||||
loginView: {
|
loginView: {
|
||||||
padding: 20
|
padding: 20
|
||||||
|
@ -19,29 +16,31 @@ export default StyleSheet.create({
|
||||||
alignItems: 'stretch',
|
alignItems: 'stretch',
|
||||||
backgroundColor: '#2f343d'
|
backgroundColor: '#2f343d'
|
||||||
},
|
},
|
||||||
view_white: {
|
defaultView: {
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
padding: 20,
|
padding: 20,
|
||||||
alignItems: 'stretch',
|
alignItems: 'stretch'
|
||||||
|
},
|
||||||
|
defaultViewBackground: {
|
||||||
backgroundColor: '#fff'
|
backgroundColor: '#fff'
|
||||||
},
|
},
|
||||||
logoContainer: {
|
logoContainer: {
|
||||||
flex: 1,
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
flexGrow: 1,
|
justifyContent: 'center',
|
||||||
justifyContent: 'center'
|
flex: 1
|
||||||
},
|
},
|
||||||
logo: {
|
loginLogo: {
|
||||||
width: Dimensions.get('window').width - 30,
|
width: Dimensions.get('window').width - 150,
|
||||||
height: Dimensions.get('window').width - 30,
|
height: Dimensions.get('window').width - 150,
|
||||||
borderRadius: 5,
|
|
||||||
resizeMode: 'contain'
|
resizeMode: 'contain'
|
||||||
},
|
},
|
||||||
formContainer: {
|
registerLogo: {
|
||||||
// marginBottom: 20
|
width: Dimensions.get('window').width - 40,
|
||||||
|
height: 100,
|
||||||
|
resizeMode: 'contain'
|
||||||
},
|
},
|
||||||
|
formContainer: {},
|
||||||
label: {
|
label: {
|
||||||
lineHeight: 40,
|
lineHeight: 40,
|
||||||
height: 40,
|
height: 40,
|
||||||
|
@ -94,6 +93,9 @@ export default StyleSheet.create({
|
||||||
backgroundColor: '#1d74f5',
|
backgroundColor: '#1d74f5',
|
||||||
marginBottom: 20
|
marginBottom: 20
|
||||||
},
|
},
|
||||||
|
registerContainer: {
|
||||||
|
marginBottom: 0
|
||||||
|
},
|
||||||
button: {
|
button: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
color: 'white',
|
color: 'white',
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
"react-native-fetch-blob": "^0.10.8",
|
"react-native-fetch-blob": "^0.10.8",
|
||||||
"react-native-image-picker": "^0.26.4",
|
"react-native-image-picker": "^0.26.4",
|
||||||
"react-native-img-cache": "^1.4.0",
|
"react-native-img-cache": "^1.4.0",
|
||||||
|
"react-native-keyboard-aware-scroll-view": "^0.3.0",
|
||||||
"react-native-loading-spinner-overlay": "^0.5.2",
|
"react-native-loading-spinner-overlay": "^0.5.2",
|
||||||
"react-native-meteor": "^1.1.0",
|
"react-native-meteor": "^1.1.0",
|
||||||
"react-native-modal": "^3.1.0",
|
"react-native-modal": "^3.1.0",
|
||||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -2055,7 +2055,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
|
||||||
safe-buffer "^5.0.1"
|
safe-buffer "^5.0.1"
|
||||||
sha.js "^2.4.8"
|
sha.js "^2.4.8"
|
||||||
|
|
||||||
create-react-class@^15.5.2:
|
create-react-class@^15.5.2, create-react-class@^15.6.0:
|
||||||
version "15.6.0"
|
version "15.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.0.tgz#ab448497c26566e1e29413e883207d57cfe7bed4"
|
resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.0.tgz#ab448497c26566e1e29413e883207d57cfe7bed4"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -5729,6 +5729,14 @@ react-native-img-cache@^1.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
crypto-js "^3.1.9-1"
|
crypto-js "^3.1.9-1"
|
||||||
|
|
||||||
|
react-native-keyboard-aware-scroll-view@^0.3.0:
|
||||||
|
version "0.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-native-keyboard-aware-scroll-view/-/react-native-keyboard-aware-scroll-view-0.3.0.tgz#b9d7b0d5b47d2bb4285fe50a3d274b10a3b5e1a7"
|
||||||
|
dependencies:
|
||||||
|
create-react-class "^15.6.0"
|
||||||
|
prop-types "^15.5.10"
|
||||||
|
react-timer-mixin "^0.13.3"
|
||||||
|
|
||||||
react-native-loading-spinner-overlay@^0.5.2:
|
react-native-loading-spinner-overlay@^0.5.2:
|
||||||
version "0.5.2"
|
version "0.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-loading-spinner-overlay/-/react-native-loading-spinner-overlay-0.5.2.tgz#b7bcd277476d596615fd7feee601789f9bdc7acc"
|
resolved "https://registry.yarnpkg.com/react-native-loading-spinner-overlay/-/react-native-loading-spinner-overlay-0.5.2.tgz#b7bcd277476d596615fd7feee601789f9bdc7acc"
|
||||||
|
@ -5943,7 +5951,7 @@ react-test-renderer@16.0.0-alpha.12:
|
||||||
fbjs "^0.8.9"
|
fbjs "^0.8.9"
|
||||||
object-assign "^4.1.0"
|
object-assign "^4.1.0"
|
||||||
|
|
||||||
react-timer-mixin@^0.13.2:
|
react-timer-mixin@^0.13.2, react-timer-mixin@^0.13.3:
|
||||||
version "0.13.3"
|
version "0.13.3"
|
||||||
resolved "https://registry.yarnpkg.com/react-timer-mixin/-/react-timer-mixin-0.13.3.tgz#0da8b9f807ec07dc3e854d082c737c65605b3d22"
|
resolved "https://registry.yarnpkg.com/react-timer-mixin/-/react-timer-mixin-0.13.3.tgz#0da8b9f807ec07dc3e854d082c737c65605b3d22"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue