Add posts lists (#22)

* Add posts list

* Use map instead of polyfill

* Fix some eslint issues

* Address camel case and client channelId
This commit is contained in:
Mike Piccolo 2016-10-17 19:19:08 -07:00 committed by Thomas Hopkins
parent 5bdc432f71
commit f6ed67e053
15 changed files with 169 additions and 23 deletions

View file

@ -46,4 +46,4 @@ export function bindClientFunc(clientFunc, request, success, failure, ...args) {
return dispatch(() => clientFunc(...args, onRequest, onSuccess, onFailure), getState);
};
}
}

17
src/actions/posts.js Normal file
View file

@ -0,0 +1,17 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import {bindClientFunc} from './helpers.js';
import Client from 'client/client_instance';
import {PostsTypes as types} from 'constants';
export function fetchPosts(teamId, channelId) {
Client.setTeamId(teamId);
return bindClientFunc(
Client.fetchPosts,
types.FETCH_POSTS_REQUEST,
types.FETCH_POSTS_SUCCESS,
types.FETCH_POSTS_FAILURE,
channelId
);
}

View file

@ -249,6 +249,15 @@ export default class Client {
}
// Post routes
fetchPosts = (channelId, onRequest, onSuccess, onFailure) => {
return this.doFetch(
`${this.getPostsRoute(channelId)}/page/0/60`,
{method: 'get'},
onRequest,
onSuccess,
onFailure
);
}
createPost = (post, onRequest, onSuccess, onFailure) => {
return this.doFetch(

View file

@ -38,10 +38,9 @@ class ChannelsList extends Component {
}
componentWillReceiveProps(props) {
if (props.channels.current_channel_id &&
!this.props.channels.current_channel_id) {
console.warn('TODO route to PostsList'); // eslint-disable-line no-console
// TODO: Routes.PostLists(); // eslint-disable-line new-cap
if (props.channels.currentChannelId &&
!this.props.channels.currentChannelId) {
Routes.goToPostsList();
}
}

View file

@ -42,7 +42,7 @@ class Login extends Component {
componentWillReceiveProps(props) {
if (this.props.login.status === 'fetching' &&
props.login.status === 'fetched') {
Routes.SelectTeam(); // eslint-disable-line new-cap
Routes.goToSelectTeam(); // eslint-disable-line new-cap
}
}

View file

@ -0,0 +1,70 @@
// 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 {StyleSheet, Text, View} from 'react-native';
import * as postActions from 'actions/posts';
import ErrorText from 'components/error_text';
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
alignItems: 'center',
paddingTop: 200,
backgroundColor: 'white'
}
});
const propTypes = {
posts: PropTypes.object.isRequired,
currentTeamId: PropTypes.string.isRequired,
currentChannelId: PropTypes.string.isRequired,
actions: PropTypes.object.isRequired
};
class PostsList extends Component {
static propTypes = propTypes;
componentWillMount() {
this.props.actions.fetchPosts(
this.props.currentTeamId,
this.props.currentChannelId
);
}
render() {
return (
<View style={styles.container}>
{this.props.posts.data.map((post) => {
return (
<Text key={post.id}>
{`${post.user_id} - ${post.message}`}
</Text>
);
})}
<ErrorText error={this.props.posts.error}/>
</View>
);
}
}
function mapStateToProps(state) {
return {
posts: state.entities.posts,
currentTeamId: state.entities.teams.currentTeamId,
currentChannelId: state.entities.channels.currentChannelId
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(postActions, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(PostsList);

View file

@ -49,7 +49,7 @@ class SelectServerView extends Component {
onClick = () => {
Client.setUrl(this.state.serverUrl);
Routes.Login(); // eslint-disable-line new-cap
Routes.goToLogin();
// this.props.getPing().then(() => {
// AsyncStorage.setItem('serverUrl', this.state.serverUrl, () => {

View file

@ -39,8 +39,8 @@ class SelectTeam extends Component {
}
componentWillReceiveProps(props) {
if (props.teams.current_team_id && !this.props.teams.current_team_id) {
Routes.ChannelsList(); // eslint-disable-line new-cap
if (props.teams.currentTeamId && !this.props.teams.currentTeamId) {
Routes.goToChannelsList();
}
}

View file

@ -3,11 +3,13 @@ import * as DeviceTypes from './device';
import * as GeneralTypes from './general';
import * as LoginTypes from './login';
import * as TeamsTypes from './teams';
import * as PostsTypes from './posts';
export {
DeviceTypes,
GeneralTypes,
LoginTypes,
TeamsTypes,
ChannelsTypes
ChannelsTypes,
PostsTypes
};

3
src/constants/posts.js Normal file
View file

@ -0,0 +1,3 @@
export const FETCH_POSTS_REQUEST = 'FETCH_POSTS_REQUEST';
export const FETCH_POSTS_SUCCESS = 'FETCH_POSTS_SUCCESS';
export const FETCH_POSTS_FAILURE = 'FETCH_POSTS_FAILURE';

View file

@ -4,7 +4,7 @@ const initState = {
status: 'not fetched',
error: null,
data: [],
current_channel_id: null
currentChannelId: null
};
export default function reduceChannels(state = initState, action) {
@ -12,7 +12,7 @@ export default function reduceChannels(state = initState, action) {
case types.SELECT_CHANNEL:
return {...state,
current_channel_id: action.channel_id
currentChannelId: action.channel_id
};
case types.FETCH_CHANNELS_REQUEST:

View file

@ -8,11 +8,13 @@ import device from './device.js';
import general from './general.js';
import login from './login';
import teams from './teams';
import posts from './posts';
const entities = combineReducers({
channels,
general,
teams
teams,
posts
});
const views = combineReducers({

32
src/reducers/posts.js Normal file
View file

@ -0,0 +1,32 @@
import _ from 'lodash';
import {PostsTypes as types} from 'constants';
const initState = {
status: 'not fetched',
error: null,
data: []
};
export default function reducePosts(state = initState, action) {
switch (action.type) {
case types.FETCH_POSTS_REQUEST:
return {...state,
status: 'fetching',
error: null
};
case types.FETCH_POSTS_SUCCESS:
return {...state,
status: 'fetched',
data: _.values(action.data.posts)
};
case types.FETCH_POSTS_FAILURE:
return {...state,
status: 'failed',
error: action.error
};
default:
return state;
}
}

View file

@ -5,7 +5,7 @@ const initState = {
status: 'not fetched',
error: null,
data: [],
current_team_id: null
currentTeamId: null
};
export default function reduceTeams(state = initState, action) {
@ -13,7 +13,7 @@ export default function reduceTeams(state = initState, action) {
case types.SELECT_TEAM:
return {...state,
current_team_id: action.team_id
currentTeamId: action.team_id
};
case types.FETCH_TEAMS_REQUEST:

View file

@ -9,6 +9,7 @@ import ChannelsList from 'components/channels_list';
import Login from 'components/login';
import SelectServerView from 'components/select_server_view';
import SelectTeam from 'components/select_team';
import PostsList from 'components/posts_list';
export default class Routes extends Component {
render() {
@ -16,26 +17,37 @@ export default class Routes extends Component {
<Router>
<Scene key='root'>
<Scene
key='ChannelsList'
component={ChannelsList}
title='Channels'
/>
<Scene
key='Login'
key='goToLogin'
component={Login}
title='Login'
/>
<Scene
key='SelectServerView'
key='goToSelectServerView'
component={SelectServerView}
title='Enter Server URL'
initial={true}
/>
<Scene
key='SelectTeam'
key='goToSelectServerView'
component={SelectServerView}
title='Enter Server URL'
initial={true}
/>
<Scene
key='goToChannelsList'
component={ChannelsList}
title='Channels'
/>
<Scene
key='goToSelectTeam'
component={SelectTeam}
title='Select Team'
/>
<Scene
key='goToPostsList'
component={PostsList}
title='Posts List'
/>
</Scene>
</Router>
);