Skip to content

Commit 9668797

Browse files
committed
Merge branch 'feature/pagination-integration' into dev
2 parents daf1773 + cca1956 commit 9668797

File tree

16 files changed

+275
-27
lines changed

16 files changed

+275
-27
lines changed

src/common/actions/pageActions.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import ActionTypes from '../constants/ActionTypes';
2+
3+
export const setPage = (resourceName, page) => {
4+
return {
5+
type: ActionTypes.SET_PAGE,
6+
resourceName,
7+
page,
8+
};
9+
};
10+
11+
export const setCrrentPage = (resourceName, currentPage) => {
12+
return {
13+
type: ActionTypes.SET_CURRENT_PAGE,
14+
resourceName,
15+
currentPage,
16+
};
17+
};

src/common/api/todo.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default (apiEngine) => ({
44
// resolve(apiEngine.get('/api/todo'));
55
// }, 5000);
66
// }),
7-
list: () => apiEngine.get('/api/todos'),
7+
list: ({ page }) => apiEngine.get('/api/todos', { params: { page } }),
88
create: (todo) => apiEngine.post('/api/todos', { data: todo }),
99
update: (id, todo) => apiEngine.put(`/api/todos/${id}`, { data: todo }),
1010
remove: (id) => apiEngine.del(`/api/todos/${id}`),

src/common/components/layouts/AppLayout.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const AppLayout = ({ children }) => (
1717
links={[
1818
// jscs:disable
1919
'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css',
20+
'https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css',
2021
'/css/main.css',
2122
// jscs:enable
2223
]}

src/common/components/pages/todo/ListPage.js

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import React, { Component } from 'react';
22
import { connect } from 'react-redux';
3+
import { withRouter } from 'react-router';
34
import PageHeader from 'react-bootstrap/lib/PageHeader';
5+
import Resources from '../../../constants/Resources';
46
import todoAPI from '../../../api/todo';
57
import { pushErrors } from '../../../actions/errorActions';
68
import {
79
setTodo,
810
addTodo,
911
removeTodo,
1012
} from '../../../actions/todoActions';
13+
import { setCrrentPage, setPage } from '../../../actions/pageActions';
1114
import PageLayout from '../../layouts/PageLayout';
15+
import Pagination from '../../utils/BsPagination';
1216

1317
class TodoItem extends Component {
1418
constructor() {
@@ -84,25 +88,29 @@ class ListPage extends Component {
8488
}
8589

8690
componentDidMount() {
87-
let { todos } = this.props;
88-
89-
if (todos.length === 0) {
90-
this.fetchTodos();
91-
}
91+
let { dispatch, location } = this.props;
92+
dispatch(setCrrentPage(Resources.TODO, location.query.page || 1));
9293
}
9394

94-
fetchTodos() {
95-
let { dispatch, apiEngine } = this.props;
96-
97-
todoAPI(apiEngine)
98-
.list()
99-
.catch((err) => {
100-
dispatch(pushErrors(err));
101-
throw err;
102-
})
103-
.then((json) => {
104-
dispatch(setTodo(json.todos));
105-
});
95+
componentDidUpdate(prevProps) {
96+
let { dispatch, apiEngine, page, router, location } = this.props;
97+
98+
if (prevProps.page.current !== page.current) {
99+
todoAPI(apiEngine)
100+
.list({ page: page.current })
101+
.catch((err) => {
102+
dispatch(pushErrors(err));
103+
throw err;
104+
})
105+
.then((json) => {
106+
dispatch(setTodo(json.todos));
107+
dispatch(setPage(Resources.TODO, json.page));
108+
router.push({
109+
pathname: location.pathname,
110+
query: { page: json.page.current },
111+
});
112+
});
113+
}
106114
}
107115

108116
_handleAddClick() {
@@ -148,9 +156,11 @@ class ListPage extends Component {
148156
}
149157

150158
render() {
159+
let { page } = this.props;
160+
151161
return (
152162
<PageLayout>
153-
<PageHeader>Todo List</PageHeader>
163+
<PageHeader>Todo List ({`${page.current} / ${page.total}`})</PageHeader>
154164
<input type="text" ref="todotext" />
155165
<button onClick={this.handleAddClick}>Add Todo</button>
156166
<ul>
@@ -161,12 +171,14 @@ class ListPage extends Component {
161171
onSaveClick={this.handleSaveClick.bind(this, todo._id)}
162172
text={todo.text} />)}
163173
</ul>
174+
<Pagination resourceName={Resources.TODO} />
164175
</PageLayout>
165176
);
166177
}
167178
};
168179

169-
export default connect(state => ({
180+
export default withRouter(connect(state => ({
170181
apiEngine: state.apiEngine,
171182
todos: state.todos,
172-
}))(ListPage);
183+
page: state.pages[Resources.TODO] || {},
184+
}))(ListPage));
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import React, { PropTypes } from 'react';
2+
import { connect } from 'react-redux';
3+
import cx from 'classnames';
4+
import { setCrrentPage } from '../../actions/pageActions';
5+
import Text from '../widgets/Text';
6+
7+
let style = {
8+
cursor: 'pointer',
9+
margin: 2,
10+
};
11+
12+
let Pagination = ({ simple, resourceName, pages, dispatch, ...rest }) => {
13+
let page = pages[resourceName] || pages.default;
14+
15+
return (
16+
<nav {...rest}>
17+
<ul className="pager">
18+
{!simple && (
19+
<li
20+
className={cx({'disabled': page.current === page.first})}
21+
style={style}
22+
>
23+
<a
24+
onClick={() =>
25+
dispatch(setCrrentPage(resourceName, page.first))
26+
}
27+
>
28+
<i className="fa fa-angle-double-left" aria-hidden="true" />
29+
{' '}<Text id="page.first" />
30+
</a>
31+
</li>
32+
)}
33+
<li
34+
className={cx({'disabled': page.current === page.first})}
35+
style={style}
36+
>
37+
<a
38+
onClick={() =>
39+
dispatch(setCrrentPage(resourceName, page.current - 1))
40+
}
41+
>
42+
<i className="fa fa-chevron-left" aria-hidden="true" />
43+
{' '}<Text id="page.prev" />
44+
</a>
45+
</li>
46+
<li
47+
className={cx({'disabled': page.current === page.last})}
48+
style={style}
49+
>
50+
<a
51+
onClick={() =>
52+
dispatch(setCrrentPage(resourceName, page.current + 1))
53+
}
54+
>
55+
<Text id="page.next" />{' '}
56+
<i className="fa fa-chevron-right" aria-hidden="true" />
57+
</a>
58+
</li>
59+
{!simple && (
60+
<li
61+
className={cx({'disabled': page.current === page.last})}
62+
style={style}
63+
>
64+
<a
65+
onClick={() =>
66+
dispatch(setCrrentPage(resourceName, page.last))
67+
}
68+
>
69+
<Text id="page.last" />{' '}
70+
<i className="fa fa-angle-double-right" aria-hidden="true" />
71+
</a>
72+
</li>
73+
)}
74+
</ul>
75+
</nav>
76+
);
77+
};
78+
79+
Pagination.propTypes = {
80+
resourceName: PropTypes.string.isRequired,
81+
simple: PropTypes.bool,
82+
};
83+
84+
export default connect(state => ({
85+
pages: state.pages,
86+
}))(Pagination);

src/common/constants/ActionTypes.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,7 @@ export default {
1515

1616
PUSH_ERRORS: 'PUSH_ERRORS',
1717
REMOVE_ERROR: 'REMOVE_ERROR',
18+
19+
SET_PAGE: 'SET_PAGE',
20+
SET_CURRENT_PAGE: 'SET_CURRENT_PAGE',
1821
};

src/common/constants/Resources.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default {
2+
TODO: 'TODO',
3+
};

src/common/i18n/en-us.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ export default {
88
'nav.user.register': 'Register',
99
'nav.user.profile': 'Profile',
1010
'nav.user.logout': 'Logout',
11+
'page.first': 'First Page',
12+
'page.prev': 'Previous',
13+
'page.next': 'Next',
14+
'page.last': 'Last Page',
1115
};

src/common/i18n/zh-tw.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ export default {
88
'nav.user.register': '註冊',
99
'nav.user.profile': '會員中心',
1010
'nav.user.logout': '登出',
11+
'page.first': '第一頁',
12+
'page.prev': '上一頁',
13+
'page.next': '下一頁',
14+
'page.last': '最後一頁',
1115
};

src/common/reducers/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { combineReducers } from 'redux';
22
import cookies from './cookieReducer';
33
import errors from './errorReducer';
44
import apiEngine from './apiEngineReducer';
5+
import pages from './pageReducer';
56
import todos from './todoReducer';
67
import form from './formReducer';
78
import intl from './intlReducer';
@@ -10,6 +11,7 @@ const rootReducer = combineReducers({
1011
cookies,
1112
errors,
1213
apiEngine,
14+
pages,
1315
todos,
1416
form, // must mount as `form` from redux-form's docs
1517
intl,

0 commit comments

Comments
 (0)