diff --git a/client/client.js b/client/client.js index 8b13789..2464ca2 100644 --- a/client/client.js +++ b/client/client.js @@ -1 +1,28 @@ +import React from 'react'; +import {render} from 'react-dom'; +import App from '../components/App'; +import configureStore from '../redux/store'; +import { Provider } from 'react-redux'; +//configure and create our store +//var store = createStore (reducers, initialState) // [] + +let initialState = { + todos: [{ + id: 0, + completed: false, + text: 'Initial todo for demo purposes' + }] +} + +let store = configureStore(initialState) + + + +render ( + + + +, document.getElementById('app') + +) diff --git a/client/index.html b/client/index.html index 7a2106d..4c0c135 100644 --- a/client/index.html +++ b/client/index.html @@ -5,7 +5,6 @@ React Todo List -

This is not a React app yet!

diff --git a/components/App.js b/components/App.js index 8b13789..6f50b56 100644 --- a/components/App.js +++ b/components/App.js @@ -1 +1,33 @@ +import React, {Component} from 'react'; +import TodoInput from './TodoInput'; +import TodoList from './TodoList'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import actions from '../redux/actions'; + +class App extends Component { + render(){ + return( +
+ +

Todo List

+ + +
+ ) + } +} + +function mapStateToProps(state) { + return state +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators(actions, dispatch) + } +} + + +export default connect(mapStateToProps, mapDispatchToProps)(App); diff --git a/components/TodoInput.js b/components/TodoInput.js new file mode 100644 index 0000000..8bdc86f --- /dev/null +++ b/components/TodoInput.js @@ -0,0 +1,37 @@ +import React, {Component} from 'react'; + +class TodoInput extends Component { + constructor(props){ + super(props) + this.state = { + inputText: '' + } + } + + handleChange(event){ + this.setState({inputText: event.target.value}) + } + +handleSubmit(event) { + event.preventDefault() + this.props.addTodo(this.state.inputText) +} + + + render(){ + return ( +
+
+ + +
+
+ ) + } +} + +export default TodoInput; diff --git a/components/TodoItem.js b/components/TodoItem.js new file mode 100644 index 0000000..4dc6c02 --- /dev/null +++ b/components/TodoItem.js @@ -0,0 +1,27 @@ +import React, {Component} from 'react'; + +class TodoItem extends Component { + + handleComplete () { + this.props.actions.completeTodo(this.props.todo.id) + } + + handleDelete(){ + this.props.actions.deleteTodo(this.props.todo.id) + + } + + + + render(){ + return ( +
  • +
    {this.props.todo.text}
    + + + +
  • + ) + } +} +export default TodoItem; diff --git a/components/TodoList.js b/components/TodoList.js new file mode 100644 index 0000000..f184f06 --- /dev/null +++ b/components/TodoList.js @@ -0,0 +1,20 @@ +import React, {Component} from 'react'; +import TodoItem from './TodoItem'; + +class TodoList extends Component { + + render(){ + return ( + + ) + } +} +export default TodoList; diff --git a/package.json b/package.json index 034be19..22e9495 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,15 @@ "babel-loader": "^6.2.2", "babel-preset-es2015": "^6.3.13", "babel-preset-react": "^6.3.13", + "babel-preset-react-hmre": "^1.1.1", "express": "^4.13.4", "react": "^0.14.7", "react-dom": "^0.14.7", - "webpack": "^1.12.13" + "react-redux": "^5.0.4", + "redux": "^3.6.0", + "redux-logger": "^3.0.1", + "webpack": "^1.12.13", + "webpack-dev-middleware": "^1.10.2", + "webpack-hot-middleware": "^2.18.0" } } diff --git a/redux/actions.js b/redux/actions.js new file mode 100644 index 0000000..d8baf24 --- /dev/null +++ b/redux/actions.js @@ -0,0 +1,24 @@ +let actions = { + addTodo: function(text) { + return { + type: 'ADD_TODO', + text: text + } + }, + + completeTodo: function (id){ + return { + type: 'COMPLETE_TODO', + id: id + } + }, + + deleteTodo: function (id) { + return { + type: 'DELETE_TODO', + id:id + } + } +} + +export default actions; diff --git a/redux/reducer.js b/redux/reducer.js new file mode 100644 index 0000000..d2ce8fd --- /dev/null +++ b/redux/reducer.js @@ -0,0 +1,39 @@ +function getId(state){ + return state.todos.reduce((maxId, todo) => { + return Math.max(todo.id, maxId) + },-1) + 1 +} + + +let reducer = function (state, action) { + switch (action.type) { + case 'ADD_TODO': + console.log('got to correct add todo'); + return Object.assign({}, state, { + todos: [{ + text: action.text, + completed: false, + id: getId(state) + }, ...state.todos] + }) + case 'COMPLETE_TODO': + console.log('COMPLETE_TODO'); + return Object.assign({}, state, { + todos: state.todos.map((todo) => { + return todo.id === action.id ? + Object.assign({}, todo, {completed: !todo.completed}) : todo + }) + }) + case 'DELETE_TODO': + console.log('DELETE_TODO'); + return Object.assign({}, state, { + todos: state.todos.filter((todo) => { + return todo.id !== action.id + }) + }) + default: + return state; + } +} + +export default reducer; diff --git a/redux/store.js b/redux/store.js new file mode 100644 index 0000000..9d9e79b --- /dev/null +++ b/redux/store.js @@ -0,0 +1,12 @@ +import { applyMiddleware, compose, createStore } from 'redux'; +import reducer from './reducer'; +import { createLogger } from 'redux-logger'; + +let finalCreateStore = compose ( + applyMiddleware(createLogger()) +)(createStore) + + +export default function configureStore (initialState = { todos: [] }) { + return createStore(reducer, initialState) +} diff --git a/server/server.js b/server/server.js index 51a4946..c6d2160 100644 --- a/server/server.js +++ b/server/server.js @@ -1,8 +1,16 @@ var express = require('express'); var path = require('path'); +var config = require('../webpack.config.js'); +var webpack = require('webpack'); +var webpackDevMiddleware = require('webpack-dev-middleware'); +var webpackHotMiddleware = require('webpack-hot-middleware'); var app = express(); +var compiler = webpack(config); +app.use(webpackDevMiddleware(compiler, {noInfo: true, publicPath: config.output.publicPath})); +app.use(webpackHotMiddleware(compiler)); + app.use(express.static('./dist')); app.use('/', function (req, res) { diff --git a/webpack.config.js b/webpack.config.js index 8b13789..ae5bfd8 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1 +1,31 @@ +const webpack = require('webpack'); +module.exports = { + devtool:'inline-source-map', + entry: [ + 'webpack-hot-middleware/client', + './client/client.js' + ], + output: { + path: require('path').resolve('./dist'), + filename: 'bundle.js', + publicPath: '/', + hot: true + }, + plugins:[ + new webpack.HotModuleReplacementPlugin(), + new webpack.NoErrorsPlugin() + ], + module: { + loaders: [ + { + test: /\.js$/, + loader: 'babel-loader', + exclude: /node_modules/, + query: { + presets: ['react', 'es2015', 'react-hmre'] + } + } + ] + } +}