Skip to content

Commit 51f666b

Browse files
authored
Pagination (#16)
1 parent d631f7d commit 51f666b

File tree

9 files changed

+78
-9
lines changed

9 files changed

+78
-9
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
/lib/
22
/node_modules/
3+
/tmp

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
language: node_js
22

33
node_js:
4+
- "8"
45
- "7"
56
- "6"
67

@@ -12,3 +13,4 @@ script:
1213
- yarn build
1314
- yarn test
1415
- yarn lint
16+
- yarn test-gen

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ A generator to scaffold a React/Redux app with Create-Retrieve-Update-Delete fea
44
Works especially well with APIs built with the [API Platform](https://api-platform.com) framework.
55

66
[![Build Status](https://travis-ci.org/api-platform/generate-crud.svg?branch=master)](https://travis-ci.org/api-platform/generate-crud)
7+
[![npm version](https://badge.fury.io/js/api-platform-generate-crud.svg)](https://badge.fury.io/js/api-platform-generate-crud)
8+
[![MIT Licence](https://badges.frapsoft.com/os/mit/mit.svg?v=103)](https://opensource.org/licenses/mit-license.php)
9+
10+
[![NPM](https://nodei.co/npm/api-platform-generate-crud.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/api-platform-generate-crud/)
711

812
## Features
913

@@ -93,7 +97,6 @@ ReactDom.render(
9397

9498
## TODO
9599

96-
* Add support for pagination
97100
* Automatically normalize numbers
98101
* Generate E2E tests
99102
* Add a React Native generator

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "api-platform-generate-crud",
3-
"version": "0.1.5",
3+
"version": "0.1.6",
44
"description": "Generate a CRUD application built with React, Redux and React Router from an Hydra-enabled API",
55
"files": [
66
"*.md",
@@ -42,7 +42,8 @@
4242
"test": "jest",
4343
"lint": "eslint src",
4444
"build": "babel src -d lib --ignore '*.test.js'",
45-
"watch": "babel --watch src -d lib --ignore '*.test.js'"
45+
"watch": "babel --watch src -d lib --ignore '*.test.js'",
46+
"test-gen": "rm -rf ./tmp && npm run build && ./lib/index.js https://demo.api-platform.com ./tmp"
4647
},
4748
"bin": {
4849
"api-platform-generate-crud": "./lib/index.js"

src/ReactCrudGenerator.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export default class ReactCrudGenerator {
6666
titleUcFirst
6767
};
6868

69+
6970
// Create directories
7071
// These directories may already exist
7172
mkdirp.sync(`${dir}/api`);

templates/react/actions/foo/list.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,21 @@ export function success(items) {
1212
return {type: '{{{ uc }}}_LIST_SUCCESS', items};
1313
}
1414

15-
export function list() {
15+
export function view(items) {
16+
return { type: '{{{ uc }}}_LIST_VIEW', items};
17+
}
18+
19+
export function page(page) {
1620
return (dispatch) => {
1721
dispatch(loading(true));
22+
dispatch(error(''));
1823

19-
{{{ lc }}}Fetch('/{{{ name }}}')
24+
{{{ lc }}}Fetch(page)
2025
.then(response => response.json())
2126
.then(data => {
2227
dispatch(loading(false));
2328
dispatch(success(data['{{{ hydraPrefix }}}member']));
29+
dispatch(view(data['{{{ hydraPrefix }}}view']));
2430
})
2531
.catch(e => {
2632
dispatch(loading(false));
@@ -29,6 +35,10 @@ export function list() {
2935
};
3036
}
3137

38+
export function list() {
39+
return page('/{{{ name }}}');
40+
}
41+
3242
export function reset() {
3343
return {type: '{{{ uc }}}_LIST_RESET'};
3444
}

templates/react/components/foo/List.js

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import React, {Component} from 'react';
22
import { connect } from 'react-redux';
33
import { Link } from 'react-router-dom';
44
import PropTypes from 'prop-types';
5-
import { list, reset } from '../../actions/{{{ lc }}}/list';
5+
import { list, reset, page } from '../../actions/{{{ lc }}}/list';
66
import { success } from '../../actions/{{{ lc }}}/delete';
7-
import { itemToLinks } from '../../utils/helpers';
7+
import { paginationRoute, itemToLinks } from '../../utils/helpers';
88

99
class List extends Component {
1010
static propTypes = {
@@ -14,8 +14,42 @@ class List extends Component {
1414
deletedItem: PropTypes.object,
1515
list: PropTypes.func.isRequired,
1616
reset: PropTypes.func.isRequired,
17+
page: PropTypes.func.isRequired,
1718
};
1819

20+
pagination() {
21+
return (
22+
<span>
23+
<button
24+
type="button"
25+
className="btn btn-basic btn-sm"
26+
onClick={() => this.props.page(paginationRoute(this.props.view['{{{ hydraPrefix }}}first']))}
27+
disabled={!this.props.view['{{{ hydraPrefix }}}previous']}
28+
>First</button>
29+
&nbsp;
30+
<button
31+
type="button"
32+
className="btn btn-basic btn-sm"
33+
onClick={() => this.props.page(paginationRoute(this.props.view['{{{ hydraPrefix }}}previous']))}
34+
disabled={!this.props.view['{{{ hydraPrefix }}}previous']}
35+
>Previous</button>
36+
&nbsp;
37+
<button
38+
type="button" className="btn btn-basic btn-sm"
39+
onClick={() => this.props.page(paginationRoute(this.props.view['{{{ hydraPrefix }}}next']))}
40+
disabled={!this.props.view['{{{ hydraPrefix }}}next']}
41+
>Next</button>
42+
&nbsp;
43+
<button
44+
type="button" className="btn btn-basic btn-sm"
45+
onClick={() => this.props.page(paginationRoute(this.props.view['{{{ hydraPrefix }}}last']))}
46+
disabled={!this.props.view['{{{ hydraPrefix }}}next']}
47+
>Last</button>
48+
&nbsp;
49+
</span>
50+
);
51+
}
52+
1953
componentDidMount() {
2054
this.props.list();
2155
}
@@ -31,6 +65,7 @@ class List extends Component {
3165
{this.props.loading && <div className="alert alert-info">Loading...</div>}
3266
{this.props.deletedItem && <div className="alert alert-success">{this.props.deletedItem['@id']} deleted.</div>}
3367
{this.props.error && <div className="alert alert-danger">{this.props.error}</div>}
68+
{this.pagination()}
3469

3570
<div className="table-responsive">
3671
<table className="table table-striped table-hover">
@@ -80,12 +115,14 @@ const mapStateToProps = (state) => {
80115
error: state.{{{ lc }}}.list.error,
81116
loading: state.{{{ lc }}}.list.loading,
82117
deletedItem: state.{{{ lc }}}.del.deleted,
118+
view: state.{{{ lc }}}.list.view,
83119
};
84120
};
85121

86122
const mapDispatchToProps = (dispatch) => {
87123
return {
88124
list: () => dispatch(list()),
125+
page: (arg) => dispatch(page(arg)),
89126
reset: () => {
90127
dispatch(reset());
91128
dispatch(success(null));

templates/react/reducers/foo/list.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { combineReducers } from 'redux'
1+
import {combineReducers} from 'redux'
22

33
export function error(state = null, action) {
44
switch (action.type) {
@@ -39,4 +39,14 @@ export function items(state = [], action) {
3939
}
4040
}
4141

42-
export default combineReducers({error, loading, items});
42+
export function view(state = [], action) {
43+
switch (action.type) {
44+
case '{{{ uc }}}_LIST_VIEW':
45+
return action.items;
46+
47+
default:
48+
return state;
49+
}
50+
}
51+
52+
export default combineReducers({error, loading, items, view});

templates/react/utils/helpers.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,7 @@ function createLink(item) {
2626
}
2727
return <span key={item}>{item}<br/></span>;
2828
}
29+
30+
export function paginationRoute(item) {
31+
return '/' + item.split('/').splice(-1,1);
32+
}

0 commit comments

Comments
 (0)