diff --git a/.eslintrc b/.eslintrc index 95bccaf46..a55acafff 100644 --- a/.eslintrc +++ b/.eslintrc @@ -36,6 +36,7 @@ "react/forbid-prop-types": 0, "jsx-quotes": [2, "prefer-single"], "jsx-a11y/href-no-hash": 0, + "import/prefer-default-export": 0, "no-underscore-dangle": 0, "no-return-assign": 0, "no-param-reassign": 0, diff --git a/.travis.yml b/.travis.yml index 209445510..3d6d2e14d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,9 @@ +branches: + only: + - develop + - master + - "/^\\d+\\.\\d+\\.\\d+(-rc\\.\\d+)?$/" + matrix: include: - os: linux diff --git a/__mocks__/react-native-img-cache.js b/__mocks__/react-native-img-cache.js index d9f1f0a72..7b5b48f99 100644 --- a/__mocks__/react-native-img-cache.js +++ b/__mocks__/react-native-img-cache.js @@ -1,3 +1 @@ -module.exports = { - CachedImage: 'CachedImage' -}; +export const CachedImage = 'CachedImage'; diff --git a/__mocks__/react-native-navigation.js b/__mocks__/react-native-navigation.js index 44bb307d2..1ea9fa342 100644 --- a/__mocks__/react-native-navigation.js +++ b/__mocks__/react-native-navigation.js @@ -1,6 +1,4 @@ -module.exports = { - Navigation: { - registerComponent: () => {}, - startSingleScreenApp: () => {} - } +export const Navigation = { + registerComponent: () => {}, + startSingleScreenApp: () => {} }; diff --git a/__tests__/RoomItem.js b/__tests__/RoomItem.js index 06a0c7d96..1244a4437 100644 --- a/__tests__/RoomItem.js +++ b/__tests__/RoomItem.js @@ -5,40 +5,28 @@ import RoomItem from '../app/components/RoomItem'; // Note: test renderer must be required after react-native. import renderer from 'react-test-renderer'; -jest.mock('react-native-img-cache', () => { - return { - CachedImage: 'View' - } -}); - -const component = props => +jest.mock('react-native-img-cache', () => { return { CachedImage: 'View' } }); it('renders correctly', () => { - const tree = renderer.create(component({ type: 'd', name: 'name' })).toJSON(); - expect(tree).toMatchSnapshot(); + expect(renderer.create().toJSON()).toMatchSnapshot(); }); it('render unread', () => { - const tree = renderer.create(component({ type: 'd', name: 'name', unread: 1 })).toJSON(); - expect(tree).toMatchSnapshot(); + expect(renderer.create().toJSON()).toMatchSnapshot(); }); it('render unread +999', () => { - const tree = renderer.create(component({ type: 'd', name: 'name', unread: 1000 })).toJSON(); - expect(tree).toMatchSnapshot(); + expect(renderer.create().toJSON()).toMatchSnapshot(); }); it('render no icon', () => { - const tree = renderer.create(component({ type: 'X', name: 'name' })).toJSON(); - expect(tree).toMatchSnapshot(); + expect(renderer.create().toJSON()).toMatchSnapshot(); }); it('render private group', () => { - const tree = renderer.create(component({ type: 'g', name: 'private-group' })).toJSON(); - expect(tree).toMatchSnapshot(); + expect(renderer.create( ).toJSON()).toMatchSnapshot(); }); it('render channel', () => { - const tree = renderer.create(component({ type: 'c', name: 'general' })).toJSON(); - expect(tree).toMatchSnapshot(); + expect(renderer.create().toJSON()).toMatchSnapshot(); }); diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 2f9b9e505..87a09ec61 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -4,15 +4,33 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = ` { -// dispatch(retrieveMoviesGenresSuccess(res)); -// }) -// .catch(error => { -// console.log(error); //eslint-disable-line -// }); -// }; -// } - -// // POPULAR -// export function retrievePopularMoviesSuccess(res) { -// return { -// type: types.RETRIEVE_POPULAR_MOVIES_SUCCESS, -// popularMovies: res.data -// }; -// } - -// export function retrievePopularMovies(page) { -// return function (dispatch) { -// return axios.get(`${TMDB_URL}/movie/popular?api_key=${TMDB_API_KEY}&page=${page}`) -// .then(res => { -// dispatch(retrievePopularMoviesSuccess(res)); -// }) -// .catch(error => { -// console.log('Popular', error); //eslint-disable-line -// }); -// }; -// } - -// // NOW PLAYING -// export function retrieveNowPlayingMoviesSuccess(res) { -// return { -// type: types.RETRIEVE_NOWPLAYING_MOVIES_SUCCESS, -// nowPlayingMovies: res.data -// }; -// } - -// export function retrieveNowPlayingMovies(page) { -// return function (dispatch) { -// return axios.get(`${TMDB_URL}/movie/now_playing?api_key=${TMDB_API_KEY}&page=${page}`) -// .then(res => { -// dispatch(retrieveNowPlayingMoviesSuccess(res)); -// }) -// .catch(error => { -// console.log('Now Playing', error); //eslint-disable-line -// }); -// }; -// } - -// // MOVIES LIST -// export function retrieveMoviesListSuccess(res) { -// return { -// type: types.RETRIEVE_MOVIES_LIST_SUCCESS, -// list: res.data -// }; -// } - -// export function retrieveMoviesList(type, page) { -// return function (dispatch) { -// return axios.get(`${TMDB_URL}/movie/${type}?api_key=${TMDB_API_KEY}&page=${page}`) -// .then(res => { -// dispatch(retrieveMoviesListSuccess(res)); -// }) -// .catch(error => { -// console.log('Movies List', error); //eslint-disable-line -// }); -// }; -// } - -// // SEARCH RESULTS -// export function retrieveMoviesSearchResultsSuccess(res) { -// return { -// type: types.RETRIEVE_MOVIES_SEARCH_RESULT_SUCCESS, -// searchResults: res.data -// }; -// } - -// export function retrieveMoviesSearchResults(query, page) { -// return function (dispatch) { -// return axios.get(`${TMDB_URL}/search/movie?api_key=${TMDB_API_KEY}&query=${query}&page=${page}`) -// .then(res => { -// dispatch(retrieveMoviesSearchResultsSuccess(res)); -// }) -// .catch(error => { -// console.log('Movies Search Results', error); //eslint-disable-line -// }); -// }; -// } - -// // MOVIE DETAILS -// export function retrieveMovieDetailsSuccess(res) { -// return { -// type: types.RETRIEVE_MOVIE_DETAILS_SUCCESS, -// details: res.data -// }; -// } - -// export function retrieveMovieDetails(movieId) { -// return function (dispatch) { -// return axios.get(`${TMDB_URL}/movie/${movieId}?api_key=${TMDB_API_KEY}&append_to_response=casts,images,videos`) -// .then(res => { -// dispatch(retrieveMovieDetailsSuccess(res)); -// }) -// .catch(error => { -// console.log('Movie Details', error); //eslint-disable-line -// }); -// }; -// } diff --git a/app/actions/server.js b/app/actions/server.js index 9f0efeed1..cfc46ad89 100644 --- a/app/actions/server.js +++ b/app/actions/server.js @@ -7,7 +7,6 @@ export function setServer(server) { }; } export function serverRequest(server) { - console.log(server); return { type: SERVER.REQUEST, server @@ -15,7 +14,6 @@ export function serverRequest(server) { } export function addServer(server) { - console.log(server); return { type: SERVER.ADD, server diff --git a/app/components/MessageBox.js b/app/components/MessageBox.js index 263b1b992..e1f809073 100644 --- a/app/components/MessageBox.js +++ b/app/components/MessageBox.js @@ -37,7 +37,6 @@ export default class MessageBox extends React.PureComponent { } submit(message) { - // console.log(this.state); const text = message; if (text.trim() === '') { return; @@ -56,8 +55,6 @@ export default class MessageBox extends React.PureComponent { }; ImagePicker.showImagePicker(options, (response) => { - // console.log('Response = ', response); - if (response.didCancel) { console.log('User cancelled image picker'); } else if (response.error) { @@ -84,8 +81,6 @@ export default class MessageBox extends React.PureComponent { this.component = component} style={styles.textBoxInput} - // value={this.state.text} - // onChangeText={text => this.setState({ text })} returnKeyType='send' onSubmitEditing={event => this.submit(event.nativeEvent.text)} blurOnSubmit={false} diff --git a/app/constants/types.js b/app/constants/types.js index 97c8b2e7c..f772c2b92 100644 --- a/app/constants/types.js +++ b/app/constants/types.js @@ -1,10 +1,2 @@ -// export const RETRIEVE_MOVIES_GENRES_SUCCESS = 'RETRIEVE_MOVIES_GENRES_SUCCESS'; - -// export const RETRIEVE_POPULAR_MOVIES_SUCCESS = 'RETRIEVE_POPULAR_MOVIES_SUCCESS'; -// export const RETRIEVE_NOWPLAYING_MOVIES_SUCCESS = 'RETRIEVE_NOWPLAYING_MOVIES_SUCCESS'; -// export const RETRIEVE_MOVIES_LIST_SUCCESS = 'RETRIEVE_MOVIES_LIST_SUCCESS'; -// export const RETRIEVE_MOVIE_DETAILS_SUCCESS = 'RETRIEVE_MOVIE_DETAILS_SUCCESS'; -// export const RETRIEVE_MOVIES_SEARCH_RESULT_SUCCESS = 'RETRIEVE_MOVIES_SEARCH_RESULT_SUCCESS'; - export const SET_CURRENT_SERVER = 'SET_CURRENT_SERVER'; export const SET_ALL_SETTINGS = 'SET_ALL_SETTINGS'; diff --git a/app/index.js b/app/index.js index c76830ae5..d126f6544 100644 --- a/app/index.js +++ b/app/index.js @@ -13,16 +13,6 @@ import styles from './views/Styles'; import store from './lib/createStore'; -// -// export const authenticated = (view) => { -// if (!store.getState().login.authenticated) { -// return store.getState().navigator.resetTo({ -// screen: 'Login' -// }); -// } -// return view; -// }; - export const authenticated = WrappedComponent => class _p extends React.PureComponent { constructor() { super(); @@ -41,12 +31,6 @@ export const authenticated = WrappedComponent => class _p extends React.PureComp }; // export class PublicScreen extends React.PureComponent { - // componentWillMount() { - // this.props.setNavigator(this.props.navigator); - // if (this.props.currentServer) { - // return this.props.navigator.navigate('private'); - // } - // } render() { return ((this.login.isAuthenticated || this.login.user) && ); } @@ -57,20 +41,13 @@ export class PublicScreen extends React.PureComponent { setNavigator: navigator => dispatch(setNavigator(navigator)) })) export class PrivateScreen extends React.PureComponent { - componentWillMount() { - // this.props.setNavigator(this.props.navigator); - } render() { - // if (this.props.logged) { - // return (oi); - // } return (); } } @connect(() => ({ // logged: state.login.isAuthenticated }), dispatch => ({ - // navigate: routeName => dispatch(NavigationActions.navigate({ routeName })), setNavigator: navigator => dispatch(setNavigator(navigator)), appInit: () => dispatch(appInit()) })) diff --git a/app/lib/realm.js b/app/lib/realm.js index 2ab94a14f..f77882afa 100644 --- a/app/lib/realm.js +++ b/app/lib/realm.js @@ -33,7 +33,6 @@ const subscriptionSchema = { name: 'string', fname: { type: 'string', optional: true }, rid: 'string', - // u: { _id: 'hKCY2XGzHYk89SAaM', username: 'rodrigo', name: null }, open: { type: 'bool', optional: true }, alert: { type: 'bool', optional: true }, // roles: [ 'owner' ], diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 7de5aadcc..a9fd9c8b2 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -50,7 +50,6 @@ const RocketChat = { const url = `${ _url }/websocket`; Meteor.connect(url, { autoConnect: true, autoReconnect: true }); - // , { autoConnect: false, autoReconnect: false } Meteor.ddp.on('disconnected', () => { reduxStore.dispatch(disconnect()); }); @@ -58,9 +57,6 @@ const RocketChat = { reduxStore.dispatch(connectSuccess()); resolve(); }); - // Meteor.ddp.on('loggin', () => { - // reduxStore.dispatch(loginSuccess({})); - // }); Meteor.ddp.on('connected', () => { Meteor.call('public-settings/get', (err, data) => { if (err) { @@ -86,19 +82,16 @@ const RocketChat = { }); Meteor.ddp.on('changed', (ddbMessage) => { - // console.log('changed', ddbMessage); if (ddbMessage.collection === 'stream-room-messages') { realm.write(() => { const message = ddbMessage.fields.args[0]; message.temp = false; message._server = { id: reduxStore.getState().server.server }; - // write('messages', message); realm.create('messages', message, true); }); } if (ddbMessage.collection === 'stream-notify-user') { - // console.log(ddbMessage); realm.write(() => { const data = ddbMessage.fields.args[1]; data._server = { id: reduxStore.getState().server.server }; diff --git a/app/sagas/selectServer.js b/app/sagas/selectServer.js index 35c3177ae..f5db20fa6 100644 --- a/app/sagas/selectServer.js +++ b/app/sagas/selectServer.js @@ -1,8 +1,16 @@ -import { put, takeEvery, call } from 'redux-saga/effects'; +import { put, takeEvery, call, takeLatest, all, race, take } from 'redux-saga/effects'; +import { delay } from 'redux-saga'; import { AsyncStorage } from 'react-native'; +import { Navigation } from 'react-native-navigation'; import { SERVER } from '../actions/actionsTypes'; import { connectRequest, disconnect } from '../actions/connect'; -import { changedServer } from '../actions/server'; +import { changedServer, serverSuccess, serverFailure, serverRequest } from '../actions/server'; +import RocketChat from '../lib/rocketchat'; +import realm from '../lib/realm'; + +const validate = function* validate(server) { + return yield RocketChat.testServer(server); +}; const selectServer = function* selectServer({ server }) { yield put(disconnect()); @@ -10,7 +18,40 @@ const selectServer = function* selectServer({ server }) { yield call([AsyncStorage, 'setItem'], 'currentServer', server); yield put(connectRequest(server)); }; + + +const validateServer = function* validateServer({ server }) { + try { + yield delay(1000); + yield call(validate, server); + yield put(serverSuccess()); + } catch (e) { + console.log(e); + yield put(serverFailure(e)); + } +}; + +const addServer = function* addServer({ server }) { + yield call(serverRequest, server); + + const { error } = race({ + error: take(SERVER.FAILURE), + success: take(SERVER.SUCCESS) + }); + if (!error) { + realm.write(() => { + realm.create('servers', { id: server, current: false }, true); + }); + Navigation.dismissModal({ + animationType: 'slide-down' + }); + } +}; + + const root = function* root() { + yield takeLatest(SERVER.REQUEST, validateServer); yield takeEvery(SERVER.SELECT, selectServer); + yield takeEvery(SERVER.ADD, addServer); }; export default root; diff --git a/package-lock.json b/package-lock.json index 3f034a132..2c14516f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9631,6 +9631,12 @@ "react-native-drawer-layout": "1.3.2" } }, + "react-native-easy-markdown": { + "version": "git+https://github.com/lappalj4/react-native-easy-markdown.git#0571414f113346d4a4f4ba32715d87595f8b9a70", + "requires": { + "simple-markdown": "0.1.2" + } + }, "react-native-fetch-blob": { "version": "0.10.8", "resolved": "https://registry.npmjs.org/react-native-fetch-blob/-/react-native-fetch-blob-0.10.8.tgz", @@ -9676,9 +9682,9 @@ } }, "react-native-loading-spinner-overlay": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/react-native-loading-spinner-overlay/-/react-native-loading-spinner-overlay-0.5.1.tgz", - "integrity": "sha512-LOgWzd1AJ4SYeqoomjYcHA0A/ngtBR49gt23GKzHKtiO4I1MFcccJXek774K/xhlIA4qfcwx9ufj5f2HuyBbEw==" + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/react-native-loading-spinner-overlay/-/react-native-loading-spinner-overlay-0.5.2.tgz", + "integrity": "sha512-wIi8PMvD/KnzEgZN865Cm0VhyIba4Zrfwbyi9OPlBYi1+qQDq4MZtDCmKgH8ct7iXE7biTrcBzUxFAAPk9CvCw==" }, "react-native-meteor": { "version": "1.1.0", @@ -10645,6 +10651,11 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, + "simple-markdown": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/simple-markdown/-/simple-markdown-0.1.2.tgz", + "integrity": "sha1-PBUQ/kC9nqBncXuKUzyc82MltBM=" + }, "simple-plist": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-0.2.1.tgz", diff --git a/package.json b/package.json index 88f21bf0a..8b813f685 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "scripts": { "start": "node node_modules/react-native/local-cli/cli.js start", "test": "jest", + "updateSnapshot": "jest --updateSnapshot", "lint": "eslint .", "ci": "eslint . && jest && codecov", "ios": "react-native run-ios",