Skip to content

Commit

Permalink
Merge pull request #29 from blairg/finish_off_redux
Browse files Browse the repository at this point in the history
Finish off redux
  • Loading branch information
blairg committed Dec 21, 2017
2 parents 0972822 + 1e1d249 commit 88b1cb2
Show file tree
Hide file tree
Showing 18 changed files with 140 additions and 36 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"function-paren-newline": 0,
"import/extensions": 0,
"jsx-a11y/label-has-for": 0,
"react/forbid-prop-types": 0
"react/forbid-prop-types": 0,
"react/require-default-props": 0
}
}
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:8.9.1-alpine
FROM node:8.9.3-alpine
MAINTAINER blair.garrett1@gmail.com
LABEL maintainer="blair.garrett1@gmail.com"

Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ I've written a [blog article](http://hackerlite.xyz/2017/12/13/boilerplate-for-h

## Get it running locally 🏌️

Assuming you are on Mac OS 🍏. Not tested on any other OS.
Assuming you are on Mac OS 🍏 and Node 8.9.3 or higher installed. Not tested on any other OS.

In the terminal run the following: -

Expand Down Expand Up @@ -49,6 +49,10 @@ Following options: -

* In the terminal run ESLint with -> `npm run lint`

## Prettier 🙏

* In the terminal run Prettier with -> `npm run pretty`

## Issues 🤒

If you find anything wrong with this repo post them [here please](https://github.com/blairg/hapi-socket-react-boilerplate/issues).
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
"winston": "^2.4.0"
},
"engines": {
"node": "8.9.1",
"npm": "5.5.1"
"node": "8.9.3",
"npm": "5.6.0"
}
}
11 changes: 11 additions & 0 deletions pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/sh

echo "pre-commit hook"

echo "running -> npm test"
# Run tests
npm test

echo "running -> npm run pretty"
# Run prettier before committing
npm run pretty
1 change: 1 addition & 0 deletions src/client/actionTypes/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const SET_TITLE = 'SET_TITLE';
export const SET_BODY = 'SET_BODY';
export const ADD_POST = 'ADD_POST';
export const SET_TODOS = 'SET_TODOS';
7 changes: 7 additions & 0 deletions src/client/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,10 @@ export function addPost() {
}
};
}

export function setTodos(todos) {
return {
type: actionTypes.SET_TODOS,
todos,
};
}
2 changes: 1 addition & 1 deletion src/client/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import thunkMiddleware from 'redux-thunk';
import { createLogger } from 'redux-logger';
import rootReducer from './reducers';

import Todos from './components/presentation/todos.jsx';
import Todos from './components/containers/todos.jsx';

import CacheService from './services/cacheService';

Expand Down
13 changes: 8 additions & 5 deletions src/client/components/containers/createTodo.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
/* eslint-disable no-console */
/* eslint-disable react/require-default-props */

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
Expand All @@ -9,14 +6,19 @@ import Axios from 'axios';
import { setTitle, setBody, addPost } from './../../actions';

