Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"dependencies": {
"axios": "^0.16.1",
"babel-polyfill": "^6.23.0",
"jsonapi-serializer": "^3.5.2",
"lodash": "^4.17.4",
"object-path-immutable": "^0.5.1",
"react": "^15.4.2",
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Categories/CategoryEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class CategoryEdit extends Component {
<Link to={`/categories`}>Back to Categories</Link>
</p>

<h2>{ isNew ? 'New Category' : category.attributes.name }</h2>
<h2>{ isNew ? 'New Category' : category.name }</h2>

<pre>{ JSON.stringify(category, null, 2) }</pre>
</div>
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Categories/CategoryList.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class CategoryList extends Component {
<div>
{categories.data.map(category =>
<div key={category.id}>
<Link to={`/categories/${category.id}`}>{category.attributes.name}</Link>
<Link to={`/categories/${category.id}`}>{category.name}</Link>
</div>
)}
</div>
Expand Down
22 changes: 3 additions & 19 deletions client/src/components/Posts/PostEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,11 @@ export class PostEdit extends Component {

onSubmit = (values) => {
const { params, post, categories, createResource, updateResource, redirectToIndex } = this.props;
const relationships = {
category: {
data: {
type: 'categories',
}
},
};

values.relationships.category.data.type = 'categories';

// TODO find better way to manage new/edit payload
const payload = omit({
const payload = {
id: post.id,
relationships,
...values,
type: 'posts',
},
'links',
'relationships.category.links',
'relationships.comments'
);
};

if (!params.id) {
createResource(payload).then(redirectToIndex);
Expand All @@ -72,7 +56,7 @@ export class PostEdit extends Component {
<Link to={`/posts`}>Back to Posts</Link>
</p>

<h2>{ isNew ? 'New Post' : post.attributes.title }</h2>
<h2>{ isNew ? 'New Post' : post.title }</h2>

{ !isNew &&
<p>
Expand Down
14 changes: 7 additions & 7 deletions client/src/components/Posts/PostForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ class PostForm extends Component {

const categoriesOptions = categories.map(category => ({
id: category.id,
name: category.attributes.name,
name: category.name,
}));

return (
<form onSubmit={handleSubmit}>
<div>
<Field name="attributes.title" component={InputField} />
<Field name="title" component={InputField} />
</div>
<div>
<Field name="relationships.category.data.id" component={SelectField}
<Field name="category.id" component={SelectField}
options={categoriesOptions} />
</div>
<div>
<Field name="attributes.body" component={TextArea} rows="10" />
<Field name="body" component={TextArea} rows="10" />
</div>
<div>
<button type="submit" disabled={pristine || submitting}>Submit</button>
Expand All @@ -36,9 +36,9 @@ class PostForm extends Component {

const validate = values => {
const errors = required(values,
'attributes.title',
'relationships.category.data.id',
'attributes.body'
'title',
'category.id',
'body'
);
return errors;
};
Expand Down
12 changes: 6 additions & 6 deletions client/src/components/Posts/PostList.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export class PostList extends Component {
}

getCategoryForPost(post) {
const categoryId = get(post, 'relationships.category.data.id');
return this.props.categoriesById[categoryId] || { attributes: {} };
const categoryId = String(get(post, 'category.id'));
return this.props.categoriesById[categoryId] || {};
}

fetchPage = (url) => (e) => {
Expand All @@ -24,10 +24,10 @@ export class PostList extends Component {

onFilter = (filter) => {
this.props.fetchPosts(filter);
}
};

render() {
const { posts, categoriesById, categories } = this.props;
const { posts, categories } = this.props;
const { prev, next } = posts.links;

return (
Expand All @@ -38,8 +38,8 @@ export class PostList extends Component {
<PostListFilter onSubmit={this.onFilter} categories={categories}></PostListFilter>
{posts.data.map(post =>
<div key={post.id}>
<Link to={`/posts/${post.id}`}>{post.attributes.title}</Link>
({this.getCategoryForPost(post).attributes.name})
<Link to={`/posts/${post.id}`}>{post.title}</Link>
({this.getCategoryForPost(post).name})
</div>
)}
<p>
Expand Down
8 changes: 6 additions & 2 deletions client/src/components/Posts/PostListFilter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ class PostListFilter extends Component {

const categoriesOptions = categories.map(category => ({
id: category.id,
name: category.attributes.name,
name: category.name,
}));
categoriesOptions.unshift({ id: "", name: 'All categories'})

categoriesOptions.unshift({
id: '',
name: 'All categories'
});

return (
<form onSubmit={handleSubmit}>
Expand Down
53 changes: 53 additions & 0 deletions client/src/store/api/__snapshots__/normalize.spec.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`normalize categories denormalize 1`] = `
Object {
"data": Object {
"attributes": Object {
"name": "Category 11",
},
"id": "11",
"type": "categories",
},
}
`;

exports[`normalize categories normalize 1`] = `
Object {
"id": "11",
"name": "Category 11",
}
`;

exports[`normalize posts denormalize 1`] = `
Object {
"data": Object {
"attributes": Object {
"body": "Body 1",
"title": "Title 1",
},
"id": "1",
"relationships": Object {
"category": Object {
"data": Object {
"id": "11",
"type": "categories",
},
},
},
"type": "posts",
},
}
`;

exports[`normalize posts normalize 1`] = `
Object {
"body": "Body 1",
"category": Object {
"id": "11",
"name": undefined,
},
"id": "1",
"title": "Title 1",
}
`;
20 changes: 14 additions & 6 deletions client/src/store/api/client.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import qs from 'qs';
import axios from 'axios';
import { isEmpty, toArray } from 'lodash';
import { get, isEmpty, toArray } from 'lodash';

import { denormalize, normalize, normalizeEach } from './normalize';

export const GET_ONE = 'GET_ONE';
export const GET_LIST = 'GET_LIST';
Expand All @@ -26,21 +28,27 @@ export default (request, payload, meta) => {
url = `${meta.key}`,
} = meta;

const normalizeResponse = response => Promise.all([
normalize(meta.key, get(response, 'data')),
normalizeEach(get(response, 'data.included')),
]).then(([data, included]) => ({...response.data, data, included}));

const params = payload;

switch(request) {
case CREATE:
return client({
url: withParams(url),
method: 'POST',
data: { data: payload },
data: denormalize(meta.key, payload),
}).then(response => response.data);
case UPDATE:
case UPDATE: {
return client({
url: withParams(`${url}/${payload.id}`),
method: 'PUT',
data: { data: payload },
data: denormalize(meta.key, payload),
}).then(response => response.data);
}
case DELETE:
return client({
url: withParams(`${url}/${payload.id}`),
Expand All @@ -51,12 +59,12 @@ export default (request, payload, meta) => {
url: withParams(`${url}/${payload.id}`, params),
method: 'GET',
data: JSON.stringify(payload),
}).then(response => response.data);
}).then(normalizeResponse);
default:
return client({
url: withParams(`${url}`, params),
method: 'GET',
data: JSON.stringify(payload),
}).then(response => response.data);
}).then(normalizeResponse);
}
};
45 changes: 45 additions & 0 deletions client/src/store/api/normalize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { omit } from 'lodash';
import { Deserializer, Serializer } from 'jsonapi-serializer';

const serializers = {
categories: {
serializer: new Serializer('categories', {
attributes: [
'name',
],
}),
deserializer: new Deserializer({}),
},

posts: {
serializer: new Serializer('posts', {
attributes: [
'title',
'body',
'category',
],
category: {
ref: 'id',
included: false,
attributes: ['name'],
}
}),
deserializer: new Deserializer({
categories: {
valueForRelationship: (relationship) => ({
id: relationship.id,
name: relationship.name,
}),
}
}),
},
};

export const normalize = (type, data) => serializers[type].deserializer.deserialize(data);

export const normalizeEach = (items = []) => items.map(item => serializers[item.type].deserializer.deserialize({data: item}));

export const denormalize = (type, data) => {
const res = serializers[type].serializer.serialize(data);
return data.id ? res : omit(res, 'data.id');
};
31 changes: 31 additions & 0 deletions client/src/store/api/normalize.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { denormalize, normalize } from './normalize';

const testNormalize = (type, values) => {
describe(type, () => {
it('denormalize', () => {
expect(denormalize(type, values)).toMatchSnapshot();
});

it('normalize', async () => {
return (normalize(type, denormalize(type, values)))
.then(res => expect(res).toMatchSnapshot());
});
});
};

describe('normalize', () => {
testNormalize('categories', {
id: 11,
name: 'Category 11',
});

testNormalize('posts', {
id: 1,
title: 'Title 1',
body: 'Body 1',
category: {
id: 11,
name: 'Category 11',
},
});
});