Skip to content
Open
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 package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"isomorphic-fetch": "^2.2.1",
"path": "^0.12.7",
"prop-types": "^15.5.8",
"query-string": "^4.3.4",
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-redux": "^5.0.5",
Expand Down
3 changes: 3 additions & 0 deletions src/actions/actionTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Library actions
export const LIBRARY_LIST_BOOKS = 'LIBRARY_LIST_BOOKS';
export const LIBRARY_SHOW_SINGLE_BOOK = 'LIBRARY_SHOW_SINGLE_BOOK';
12 changes: 12 additions & 0 deletions src/config/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default {
serverPort: 3000,
baseUrl: 'http://localhost:3000',
api: {
url: '/api/'
},
views: {
engine: '.hbs',
extension: '.hbs',
path: './views'
}
}
6 changes: 6 additions & 0 deletions src/constants/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const API = Object.freeze({
LIBRARY: {
BOOK: 'library/book',
BOOKS: 'library/books'
}
});
19 changes: 19 additions & 0 deletions src/containers/Library/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Actions Types
import * as types from '../../actions/actionTypes';

// Api
import libraryApi from './api';

export function loadBooks() {
return {
type: types.LIBRARY_LIST_BOOKS,
payload: libraryApi.getAllBooks()
};
}

export function loadSingleBook(query) {
return {
type: types.LIBRARY_SHOW_SINGLE_BOOK,
payload: libraryApi.getSingleBook(query)
};
}
17 changes: 17 additions & 0 deletions src/containers/Library/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Constants
import { API } from '../../constants/api';

// Utils
import { apiFetch } from '../../lib/utils/api';

class LibraryApi {
static getAllBooks(query) {
return apiFetch(API.LIBRARY.BOOKS, {}, query);
}

static getSingleBook(query) {
return apiFetch(API.LIBRARY.BOOK, {}, query);
}
}

export default LibraryApi;
133 changes: 133 additions & 0 deletions src/containers/Library/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Dependencies
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';

// Actions
import * as actions from '../../containers/Library/actions';

// Utils
import { isFirstRender } from '../../lib/utils/frontend';

class Library extends Component {
static propTypes = {
loadBooks: PropTypes.func.isRequired,
books: PropTypes.array.isRequired,
book: PropTypes.array
};

constructor(props) {
super(props);

this.state = {
displaySingleBook: false
};
}

componentWillMount() {
const {
match: {
params: {
id = 0
}
}
} = this.props;

if (id > 0) {
this.setState({
displaySingleBook: true
});

this.props.loadSingleBook({ id });
} else {
this.setState({
displaySingleBook: false
});

this.props.loadBooks();
}
}

componentWillReceiveProps(nextProps) {
const {
match: {
params: {
id = 0
}
}
} = nextProps;

if (nextProps.match.params !== this.props.match.params) {
if (id > 0) {
this.setState({
displaySingleBook: true
});

this.props.loadSingleBook({ id });
} else {
this.setState({
displaySingleBook: false
});
}
}
}

renderSingleBook(book) {
return (
<div>
<h1>{book.title}</h1>
<p>Autor: {book.author}</p>
<p><img src={book.image} style={{ maxWidth: '300px' }} /></p>
<p><Link to="/library">Go back</Link></p>
</div>
);
}

renderBooksList(books) {
return (
<div>
<h1>Library</h1>
<ul>
{
books.map((book, key) => {
return (
<li key={key}>
<Link to={`/library/${book.id}`}>{book.title}</Link> - {book.author}
</li>
)
})
}
</ul>
</div>
);
}

render() {
const {
books,
book
} = this.props;

if (isFirstRender(books) && book.length === 0) {
return null;
}

let show = this.renderBooksList(books);

if (this.state.displaySingleBook && book.length > 0) {
show = this.renderSingleBook(book[0]);
}

return (
<div className="Home">
{show}
</div>
);
}
}

