Skip to content

Commit 1409585

Browse files
committed
Add support for multiple lists
1 parent 236de3a commit 1409585

File tree

6 files changed

+76
-18
lines changed

6 files changed

+76
-18
lines changed

client/src/components/App.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ export class App extends Component {
2626
<NavbarToggler right onClick={this.toggle} />
2727
<Collapse isOpen={this.state.isOpen} navbar>
2828
<Nav navbar>
29+
<NavItem>
30+
<NavLink href="/#/">Dashboard</NavLink>
31+
</NavItem>
2932
<NavItem>
3033
<NavLink href="/#/posts">Posts</NavLink>
3134
</NavItem>

client/src/components/Dashboard.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React, { Component, PropTypes } from 'react';
2+
import { Link } from 'react-router';
3+
import { connect } from 'react-redux';
4+
import { get, find, keyBy } from 'lodash';
5+
6+
import { fetchList, getList, getMap } from '../store/api';
7+
8+
const formatDate = date => (new Date(date)).toLocaleString();
9+
10+
export class Dashobard extends Component {
11+
componentWillMount() {
12+
this.props.fetchPostsList();
13+
}
14+
15+
getCategoryForPost(post) {
16+
const categoryId = String(get(post, 'category.id'));
17+
return this.props.categoriesById[categoryId] || {};
18+
}
19+
20+
render() {
21+
const { postsList } = this.props;
22+
23+
return (
24+
<div>
25+
<h4>Latest posts</h4>
26+
{postsList.data.map(post =>
27+
<div key={post.id}>
28+
<Link to={`/posts/${post.id}`}>{post.title}</Link>
29+
({this.getCategoryForPost(post).name})
30+
{formatDate(post.createdAt)}
31+
</div>
32+
)}
33+
</div>
34+
);
35+
}
36+
}
37+
38+
export const mapStateToProps = state => ({
39+
postsList: getList(state, 'posts', 'latestPosts'),
40+
categoriesById: getMap(state, 'categories'),
41+
});
42+
43+
export const mapDispatchToProps = dispatch => ({
44+
fetchPostsList: () => dispatch(fetchList(
45+
'posts',
46+
{ include: 'category', page: { size: 5 }, sort: '-createdAt' },
47+
{ list: 'latestPosts' },
48+
)),
49+
});
50+
51+
export default connect(mapStateToProps, mapDispatchToProps)(Dashobard);

client/src/components/Posts/PostList.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export const mapStateToProps = state => ({
8787
});
8888

8989
export const mapDispatchToProps = dispatch => ({
90-
fetchCategories: () => dispatch(fetchList('categories', { page: { limit: 999 } })),
90+
fetchCategories: () => dispatch(fetchList('categories', { page: { size: 999 } })),
9191
});
9292

9393
export default connect(mapStateToProps, mapDispatchToProps)(

client/src/components/Routes.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { UserAuthWrapper } from 'redux-auth-wrapper';
44

55
import { getUser } from '../store/api';
66
import App from './App';
7+
import Dashboard from './Dashboard';
78
import { PostList, PostEdit } from './Posts';
89
import { CategoryList, CategoryEdit } from './Categories';
910
import { UserList, UserEdit } from './Users';
@@ -22,7 +23,7 @@ export class Routes extends PureComponent {
2223
return (
2324
<Router history={history}>
2425
<Route path="/" component={UserIsAuthenticated(App)}>
25-
<IndexRoute component={PostList}/>
26+
<IndexRoute component={Dashboard}/>
2627
<Route path="/posts" component={PostList}/>
2728
<Route path="/posts/new" component={PostEdit}/>
2829
<Route path="/posts/:id" component={PostEdit}/>

client/src/store/api/reducer.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const addNormalized = (newState, payload) => {
4141

4242
export default (state = initialState, action) => {
4343
const { type, payload, meta } = action;
44-
const { key } = meta || {};
44+
const { key, list = 'list' } = meta || {};
4545
let newState = state;
4646

4747
switch (type) {
@@ -50,10 +50,10 @@ export default (state = initialState, action) => {
5050
}
5151
case actionType(GET_LIST, SUCCESS): {
5252
newState = addNormalized(newState, payload);
53-
newState = imm.set(newState, [key, 'list', 'ids'], map(payload.data, 'id'));
54-
newState = imm.set(newState, [key, 'list', 'params'], payload.params);
55-
newState = imm.set(newState, [key, 'list', 'links'], payload.links);
56-
newState = imm.set(newState, [key, 'list', 'meta'], payload.meta);
53+
newState = imm.set(newState, [key, list, 'ids'], map(payload.data, 'id'));
54+
newState = imm.set(newState, [key, list, 'params'], payload.params);
55+
newState = imm.set(newState, [key, list, 'links'], payload.links);
56+
newState = imm.set(newState, [key, list, 'meta'], payload.meta);
5757
return newState;
5858
}
5959
case actionType(GET_MANY, SUCCESS): {
@@ -62,7 +62,7 @@ export default (state = initialState, action) => {
6262
case actionType(CREATE, SUCCESS): {
6363
newState = addNormalized(newState, payload);
6464
if (meta.list) {
65-
newState = imm.push(newState, [key, 'list', 'ids'], payload.data.id);
65+
newState = imm.push(newState, [key, list, 'ids'], payload.data.id);
6666
}
6767
return newState;
6868
}
@@ -71,8 +71,8 @@ export default (state = initialState, action) => {
7171
}
7272
case actionType(DELETE, SUCCESS): {
7373
newState = imm.del(newState, [key, 'byId', payload.data.id]);
74-
newState = imm.set(newState, [key, 'list', 'ids'],
75-
without(get(newState, [key, 'list', 'ids']), payload.data.id),
74+
newState = imm.set(newState, [key, list, 'ids'],
75+
without(get(newState, [key, list, 'ids']), payload.data.id),
7676
);
7777
return newState;
7878
}

client/src/store/api/selectors.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
import { get, isEmpty } from 'lodash';
22

3-
export const getUser = state => get(state, ['api', 'user']) || {};
3+
export const getUser = state =>
4+
get(state, ['api', 'user']) || {};
45

5-
export const getOne = (state, key, id) => get(state, ['api', key, 'byId', id]) || {};
6+
export const getOne = (state, resourceName, id) =>
7+
get(state, ['api', resourceName, 'byId', id]) || {};
68

7-
export const getMap = (state, key) => get(state, ['api', key, 'byId']) || {};
8-
9-
export const getMany = (state, key, ids) => {
10-
const { byId } = get(state, ['api', key]) || {};
9+
export const getMap = (state, resourceName) =>
10+
get(state, ['api', resourceName, 'byId']) || {};
1111

12+
export const getMany = (state, resourceName, ids) => {
13+
const byId = get(state, ['api', resourceName, 'byId']);
1214
return isEmpty(byId)
1315
? []
1416
: (ids || Object.keys(byId)).map(id => byId[id]);
1517
};
1618

17-
export const getList = (state, key) => {
18-
const { byId, list } = get(state, ['api', key]) || {};
19+
export const getList = (state, resourceName, listName = 'list') => {
20+
const byId = get(state, ['api', resourceName, 'byId']) || {};
21+
const list = get(state, ['api', resourceName, listName]) || {};
1922
return isEmpty(list)
2023
? { data: [], ids: [], links: {}, params: { page: {}, filter: {} } }
2124
: { ...list, data: list.ids.map(id => byId[id]) };

0 commit comments

Comments
 (0)