From 71e588962e86b3e38fd984be3103a1d8a086b210 Mon Sep 17 00:00:00 2001 From: Loaye Date: Mon, 28 Aug 2017 13:32:15 -0700 Subject: [PATCH 1/3] basic scaffold --- .gitignore | 1 + package.json | 46 +++++++++++++++++++++++++ src/index.html | 0 src/lib/store.js | 0 src/lib/util.js | 0 src/main.js | 0 webpack-config.js | 85 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 132 insertions(+) create mode 100644 .gitignore create mode 100644 package.json create mode 100644 src/index.html create mode 100644 src/lib/store.js create mode 100644 src/lib/util.js create mode 100644 src/main.js create mode 100644 webpack-config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..63739f2 --- /dev/null +++ b/package.json @@ -0,0 +1,46 @@ +{ + "name": "26-react-redux", + "version": "1.0.0", + "description": "![cf](https://i.imgur.com/7v5ASc8.png) 26: React & Redux ======", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Loaye/26-react-redux.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/Loaye/26-react-redux/issues" + }, + "homepage": "https://github.com/Loaye/26-react-redux#readme", + "dependencies": { + "babel-core": "^6.26.0", + "babel-loader": "^7.1.2", + "babel-plugin-transform-object-rest-spread": "^6.26.0", + "babel-preset-es2015": "^6.24.1", + "babel-preset-react": "^6.24.1", + "clean-webpack-plugin": "^0.1.16", + "css-loader": "^0.28.5", + "dotenv": "^4.0.0", + "extract-text-webpack-plugin": "^3.0.0", + "file-loader": "^0.11.2", + "html-webpack-plugin": "^2.30.1", + "node-sass": "^4.5.3", + "react": "^15.6.1", + "react-dom": "^15.6.1", + "react-redux": "^5.0.6", + "react-router-dom": "^4.2.2", + "react-test-renderer": "^15.6.1", + "redux": "^3.7.2", + "sass-loader": "^6.0.6", + "superagent": "^3.6.0", + "uglifyjs-webpack-plugin": "^0.4.6", + "url-loader": "^0.5.9", + "webpack": "^3.5.5", + "webpack-dev-server": "^2.7.1" + } +} diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/store.js b/src/lib/store.js new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/util.js b/src/lib/util.js new file mode 100644 index 0000000..e69de29 diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..e69de29 diff --git a/webpack-config.js b/webpack-config.js new file mode 100644 index 0000000..c9297fd --- /dev/null +++ b/webpack-config.js @@ -0,0 +1,85 @@ +'use strict'; + +require('dotenv').config({ path: `${__dirname}/.dev.env` }); +const production = process.env.NODE_ENV === 'production'; + +const {DefinePlugin, EnvironmentPlugin} = require('webpack'); +const HtmlPlugin = require('html-webpack-plugin'); +const CleanPlugin = require('clean-webpack-plugin'); +const UglifyPlugin = require('uglifyjs-webpack-plugin'); +const ExtractPlugin = require('extract-text-webpack-plugin'); + +let plugins = [ + new EnvironmentPlugin(['NODE_ENV']), + new ExtractPlugin('bundle-[hash].css'), + new HtmlPlugin({ template: `${__dirname}/src/index.html` }), + new DefinePlugin({ + __DEBUG__: JSON.stringify(!production) + }) +] + +if (production) { + plugins = plugins.concat([ new CleanPlugin(), new UglifyPlugin() ]); +} + +module.exports = { + plugins, + entry: `${__dirname}/src/main.js`, + devServer: { + historyApiFallback: true + }, + devtool: production ? undefined : 'eval', + output: { + path: `${__dirname}/build`, + filename: 'bundle-[hash].js', + publicPath: process.env.CDN_URL + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /node_modules/, + loader: 'babel-loader' + }, + { + test: /\.scss$/, + loader: ExtractPlugin.extract(['css-loader', 'sass-loader']) + }, + { + test: /\.(woff|woff2|ttf|eot|glyph|\.svg)$/, + use: [ + { + loader: 'url-loader', + options: { + limit: 10000, + name: 'font/[name].[ext]' + } + } + ] + }, + { + test: /\.(jpg|jpeg|gif|png|tiff|svg)$/, + exclude: /\.glyph.svg/, + use: [ + { + loader: 'url-loader', + options: { + limit: 6000, + name: 'image/[name].[ext]' + } + } + ] + }, + { + test: /\.(mp3|aac|aiff|wav|flac|m4a|mp4|ogg)$/, + exclude: /\.glyph.svg/, + use: [ + { + loader: 'file-loader', + options: { name: 'audio/[name].[ext]' } + } + ] + } + ] + } +} \ No newline at end of file From 4373a7207b42eba9e40368db4eee0d9bb42a2602 Mon Sep 17 00:00:00 2001 From: Loaye Date: Mon, 28 Aug 2017 14:00:10 -0700 Subject: [PATCH 2/3] starting to build it out --- .babelrc | 4 ++++ package.json | 5 +++-- src/action/category-action.js | 22 ++++++++++++++++++++++ src/index.html | 9 +++++++++ src/lib/store.js | 4 ++++ src/lib/util.js | 4 ++++ src/main.js | 5 +++++ src/reducer/category.js | 23 +++++++++++++++++++++++ 8 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 .babelrc create mode 100644 src/action/category-action.js create mode 100644 src/reducer/category.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..13285db --- /dev/null +++ b/.babelrc @@ -0,0 +1,4 @@ +{ + "preset": ["es2015", "react"], + "plugins": ["transform-object-rest-spread"], +} \ No newline at end of file diff --git a/package.json b/package.json index 63739f2..be4761b 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,10 @@ "name": "26-react-redux", "version": "1.0.0", "description": "![cf](https://i.imgur.com/7v5ASc8.png) 26: React & Redux ======", - "main": "index.js", + "main": "main.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "webpack", + "watch": "webpack-dev-server --inline --hot" }, "repository": { "type": "git", diff --git a/src/action/category-action.js b/src/action/category-action.js new file mode 100644 index 0000000..a44bccd --- /dev/null +++ b/src/action/category-action.js @@ -0,0 +1,22 @@ +import uuid from'uuid/v1'; + +export const categoryCreate = (category) => { + category.id = uuid(); + category.timestamp = new Date(); + return { + type: 'CATEGORY_CREATE', + payload: category + } +} + +export const categoryUpdate = (category) => ({ + type: 'CATEGORY_CREATE', + payload: category +}) + +export const categoryDelete = (category) => ({ + type: 'CATEGORY_DELETE', + payload: category +}) + +export const categoryReset = () => ({type: 'CATEGORY_RESET'}) \ No newline at end of file diff --git a/src/index.html b/src/index.html index e69de29..7a9232b 100644 --- a/src/index.html +++ b/src/index.html @@ -0,0 +1,9 @@ + + + + Budget Tracker + + +
+ + \ No newline at end of file diff --git a/src/lib/store.js b/src/lib/store.js index e69de29..75700f6 100644 --- a/src/lib/store.js +++ b/src/lib/store.js @@ -0,0 +1,4 @@ +import {createStore} from 'redux'; +import reducer from '../reducer/category.js'; + +export default () => createStore(reducer); \ No newline at end of file diff --git a/src/lib/util.js b/src/lib/util.js index e69de29..e27054d 100644 --- a/src/lib/util.js +++ b/src/lib/util.js @@ -0,0 +1,4 @@ +export const renderIf = (test, component) => test ? component : undefined; + +export const classToggler = (options) => + Object.keys(options).filter(key => !!options[key]).join(' '); \ No newline at end of file diff --git a/src/main.js b/src/main.js index e69de29..d209467 100644 --- a/src/main.js +++ b/src/main.js @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDom from 'react-dom'; +import App from './component/app'; + +ReactDom.render(, document.getElementById('root')); \ No newline at end of file diff --git a/src/reducer/category.js b/src/reducer/category.js new file mode 100644 index 0000000..ce0752b --- /dev/null +++ b/src/reducer/category.js @@ -0,0 +1,23 @@ +let initialState = []; + +export default (state=initialState, action) => { + let {type, payload} = action; + + switch(type){ + case 'CATEGORY_CREATE': + return [...state, payload] + + case 'CATEGORY_UPDATE': + return state.map(category => + category.id === payload.id ? payload : category) + + case 'CATEGORY_DELETE': + return state.filter(category => category.id !== payload.id) + + case 'CATEGORY_RESET': + return initialState + + default: + return state + } +} \ No newline at end of file From 6fe6c96fbc17f06bc092221b260d50babf50438e Mon Sep 17 00:00:00 2001 From: Loaye Date: Mon, 28 Aug 2017 14:10:48 -0700 Subject: [PATCH 3/3] trucking along --- src/component/app/index.js | 31 ++++++++++++ src/component/category-form/category-form.js | 39 +++++++++++++++ src/component/dashboard-container/index.js | 52 ++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 src/component/app/index.js create mode 100644 src/component/category-form/category-form.js create mode 100644 src/component/dashboard-container/index.js diff --git a/src/component/app/index.js b/src/component/app/index.js new file mode 100644 index 0000000..d07c2b9 --- /dev/null +++ b/src/component/app/index.js @@ -0,0 +1,31 @@ +import React from 'react'; +import {Provider} from 'react-redux'; +import {BroswerRouter} from 'react-router-dom'; +import createAppStore from '../../lib/store.js'; +import DashboardContainer from '../dashboard-container' + +const store = createAppStore(); + +class App extends React.Component{ + componentDidMount(){ + store.subscribe(() => { + console.log('--STATE--', store.getState()) + }); + + store.dispatch({type: null}); + } + + render(){ + return( +
+ + + + + +
+ ) + } +} + +export default App; \ No newline at end of file diff --git a/src/component/category-form/category-form.js b/src/component/category-form/category-form.js new file mode 100644 index 0000000..94cdbc8 --- /dev/null +++ b/src/component/category-form/category-form.js @@ -0,0 +1,39 @@ +import React from 'react'; + +class CategoryForm extends React.Component{ + constructor(props){ + super(props); + + this.state = { + title: props.category ? props.category.title : '' + } + + this.handleChange = this.handleChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + } + + handleChange(e){ + this.setState({title: e.target.value}); + } + + handleSubmit(e){ + e.preventDefault(); + this.props.onComplete(Object.assign({}, this.state)) + } + + render(){ + return( +
+ + + +
+ ) + } +} \ No newline at end of file diff --git a/src/component/dashboard-container/index.js b/src/component/dashboard-container/index.js new file mode 100644 index 0000000..45e392c --- /dev/null +++ b/src/component/dashboard-container/index.js @@ -0,0 +1,52 @@ +import React from 'react'; +import {connect} from 'react-redux'; + +import{ + categoryCreate, + categoryUpdate, + categoryDelete, +} from '../../action/category-actions.js'; + +import categoryForm from '../category-form'; + +class DashboardContainer extends React.Component{ + componentDidMount(){ + this.props.categoryCreate({title: 'some category'}); + this.props.categoryCreate({title: 'another category'}); + this.props.categoryCreate({title: 'cool category'}); + } + + render(){ + return( +
+

Dashboard

+ + + + {this.props.categories.map((item) => +
+

{item.title}

+
+ )} +
+ ) + } +} + +const mapStateToProps = (state) => { + return{ + categories: state + } +} + +const mapDispatchToProps = (dispatch, getState) => { + return{ + categoryCreate: (category) => dispatch(categoryCreate(category)), + categoryUpdate: (category) => dispatch(categoryUpdate(category)), + categoryDelete: (category) => dispatch(categoryDelete(category)), + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(DashboardContainer); \ No newline at end of file