export default connect(state => ({
books: state.library.books,
book: state.library.book
}), actions)(Library);
30 changes: 30 additions & 0 deletions src/containers/Library/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Utils
import { getNewState } from '../../lib/utils/frontend';

const initialState = {
books: [],
book: []
};

export default function libraryReducer(state = initialState, action) {
switch (action.type) {
case 'LIBRARY_LIST_BOOKS_SUCCESS': {
const { payload: { response = [] } } = action;

return getNewState(state, {
books: response
});
}

case 'LIBRARY_SHOW_SINGLE_BOOK_SUCCESS': {
const { payload: { response = [] } } = action;

return getNewState(state, {
book: response
});
}

default:
return state;
}
}
34 changes: 34 additions & 0 deletions src/data/books.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"response": [
{
"id": 1,
"title": "El Señor de los Anillos",
"author": "J. R. R. Tolkien",
"image": "https://imagessl7.casadellibro.com/a/l/t0/87/9788445000687.jpg"
},
{
"id": 2,
"title": "Padre Rico Padre Pobre",
"author": "Robert Kiyosaki",
"image": "https://imagessl2.casadellibro.com/a/l/t0/02/9788466317702.jpg"
},
{
"id": 3,
"title": "El Tao de Warren Buffett",
"author": "Mary Buffett",
"image": "https://imagessl6.casadellibro.com/a/l/t0/56/9788493562656.jpg"
},
{
"id": 4,
"title": "Burlar al Diablo. Secretos desde la Cripta",
"author": "Napoleon Hill",
"image": "https://images-na.ssl-images-amazon.com/images/I/41DcYrw4upL._SX311_BO1,204,203,200_.jpg"
},
{
"id": 5,
"title": "El Alquimista",
"author": "Paulo Coelho",
"image": "http://libros-gratis.com/wp-content/uploads/2015/12/el-alquimista.jpg"
}
]
}
4 changes: 4 additions & 0 deletions src/data/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,9 @@ export default [
{
title: 'Contact Us',
url: '/contact'
},
{
title: 'Library',
url: '/library'
}
];
16 changes: 0 additions & 16 deletions src/data/post.json

This file was deleted.

1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Dependencies
import 'babel-polyfill';
import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
Expand Down
59 changes: 59 additions & 0 deletions src/lib/utils/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Dependencies
import queryString from 'query-string';

// Config
import config from '../../config';

export function apiEndpoint(endpoint, qs) {
let query = '';

if (qs) {
query = `?${qs}`;
}

return `${config.api.url}${endpoint}${query}`;
}

export function apiFetch(endpoint, options = {}, query = false) {
let qs;

if (query) {
qs = queryString.stringify(query);
}

const getPromise = async () => {
try {
const fetchOptions = apiOptions(options);
const fetchEndpoint = apiEndpoint(endpoint, qs);
const response = await fetch(fetchEndpoint, fetchOptions);

return response.json();
} catch (e) {
throw e;
}
};

return getPromise();
}

export function apiOptions(options = {}) {
const {
method = 'GET',
headers = {
'Content-Type': 'application/json'
},
body = false
} = options;

const newOptions = {
method,
headers,
credentials: 'include'
};

if (body) {
newOptions.body = body;
}

return newOptions;
}
9 changes: 9 additions & 0 deletions src/lib/utils/frontend.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { isDefined } from './is';

export function getNewState(state, newState) {
return Object.assign({}, state, newState);
}

export function isFirstRender(items) {
return items && items.length === 0 || !isDefined(items);
}
15 changes: 15 additions & 0 deletions src/lib/utils/is.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export function isArray(variable) {
return variable instanceof Array;
}

export function isDefined(variable) {
return typeof variable !== 'undefined' && variable !== null;
}

export function isFunction(variable) {
return typeof variable === 'function';
}

export function isObject(variable) {
return isDefined(variable) && typeof variable === 'object';
}
Loading