class CreateTodo extends React.Component {
static handleDelete(event) {
Axios.delete('/todos')
static async handleDelete(event) {
let success = true;

await Axios.delete('/todos')
.then(() => {})
.catch(error => {
success = false;
console.error(error);
});

event.preventDefault();

return success;
}

render() {
Expand Down Expand Up @@ -98,6 +100,7 @@ CreateTodo.propTypes = {
body: PropTypes.string,
};

/* istanbul ignore next */
const mapDispatchToProps = dispatch => ({
titleChange: event => {
dispatch(setTitle(event.target.value));
Expand Down
1 change: 1 addition & 0 deletions src/client/components/containers/todo.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class Todo extends React.Component {
this.tick = this.tick.bind(this);
}

/* istanbul ignore next */
componentDidMount() {
this.timer = setInterval(this.tick, 1000);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
/* eslint-disable import/extensions */
/* eslint-disable react/forbid-prop-types */

import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import { setTodos } from './../../actions';
import subscribeToTodos from '../../subscribers/todoSubscriber';
import CreateTodo from '../containers/createTodo.jsx';
import Todo from '../containers/todo.jsx';
Expand All @@ -28,32 +27,36 @@ class Todos extends React.Component {

return entriesNew;
}
constructor(props) {
super(props);
this.state = {
entries: props.entries ? props.entries : [],
};
}

/* istanbul ignore next */
componentDidMount() {
subscribeToTodos(data =>
this.setState({
entries: data,
}),
);
/* istanbul ignore next */
subscribeToTodos(data => this.props.dispatchTodos(data));
}

render() {
const entries = Todos.getEntries(
this.state.entries ? this.state.entries : this.props.entries,
);

return <CreateTodo entries={entries} />;
return <CreateTodo entries={Todos.getEntries(this.props.entries)} />;
}
}

Todos.propTypes = {
entries: PropTypes.array.isRequired,
dispatchTodos: PropTypes.func.isRequired,
};

/* istanbul ignore next */
const mapDispatchToProps = dispatch => ({
dispatchTodos: todos => {
dispatch(setTodos(todos));
},
});

const mapStateToProps = state => {
const { todos } = state.setTodos;

return {
entries: todos,
};
};

export default Todos;
export default connect(mapStateToProps, mapDispatchToProps)(Todos);
10 changes: 10 additions & 0 deletions src/client/reducers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,20 @@ export function addPost(state = { post: { title: '', body: '' } }, action) {
}
}

export function setTodos(state = { todos: [] }, action) {
switch (action.type) {
case actionTypes.SET_TODOS:
return { ...state, todos: action.todos };
default:
return state;
}
}

const rootReducer = combineReducers({
setTitle,
setBody,
addPost,
setTodos,
});

export default rootReducer;
2 changes: 1 addition & 1 deletion src/server/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import rootReducer from './../../client/reducers';
import CacheServiceImport from './../services/cacheService';

// React Components
import Todos from './../../client/components/presentation/todos.jsx';
import Todos from './../../client/components/containers/todos.jsx';
import Index from './../../client/components/presentation/index.jsx';

const loggerMiddleware = createLogger();
Expand Down
13 changes: 13 additions & 0 deletions test/client/actions/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
setTitle,
setBody,
addPost,
setTodos,
} from './../../../src/client/actions/index';

const sandbox = sinon.sandbox.create();
Expand Down Expand Up @@ -91,4 +92,16 @@ describe('client/actions/index', () => {
sinon.assert.notCalled(dispatch);
});
});

describe('setTodos', () => {
it('should create an action to set todos', () => {
const todos = { title: 'my title', body: 'my body', timestamp: 2131231 };
const expected = {
type: actionTypes.SET_TODOS,
todos,
};

assert.deepEqual(setTodos(todos), expected);
});
});
});
46 changes: 46 additions & 0 deletions test/client/components/containers/createTodo.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* eslint-disable no-undef */
/* eslint-disable react/jsx-filename-extension */
/* eslint-disable import/extensions */

import assert from 'assert';
import sinon from 'sinon';
import Axios from 'axios';
import MockAdapter from 'axios-mock-adapter';

import CreateTodo from './../../../../src/client/components/containers/createTodo.jsx';

const sandbox = sinon.sandbox.create();
let mockAxios;

describe('client/components/containers/createTodo -> <CreateTodo />', () => {
const event = { preventDefault: () => {} };

beforeEach(() => {
mockAxios = new MockAdapter(Axios);
sandbox.stub(event, 'preventDefault');
sandbox.stub(console, 'error');
});

afterEach(() => {
mockAxios.reset();
sandbox.restore();
});

describe('CreateTodo.handleDelete(event)', () => {
it('should call Axios.delete and event.preventDefault()', async () => {
mockAxios.onDelete('/todos').reply(200);
const success = await CreateTodo.handleDelete(event);

assert.equal(event.preventDefault.called, true);
assert.equal(success, true);
});

it('should call Axios.delete and throw error', async () => {
mockAxios.onDelete('/todos').networkError();
const success = await CreateTodo.handleDelete(event);

assert.equal(event.preventDefault.called, true);
assert.equal(success, false);
});
});
});
8 changes: 5 additions & 3 deletions test/client/components/presentation/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import Todos from './../../../../src/client/components/presentation/todos.jsx';
import Todos from './../../../../src/client/components/containers/todos.jsx';
import Index from './../../../../src/client/components/presentation/index.jsx';

const middlewares = [];
const mockStore = configureStore(middlewares);
const initialState = {};
const store = mockStore(initialState);

const sandbox = sinon.sandbox.create();

Expand All @@ -29,6 +27,10 @@ describe('client/components/presentation/index -> <Index todos={todos} />', () =

it('should contain body and title in the Index component', () => {
const todo = { title: 'my title', body: 'my body' };

const initialState = { setTodos: { todos: [todo] } };
const store = mockStore(initialState);

const todosComponent = (
<Provider store={store}>
<Todos entries={[todo]} />
Expand Down

0 comments on commit 88b1cb2

Please sign in to comment.