diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js
index 1ce10d23b..0aca14405 100644
--- a/app/actions/actionsTypes.js
+++ b/app/actions/actionsTypes.js
@@ -12,11 +12,11 @@ function createRequestTypes(base, types = defaultTypes) {
// Login events
export const LOGIN = createRequestTypes('LOGIN', [...defaultTypes, 'SET_TOKEN', 'SUBMIT']);
export const ROOMS = createRequestTypes('ROOMS');
-export const APP = createRequestTypes('APP', ['READY']);
+export const APP = createRequestTypes('APP', ['READY', 'INIT']);
export const MESSAGES = createRequestTypes('MESSAGES');
-export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL');
+export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL', [...defaultTypes, 'REQUEST_USERS', 'SUCCESS_USERS', 'FAILURE_USERS', 'SET_USERS']);
export const NAVIGATION = createRequestTypes('NAVIGATION', ['SET']);
-export const SERVER = createRequestTypes('SERVER', ['SELECT', 'CHANGED']);
+export const SERVER = createRequestTypes('SERVER', [...defaultTypes, 'SELECT', 'CHANGED', 'ADD']);
export const METEOR = createRequestTypes('METEOR_CONNECT', [...defaultTypes, 'DISCONNECT']);
export const LOGOUT = 'LOGOUT'; // logout is always success
diff --git a/app/actions/createChannel.js b/app/actions/createChannel.js
index 60a8cca30..df4cad35a 100644
--- a/app/actions/createChannel.js
+++ b/app/actions/createChannel.js
@@ -20,3 +20,32 @@ export function createChannelFailure(err) {
err
};
}
+
+
+export function createChannelRequestUsers(data) {
+ return {
+ type: types.CREATE_CHANNEL.REQUEST_USERS,
+ data
+ };
+}
+
+export function createChannelSetUsers(data) {
+ return {
+ type: types.CREATE_CHANNEL.SET_USERS,
+ data
+ };
+}
+
+export function createChannelSuccessUsers(data) {
+ return {
+ type: types.CREATE_CHANNEL.SUCCESS_USERS,
+ data
+ };
+}
+
+export function createChannelFailureUsers(err) {
+ return {
+ type: types.CREATE_CHANNEL.FAILURE_USERS,
+ err
+ };
+}
diff --git a/app/actions/index.js b/app/actions/index.js
index 75a05545f..35af27309 100644
--- a/app/actions/index.js
+++ b/app/actions/index.js
@@ -6,6 +6,12 @@ export function appReady() {
type: APP.READY
};
}
+
+export function appInit() {
+ return {
+ type: APP.INIT
+ };
+}
export function setCurrentServer(server) {
return {
type: types.SET_CURRENT_SERVER,
diff --git a/app/actions/login.js b/app/actions/login.js
index cffc3cdda..7969c8090 100644
--- a/app/actions/login.js
+++ b/app/actions/login.js
@@ -28,7 +28,7 @@ export function loginFailure(err) {
};
}
-export function setToken(user) {
+export function setToken(user = {}) {
return {
type: types.LOGIN.SET_TOKEN,
token: user.token,
diff --git a/app/actions/server.js b/app/actions/server.js
index 230b4cd06..9f0efeed1 100644
--- a/app/actions/server.js
+++ b/app/actions/server.js
@@ -6,6 +6,37 @@ export function setServer(server) {
server
};
}
+export function serverRequest(server) {
+ console.log(server);
+ return {
+ type: SERVER.REQUEST,
+ server
+ };
+}
+
+export function addServer(server) {
+ console.log(server);
+ return {
+ type: SERVER.ADD,
+ server
+ };
+}
+
+
+export function serverSuccess() {
+ return {
+ type: SERVER.SUCCESS
+ };
+}
+
+export function serverFailure(err) {
+ return {
+ type: SERVER.FAILURE,
+ err
+ };
+}
+
+
export function changedServer(server) {
return {
type: SERVER.CHANGED,
diff --git a/app/components/Message.js b/app/components/Message.js
index 6a2523fcf..b1dee59ed 100644
--- a/app/components/Message.js
+++ b/app/components/Message.js
@@ -1,12 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
import { View, Text, StyleSheet } from 'react-native';
-import { CachedImage } from 'react-native-img-cache';
import { emojify } from 'react-emojione';
import Markdown from 'react-native-easy-markdown';
import moment from 'moment';
-
-import avatarInitialsAndColor from '../utils/avatarInitialsAndColor';
+import Avatar from './avatar';
import Card from './message/card';
const styles = StyleSheet.create({
@@ -20,26 +18,6 @@ const styles = StyleSheet.create({
flexDirection: 'row',
transform: [{ scaleY: -1 }]
},
- avatarContainer: {
- backgroundColor: '#eee',
- width: 40,
- height: 40,
- marginRight: 10,
- borderRadius: 5
- },
- avatar: {
- width: 40,
- height: 40,
- borderRadius: 5,
- position: 'absolute'
- },
- avatarInitials: {
- margin: 2,
- textAlign: 'center',
- lineHeight: 36,
- fontSize: 22,
- color: '#ffffff'
- },
texts: {
flex: 1
},
@@ -87,33 +65,17 @@ export default class Message extends React.PureComponent {
const username = item.alias || item.u.username;
- let { initials, color } = avatarInitialsAndColor(username);
-
- const avatar = item.avatar || `${ this.props.baseUrl }/avatar/${ item.u.username }`;
- if (item.avatar) {
- initials = '';
- color = 'transparent';
- }
-
- let aliasUsername;
- if (item.alias) {
- aliasUsername = @{item.u.username};
- }
-
const time = moment(item.ts).format(this.props.Message_TimeFormat);
return (
-
- {initials}
-
-
+
{username}
- {aliasUsername}{time}
+ {item.alias && @{item.u.username}}{time}
{this.attachments()}
diff --git a/app/components/RoomItem.js b/app/components/RoomItem.js
index 7737e03f3..b1957787e 100644
--- a/app/components/RoomItem.js
+++ b/app/components/RoomItem.js
@@ -1,9 +1,8 @@
import React from 'react';
-import { CachedImage } from 'react-native-img-cache';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import PropTypes from 'prop-types';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
-
+import Avatar from './avatar';
import avatarInitialsAndColor from '../utils/avatarInitialsAndColor';
const styles = StyleSheet.create({
@@ -81,12 +80,8 @@ export default class RoomItem extends React.PureComponent {
}
if (type === 'd') {
- const { initials, color } = avatarInitialsAndColor(name);
return (
-
- {initials}
-
-
+
);
}
diff --git a/app/components/avatar.js b/app/components/avatar.js
index 8ecd3ad10..8cc05a7fc 100644
--- a/app/components/avatar.js
+++ b/app/components/avatar.js
@@ -4,49 +4,48 @@ import { StyleSheet, Text, View } from 'react-native';
import { CachedImage } from 'react-native-img-cache';
import avatarInitialsAndColor from '../utils/avatarInitialsAndColor';
+const styles = StyleSheet.create({
+ iconContainer: {
+ overflow: 'hidden',
+ justifyContent: 'center',
+ alignItems: 'center'
+ },
+ avatar: {
+ position: 'absolute'
+ },
+ avatarInitials: {
+ color: '#ffffff'
+ } });
-const styles = StyleSheet.create({ iconContainer: {
- height: 40,
- width: 40,
- borderRadius: 20,
- overflow: 'hidden',
- justifyContent: 'center',
- alignItems: 'center'
-},
-icon: {
- fontSize: 20,
- color: '#fff'
-},
-avatar: {
- width: 40,
- height: 40,
- position: 'absolute'
-},
-avatarInitials: {
- fontSize: 20,
- color: '#ffffff'
-} });
+class Avatar extends React.PureComponent {
+ render() {
+ const { text = '', size = 25, baseUrl = this.props.baseUrl,
+ borderRadius = 5, style, avatar } = this.props;
+ const { initials, color } = avatarInitialsAndColor(`${ text }`);
+ return (
+
+ {initials}
+ { (avatar || baseUrl) && }
+ );
+ }
+}
-
-const avatar = ({ text = '', width = 25, height = 25, fontSize = 12, baseUrl,
- borderRadius = 2, style }) => {
- const { initials, color } = avatarInitialsAndColor(`${ text }`);
- return (
-
- {initials}
- { baseUrl ? : null}
- );
-};
-
-avatar.propTypes = {
+Avatar.propTypes = {
+ style: PropTypes.object,
baseUrl: PropTypes.string,
text: PropTypes.string.isRequired,
- width: PropTypes.number,
- fontSize: PropTypes.number,
- height: PropTypes.number,
+ avatar: PropTypes.string,
+ size: PropTypes.number,
borderRadius: PropTypes.number
};
-export default avatar;
+export default Avatar;
diff --git a/app/components/tags.js b/app/components/tags.js
index 2eec8def4..4700ddab4 100644
--- a/app/components/tags.js
+++ b/app/components/tags.js
@@ -74,8 +74,8 @@ const styles = StyleSheet.create({
const renderTag = (item, index) => (- this.props.onPress(item, index)} />);
-const renderItemResult = ({ item = '' }) => (
-
+const renderItemResult = ({ item = '', onPress }) => (
+
@{item}
);
@@ -102,11 +102,11 @@ export default class tags extends React.PureComponent {
onChangeText={this.props.onChangeText}
/>
- {this.props.result ? item}
style={styles.result}
data={this.props.result || []}
- renderItem={this.props.renderItemResult || renderItemResult}
+ renderItem={e => (this.props.renderItemResult || renderItemResult)(e, this.props.onSelect)}
/> : null}
);
}
diff --git a/app/index.js b/app/index.js
index 394d881ab..c76830ae5 100644
--- a/app/index.js
+++ b/app/index.js
@@ -1,11 +1,16 @@
import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
-import { Text } from 'react-native';
+import * as Animatable from 'react-native-animatable';
import setNavigator from './actions/navigator';
+import { appInit } from './actions';
import LoginView from './views/login';
import ListServerView from './views/serverList';
+import { Keyboard, Text, TextInput, View, Image, TouchableOpacity } from 'react-native';
+
+import styles from './views/Styles';
+
import store from './lib/createStore';
//
@@ -22,16 +27,16 @@ export const authenticated = WrappedComponent => class _p extends React.PureComp
constructor() {
super();
this.login = store.getState().login;
- console.log('this.login.token', this.login.token);
if (!this.login.token || this.login.failure) {
return store.getState().navigator.resetTo({
- screen: 'Login'
+ screen: 'Login',
+ animationType: 'none'
});
}
}
render() {
// Wraps the input component in a container, without mutating it. Good!
- return ;
+ return ((this.login.isAuthenticated || this.login.user) && );
}
};
//
@@ -43,7 +48,7 @@ export class PublicScreen extends React.PureComponent {
// }
// }
render() {
- return !this.login.isAuthenticated || !this.login.user ? null : ();
+ return ((this.login.isAuthenticated || this.login.user) && );
}
}
@@ -66,21 +71,29 @@ export class PrivateScreen extends React.PureComponent {
// logged: state.login.isAuthenticated
}), dispatch => ({
// navigate: routeName => dispatch(NavigationActions.navigate({ routeName })),
- setNavigator: navigator => dispatch(setNavigator(navigator))
+ setNavigator: navigator => dispatch(setNavigator(navigator)),
+ appInit: () => dispatch(appInit())
}))
export const HomeScreen = class extends React.PureComponent {
static propTypes = {
setNavigator: PropTypes.func.isRequired,
navigator: PropTypes.object.isRequired
}
-
+ static navigatorStyle = {
+ navBarHidden: true
+ };
componentWillMount() {
this.props.setNavigator(this.props.navigator);
- this.props.navigator.resetTo({
- screen: 'public'
- });
+ this.props.appInit();
+ //
+ // this.props.navigator.setDrawerEnabled({
+ // side: 'left', // the side of the drawer since you can have two, 'left' / 'right'
+ // enabled: false // should the drawer be enabled or disabled (locked closed)
+ // });
}
render() {
- return (oieee);
+ return (
+
+ );
}
};
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index 22647b488..7de5aadcc 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -23,12 +23,8 @@ const call = (method, ...params) => new Promise((resolve, reject) => {
const RocketChat = {
createChannel({ name, users, type }) {
- console.log('FISTALEU', { name, users, type });
return new Promise((resolve, reject) => {
- Meteor.call(type ? 'createChannel' : 'createPrivateGroup', name, users, type, (err, res) => {
- console.log(err, res);
- return (err ? reject(err) : resolve(res));
- });
+ Meteor.call(type ? 'createChannel' : 'createPrivateGroup', name, users, type, (err, res) => (err ? reject(err) : resolve(res)));
});
},
@@ -40,7 +36,15 @@ const RocketChat = {
console.warn(`AsyncStorage error: ${ error.message }`);
}
},
-
+ async testServer(url) {
+ if (/^(https?:\/\/)?(((\w|[0-9])+(\.(\w|[0-9-_])+)+)|localhost)(:\d+)?$/.test(url)) {
+ const response = await fetch(url, { method: 'HEAD' });
+ if (response.status === 200 && response.headers.get('x-instance-id') != null && response.headers.get('x-instance-id').length) {
+ return url;
+ }
+ }
+ throw new Error({ error: 'invalid server' });
+ },
connect(_url) {
return new Promise((resolve) => {
const url = `${ _url }/websocket`;
@@ -69,7 +73,7 @@ const RocketChat = {
const setting = {
_id: item._id
};
- setting._server = { id: reduxStore.getState().server };
+ setting._server = { id: reduxStore.getState().server.server };
if (settingsType[item.type]) {
setting[settingsType[item.type]] = item.value;
realm.create('settings', setting, true);
@@ -87,7 +91,7 @@ const RocketChat = {
realm.write(() => {
const message = ddbMessage.fields.args[0];
message.temp = false;
- message._server = { id: reduxStore.getState().server };
+ message._server = { id: reduxStore.getState().server.server };
// write('messages', message);
realm.create('messages', message, true);
});
@@ -97,7 +101,7 @@ const RocketChat = {
// console.log(ddbMessage);
realm.write(() => {
const data = ddbMessage.fields.args[1];
- data._server = { id: reduxStore.getState().server };
+ data._server = { id: reduxStore.getState().server.server };
realm.create('subscriptions', data, true);
});
}
@@ -108,13 +112,11 @@ const RocketChat = {
},
login(params, callback) {
- console.log('login(params, callback)');
return new Promise((resolve, reject) => {
Meteor._startLoggingIn();
return Meteor.call('login', params, (err, result) => {
Meteor._endLoggingIn();
Meteor._handleLoginCallback(err, result);
- console.log('login(params, callback)asdas', err, result);
if (err) {
reject(err);
} else {
@@ -183,7 +185,7 @@ const RocketChat = {
// if (typeof item.value === 'string') {
// subscription.value = item.value;
// }
- subscription._server = { id: reduxStore.getState().server };
+ subscription._server = { id: reduxStore.getState().server.server };
// write('subscriptions', subscription);
realm.create('subscriptions', subscription, true);
});
@@ -207,7 +209,7 @@ const RocketChat = {
realm.write(() => {
data.messages.forEach((message) => {
message.temp = false;
- message._server = { id: reduxStore.getState().server };
+ message._server = { id: reduxStore.getState().server.server };
// write('messages', message);
realm.create('messages', message, true);
});
@@ -237,7 +239,7 @@ const RocketChat = {
ts: new Date(),
_updatedAt: new Date(),
temp: true,
- _server: { id: reduxStore.getState().server },
+ _server: { id: reduxStore.getState().server.server },
u: {
_id: reduxStore.getState().login.user.id || '1',
username: reduxStore.getState().login.user.id
@@ -381,7 +383,6 @@ const RocketChat = {
return subscription;
});
// Meteor.subscribe('stream-notify-user', `${ Meteor.userId() }/rooms-changed`, false);
- console.log('getRooms resolved', reduxStore.getState().server, data);
realm.write(() => {
data.forEach((subscription) => {
// const subscription = {
@@ -390,7 +391,7 @@ const RocketChat = {
// if (typeof item.value === 'string') {
// subscription.value = item.value;
// }
- subscription._server = { id: reduxStore.getState().server };
+ subscription._server = { id: reduxStore.getState().server.server };
// write('subscriptions', subscription);
realm.create('subscriptions', subscription, true);
});
diff --git a/app/reducers/server.js b/app/reducers/server.js
index 8ee296cd5..ea0315e25 100644
--- a/app/reducers/server.js
+++ b/app/reducers/server.js
@@ -1,9 +1,36 @@
import { SERVER } from '../actions/actionsTypes';
-export default function server(state = '', action) {
+const initialState = {
+ connecting: false,
+ connected: false,
+ errorMessage: '',
+ failure: false,
+ server: ''
+};
+
+
+export default function server(state = initialState, action) {
switch (action.type) {
+ case SERVER.REQUEST:
+ return { ...state,
+ connecting: true,
+ failure: false
+ };
+ case SERVER.SUCCESS:
+ return { ...state,
+ connecting: false,
+ connected: true,
+ failure: false
+ };
+ case SERVER.FAILURE:
+ return { ...state,
+ connecting: false,
+ connected: false,
+ failure: true,
+ errorMessage: action.err
+ };
case SERVER.SELECT:
- return action.server;
+ return { ...state, server: action.server };
default:
return state;
}
diff --git a/app/sagas/connect.js b/app/sagas/connect.js
index 4a8ac45f3..3b0c6f793 100644
--- a/app/sagas/connect.js
+++ b/app/sagas/connect.js
@@ -1,10 +1,10 @@
-import { take, put, call, fork, takeLatest, select } from 'redux-saga/effects';
+import { put, call, takeLatest, select } from 'redux-saga/effects';
import { METEOR } from '../actions/actionsTypes';
import RocketChat from '../lib/rocketchat';
import { connectSuccess, connectFailure } from '../actions/connect';
-const getServer = ({ server }) => server;
+const getServer = ({ server }) => server.server;
const connect = url => RocketChat.connect(url);
@@ -17,14 +17,11 @@ const test = function* test() {
yield put(connectFailure(err.status));
}
};
-const watchConnect = function* watchConnect() {
- yield takeLatest(METEOR.REQUEST, test);
- while (true) {
- yield take(METEOR.DISCONNECT);
- }
-};
+// const watchConnect = function* watchConnect() {
+// };
const root = function* root() {
- yield fork(watchConnect);
+ yield takeLatest(METEOR.REQUEST, test);
+ // yield fork(watchConnect);
// yield fork(auto);
};
export default root;
diff --git a/app/sagas/init.js b/app/sagas/init.js
index b06120211..ceedb0509 100644
--- a/app/sagas/init.js
+++ b/app/sagas/init.js
@@ -1,13 +1,22 @@
import { AsyncStorage } from 'react-native';
-import { call, put } from 'redux-saga/effects';
+import { call, put, select, take } from 'redux-saga/effects';
import * as actions from '../actions';
import { setServer } from '../actions/server';
+import { APP } from '../actions/actionsTypes';
const restore = function* restore() {
try {
+ yield take(APP.INIT);
+ const { navigator } = yield select(state => state);
const currentServer = yield call([AsyncStorage, 'getItem'], 'currentServer');
yield put(actions.appReady({}));
- if (currentServer) { yield put(setServer(currentServer)); }
+ if (currentServer) {
+ yield put(setServer(currentServer));
+ } else {
+ navigator.resetTo({
+ screen: 'ListServer'
+ });
+ }
} catch (e) {
console.log(e);
}
diff --git a/app/sagas/login.js b/app/sagas/login.js
index b21d2503e..b987d4f39 100644
--- a/app/sagas/login.js
+++ b/app/sagas/login.js
@@ -1,12 +1,12 @@
import { AsyncStorage } from 'react-native';
import { take, put, call, takeEvery, fork, select, all, race } from 'redux-saga/effects';
import * as types from '../actions/actionsTypes';
-import { loginRequest, loginSuccess, loginFailure, setToken } from '../actions/login';
+import { loginRequest, loginSuccess, loginFailure, setToken, logout } from '../actions/login';
import RocketChat from '../lib/rocketchat';
const TOKEN_KEY = 'reactnativemeteor_usertoken';
const getUser = state => state.login;
-const getServer = state => state.server;
+const getServer = state => state.server.server;
const loginCall = args => (args.resume ? RocketChat.login(args) : RocketChat.loginWithPassword(args));
const getToken = function* getToken() {
@@ -20,6 +20,8 @@ const getToken = function* getToken() {
} catch (e) {
console.log('getTokenerr', e);
}
+ } else {
+ yield put(setToken());
}
};
@@ -27,10 +29,9 @@ const handleLoginWhenServerChanges = function* handleLoginWhenServerChanges() {
// do {
try {
yield take(types.METEOR.SUCCESS);
+ yield call(getToken);
const { navigator } = yield select(state => state);
- navigator.resetTo({
- screen: 'Rooms'
- });
+
const user = yield select(getUser);
if (user.token) {
yield put(loginRequest({ resume: user.token }));
@@ -47,6 +48,9 @@ const handleLoginWhenServerChanges = function* handleLoginWhenServerChanges() {
// });
// }
}
+ navigator.resetTo({
+ screen: 'Rooms'
+ });
} catch (e) {
console.log(e);
}
@@ -66,8 +70,11 @@ const handleLoginRequest = function* handleLoginRequest() {
const response = yield call(loginCall, credentials);
yield put(loginSuccess(response));
} catch (err) {
- // console.log('login failed');
- yield put(loginFailure(err));
+ if (err.error === 403) {
+ yield put(logout());
+ } else {
+ yield put(loginFailure(err));
+ }
}
}
};
@@ -93,7 +100,6 @@ const handleLoginSubmit = function* handleLoginSubmit() {
};
const root = function* root() {
- yield takeEvery(types.SERVER.CHANGED, getToken);
yield takeEvery(types.SERVER.CHANGED, handleLoginWhenServerChanges);
yield fork(handleLoginRequest);
yield takeEvery(types.LOGIN.SUCCESS, saveToken);
diff --git a/app/sagas/selectServer.js b/app/sagas/selectServer.js
index de45cd34c..35c3177ae 100644
--- a/app/sagas/selectServer.js
+++ b/app/sagas/selectServer.js
@@ -7,7 +7,6 @@ import { changedServer } from '../actions/server';
const selectServer = function* selectServer({ server }) {
yield put(disconnect());
yield put(changedServer(server));
- yield console.log('SERVER->', server);
yield call([AsyncStorage, 'setItem'], 'currentServer', server);
yield put(connectRequest(server));
};
diff --git a/app/utils/avatarInitialsAndColor.js b/app/utils/avatarInitialsAndColor.js
index 09c41fb1d..13029c66c 100644
--- a/app/utils/avatarInitialsAndColor.js
+++ b/app/utils/avatarInitialsAndColor.js
@@ -1,6 +1,12 @@
import { AVATAR_COLORS } from '../constants/colors';
export default function(username = '') {
+ if (username === '') {
+ return {
+ initials: '',
+ colors: 'transparent'
+ };
+ }
const position = username.length % AVATAR_COLORS.length;
const color = AVATAR_COLORS[position];
diff --git a/app/views/login.js b/app/views/login.js
index 1195b7c24..1c70b5490 100644
--- a/app/views/login.js
+++ b/app/views/login.js
@@ -119,7 +119,7 @@ class LoginView extends React.Component {
function mapStateToProps(state) {
// console.log(Object.keys(state));
return {
- server: state.server,
+ server: state.server.server,
Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder,
Accounts_PasswordPlaceholder: state.settings.Accounts_PasswordPlaceholder,
login: state.login
diff --git a/app/views/room.js b/app/views/room.js
index 2f0e0a29a..0060f4342 100644
--- a/app/views/room.js
+++ b/app/views/room.js
@@ -46,7 +46,7 @@ const styles = StyleSheet.create({
@connect(state => ({
- server: state.server,
+ server: state.server.server,
Site_Url: state.settings.Site_Url,
Message_TimeFormat: state.settings.Message_TimeFormat,
loading: state.messages.isFetching
diff --git a/app/views/roomsList.js b/app/views/roomsList.js
index b503bc4cb..559fbffff 100644
--- a/app/views/roomsList.js
+++ b/app/views/roomsList.js
@@ -56,10 +56,10 @@ const styles = StyleSheet.create({
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
@connect(state => ({
- server: state.server,
+ server: state.server.server,
login: state.login,
Site_Url: state.settings.Site_Url,
- canShowList: state.login.token.length || state.login.user.token
+ canShowList: state.login.token || state.login.user.token
}), dispatch => ({
login: () => dispatch(actions.login()),
connect: () => dispatch(server.connectRequest())
diff --git a/app/views/serverList.js b/app/views/serverList.js
index ec04b22c3..5bf276b08 100644
--- a/app/views/serverList.js
+++ b/app/views/serverList.js
@@ -65,7 +65,7 @@ const zeroconf = new Zeroconf();
@connect(state => ({
- server: state.server
+ server: state.server.server
}), dispatch => ({
selectServer: server => dispatch(setServer(server))
}))
diff --git a/app/views/serverNew.js b/app/views/serverNew.js
index e4eae9fdf..0cd3a38e7 100644
--- a/app/views/serverNew.js
+++ b/app/views/serverNew.js
@@ -2,9 +2,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Navigation } from 'react-native-navigation';
import { Text, TextInput, View, StyleSheet } from 'react-native';
-import _ from 'underscore';
-import realm from '../lib/realm';
-
+import { connect } from 'react-redux';
+import { serverRequest, addServer } from '../actions/server';
import KeyboardView from '../components/KeyboardView';
const styles = StyleSheet.create({
@@ -47,10 +46,17 @@ const styles = StyleSheet.create({
flexGrow: 1
}
});
-
+@connect(state => ({
+ validInstance: !state.server.failure,
+ validating: state.server.connecting
+}), dispatch => ({
+ validateServer: url => dispatch(serverRequest(url)),
+ addServer: url => dispatch(addServer(url))
+}))
export default class NewServerView extends React.Component {
static propTypes = {
- navigator: PropTypes.object.isRequired
+ navigator: PropTypes.object.isRequired,
+ validateServer: PropTypes.func.isRequired
}
static navigationOptions = () => ({
@@ -66,37 +72,11 @@ export default class NewServerView extends React.Component {
};
this.submit = () => {
- let url = this.state.text.trim();
- if (!url) {
- url = this.state.defaultServer;
- } else {
- url = this.completeUrl(this.state.text);
- }
-
- this.setState({
- editable: false
- });
-
- this.inputElement.blur();
- this.validateServer(url).then(() => {
- realm.write(() => {
- realm.create('servers', { id: url, current: false }, true);
- });
- Navigation.dismissModal({
- animationType: 'slide-down'
- });
- }).catch(() => {
- this.setState({
- editable: true
- });
- this.inputElement.focus();
- });
+ this.props.addServer(this.completeUrl(this.state.text.trim() || this.state.defaultServer));
};
}
componentDidMount() {
- this._mounted = true;
-
this.props.navigator.setTitle({
title: 'New server'
});
@@ -111,11 +91,6 @@ export default class NewServerView extends React.Component {
this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
}
-
- componentWillUnmount() {
- this._mounted = false;
- }
-
onNavigatorEvent = (event) => {
if (event.type === 'NavBarButtonPress') {
if (event.id === 'close') {
@@ -128,62 +103,8 @@ export default class NewServerView extends React.Component {
onChangeText = (text) => {
this.setState({ text });
-
- this.validateServerDebounced(text);
+ this.props.validateServer(this.completeUrl(text));
}
-
- validateServer = url => new Promise((resolve, reject) => {
- url = this.completeUrl(url);
-
- this.setState({
- validating: false,
- url
- });
-
- if (/^(https?:\/\/)?(((\w|[0-9])+(\.(\w|[0-9-_])+)+)|localhost)(:\d+)?$/.test(url)) {
- this.setState({
- validating: true
- });
-
- fetch(url, { method: 'HEAD' })
- .then((response) => {
- if (!this._mounted) {
- return;
- }
- if (response.status === 200 && response.headers.get('x-instance-id') != null && response.headers.get('x-instance-id').length) {
- this.setState({
- validInstance: true,
- validating: false
- });
- resolve(url);
- } else {
- this.setState({
- validInstance: false,
- validating: false
- });
- reject(url);
- }
- })
- .catch(() => {
- if (!this._mounted) {
- return;
- }
- this.setState({
- validInstance: false,
- validating: false
- });
- reject(url);
- });
- } else {
- this.setState({
- validInstance: undefined
- });
- reject(url);
- }
- })
-
- validateServerDebounced = _.debounce(this.validateServer, 1000)
-
completeUrl = (url) => {
url = url.trim();
@@ -203,7 +124,10 @@ export default class NewServerView extends React.Component {
}
renderValidation = () => {
- if (this.state.validating) {
+ if (!this.state.text.trim()) {
+ return null;
+ }
+ if (this.props.validating) {
return (
Validating {this.state.url} ...
@@ -211,7 +135,7 @@ export default class NewServerView extends React.Component {
);
}
- if (this.state.validInstance) {
+ if (this.props.validInstance) {
return (
{this.state.url} is a valid Rocket.Chat instance
@@ -219,7 +143,7 @@ export default class NewServerView extends React.Component {
);
}
- if (this.state.validInstance === false) {
+ if (!this.state.validInstance) {
return (
{this.state.url} is not a valid Rocket.Chat instance
diff --git a/package.json b/package.json
index 53b258670..88f21bf0a 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"react-emojione": "^3.1.10",
"react-native": "0.46.1",
"react-native-action-button": "^2.7.2",
+ "react-native-animatable": "^1.2.3",
"react-native-card-view": "0.0.3",
"react-native-easy-markdown": "git+https://github.com/lappalj4/react-native-easy-markdown.git",
"react-native-fetch-blob": "^0.10.8",
diff --git a/storybook/stories/Avatar.js b/storybook/stories/Avatar.js
new file mode 100644
index 000000000..204a38bd6
--- /dev/null
+++ b/storybook/stories/Avatar.js
@@ -0,0 +1,13 @@
+import React from 'react';
+import { ScrollView } from 'react-native';
+
+import Avatar from '../../app/components/avatar';
+
+export default (
+
+
+
+
+
+
+);
diff --git a/storybook/stories/index.js b/storybook/stories/index.js
index 4f10d5fa9..abba63548 100644
--- a/storybook/stories/index.js
+++ b/storybook/stories/index.js
@@ -8,6 +8,9 @@ import { storiesOf } from '@storybook/react-native';
import DirectMessage from './Channels/DirectMessage';
import TagInput from './TagInput';
+import Avatar from './Avatar';
+
+storiesOf('Avatar', module).add('avatar', () => Avatar);
storiesOf('Tag Input', module).add('Tag Input', () => TagInput);
storiesOf('Channel Cell', module).add('Direct Messages', () => DirectMessage);