Skip to content

Commit faf238f

Browse files
committed
Crud for products
1 parent 3132d60 commit faf238f

File tree

9 files changed

+153
-2
lines changed

9 files changed

+153
-2
lines changed

app/resources/product_resource.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
class ProductResource < JSONAPI::Resource
2-
attributes :product_name
2+
attributes :product_name, :created_at
3+
4+
paginator :paged
35
end

client/src/api/normalize.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,19 @@ const serializers = {
5858
}),
5959
},
6060

61+
products: {
62+
serializer: new Serializer('products', {
63+
keyForAttribute: 'camelCase',
64+
attributes: [
65+
'productName',
66+
'createdAt'
67+
],
68+
}),
69+
deserializer: new Deserializer({
70+
keyForAttribute: 'camelCase',
71+
}),
72+
},
73+
6174
roles: {
6275
serializer: new Serializer('roles', {
6376
keyForAttribute: 'camelCase',

client/src/components/App.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ export class App extends Component {
4343
userIsAdmin && <NavLink href="/#/users">Users</NavLink>
4444
}
4545
</NavItem>
46+
<NavItem>
47+
<NavLink href="/#/products">Products</NavLink>
48+
</NavItem>
4649
</Nav>
4750
<Nav navbar className="ml-auto">
4851
<NavDropdown isOpen={this.state.isOpen} toggle={this.toggle}>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React, { Component, PropTypes } from 'react';
2+
import { push } from 'react-router-redux';
3+
import { connect } from 'react-redux';
4+
5+
import { ErrorAlert, Loading, EditHeader } from '../UI';
6+
import { withResource } from '../../hocs';
7+
import ProductForm from './ProductForm';
8+
import { getMany, fetchList } from '../../store/api';
9+
10+
export class ProductEdit extends Component {
11+
componentWillMount() {
12+
const { params, fetchResource } = this.props;
13+
14+
if (params.id) {
15+
fetchResource({ id: params.id });
16+
}
17+
}
18+
19+
render() {
20+
const { isNew, error, loading, resource, onSubmit } = this.props;
21+
22+
if (error) {
23+
return (<ErrorAlert {...error} />);
24+
}
25+
26+
if (loading) {
27+
return (<Loading />);
28+
}
29+
30+
return (
31+
<div>
32+
<EditHeader {...this.props}>{ isNew ? 'New Product' : resource.productName }</EditHeader>
33+
<ProductForm initialValues={resource} onSubmit={onSubmit}></ProductForm>
34+
</div>
35+
);
36+
}
37+
}
38+
39+
40+
export const mapDispatchToProps = dispatch => ({
41+
redirectToIndex: () => dispatch(push('/products')),
42+
});
43+
44+
export default connect(null, mapDispatchToProps)(
45+
withResource('products')(ProductEdit),
46+
);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React, { Component, PropTypes } from 'react';
2+
import { isEmpty } from 'lodash';
3+
import { Field, reduxForm } from 'redux-form';
4+
import { Button, Form } from 'reactstrap';
5+
6+
import { InputField, MultiselectField, required } from '../../forms';
7+
8+
class ProductForm extends Component {
9+
render() {
10+
const { handleSubmit, pristine, reset, submitting } = this.props;
11+
12+
return (
13+
<Form onSubmit={handleSubmit}>
14+
<div>
15+
<Field
16+
name="productName"
17+
label="Name"
18+
component={InputField}
19+
/>
20+
</div>
21+
<div>
22+
<Button disabled={pristine || submitting} color="primary">Submit</Button>
23+
<Button disabled={pristine || submitting} onClick={reset}>Undo Changes</Button>
24+
</div>
25+
</Form>
26+
);
27+
}
28+
}
29+
30+
const validate = (values) => {
31+
const errors = required(values, 'productName');
32+
return errors;
33+
};
34+
35+
export default reduxForm({
36+
enableReinitialize: true,
37+
form: 'product',
38+
validate,
39+
})(ProductForm);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React, { Component, PropTypes } from 'react';
2+
import { Link } from 'react-router';
3+
import { find, keyBy } from 'lodash';
4+
5+
import { ListTable } from '../UI';
6+
import { withResourceList } from '../../hocs';
7+
import { Button } from 'reactstrap';
8+
9+
const formatDate = date => (new Date(date)).toLocaleString();
10+
11+
export class ProductList extends Component {
12+
componentWillMount() {
13+
const { resourceList } = this.props;
14+
this.props.fetchResourceList({ sort: '-createdAt', ...resourceList.params });
15+
}
16+
17+
render() {
18+
const columns = [
19+
{
20+
attribute: 'productName',
21+
header: 'Name',
22+
rowRender: product => <Link to={`/products/${product.id}`}>{product.productName}</Link>,
23+
sortable: true,
24+
},
25+
{
26+
attribute: 'createdAt',
27+
header: 'Created At',
28+
rowRender: product => formatDate(product.createdAt),
29+
sortable: true,
30+
}
31+
];
32+
33+
return (
34+
<div>
35+
<Button tag={Link} to={'/products/new'}>New Product</Button>
36+
<ListTable {...this.props} columns={columns} />
37+
</div>
38+
);
39+
}
40+
}
41+
42+
export default withResourceList('products')(ProductList);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export ProductList from './ProductList';
2+
export ProductEdit from './ProductEdit';

client/src/components/Routes.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { PostList, PostEdit } from './Posts';
99
import { CategoryList, CategoryEdit } from './Categories';
1010
import { UserList, UserEdit } from './Users';
1111
import { Login } from './Auth';
12+
import { ProductList, ProductEdit } from './Products';
1213

1314
const UserIsAuthenticated = UserAuthWrapper({ authSelector: getUser });
1415
const UserIsAdmin = UserAuthWrapper({
@@ -34,6 +35,9 @@ export class Routes extends PureComponent {
3435
<Route path="/categories" component={CategoryList}/>
3536
<Route path="/users" component={UserIsAdmin(UserList)}/>
3637
<Route path="/users/:id" component={UserIsAdmin(UserEdit)}/>
38+
<Route path="/products" component={ProductList}/>
39+
<Route path="/products/new" component={ProductEdit}/>
40+
<Route path="/products/:id" component={ProductEdit}/>
3741
</Route>
3842
<Route path="/login" component={Login}/>
3943
</Router>

config/routes.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
jsonapi_resources :categories
44
jsonapi_resources :comments
55
jsonapi_resources :posts
6-
jsonapi_resources :products
76
jsonapi_resources :users
87
jsonapi_resources :roles
98
jsonapi_resources :orders
109
jsonapi_resources :customers
1110
jsonapi_resources :suppliers
11+
jsonapi_resources :products
1212
end

0 commit comments

Comments
 (0)