[
  {
    "path": ".editorconfig",
    "content": "# http://editorconfig.org\nroot = true\n\n[*.{css,html,js,scss}]\nindent_style = space\nindent_size = 4\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n    \"parser\": \"babel-eslint\",\n    \"parserOptions\": {\n        \"ecmaVersion\": 6,\n        \"ecmaFeatures\": {\n          \"jsx\": true\n        },\n        \"sourceType\": \"module\"\n    },\n    \"env\": {\n        \"browser\": true,\n        \"es6\": true\n    },\n    \"globals\": {\n        \"module\": true,\n    },\n    \"plugins\": [\n      \"react\"\n    ],\n    \"extends\": [\n      \"plugin:react/recommended\"\n    ],\n    \"rules\": {\n        \"comma-dangle\": [2, \"never\"],\n        \"no-cond-assign\": [2, \"except-parens\"],\n        \"no-console\": 1,\n        \"no-constant-condition\": 2,\n        \"no-control-regex\": 2,\n        \"no-debugger\": 2,\n        \"no-dupe-args\": 2,\n        \"no-dupe-keys\": 2,\n        \"no-duplicate-case\": 2,\n        \"no-empty\": 1,\n        \"no-empty-character-class\": 2,\n        \"no-ex-assign\": 2,\n        \"no-extra-boolean-cast\": 2,\n        \"no-extra-parens\": [2, \"functions\"],\n        \"no-extra-semi\": 2,\n        \"no-func-assign\": 2,\n        \"no-invalid-regexp\": 2,\n        \"no-irregular-whitespace\": 2,\n        \"no-obj-calls\": 2,\n        \"no-regex-spaces\": 1,\n        \"no-sparse-arrays\": 2,\n        \"no-unexpected-multiline\": 2,\n        \"no-unreachable\": 2,\n        \"no-unsafe-negation\": 2,\n        \"use-isnan\": 2,\n        \"valid-typeof\": 2,\n\n        \"accessor-pairs\": [2, { \"getWithoutSet\":true }],\n        \"block-scoped-var\": 2,\n        \"curly\": [2, \"all\"],\n        \"dot-location\": [2, \"property\"],\n        \"eqeqeq\": [2, \"smart\"],\n        \"no-alert\": 2,\n        \"no-else-return\": 2,\n        \"no-eval\": 2,\n        \"no-extra-bind\": 2,\n        \"no-fallthrough\": 2,\n        \"no-floating-decimal\": 2,\n        \"no-global-assign\": 2,\n        \"no-implicit-globals\": 2,\n        \"no-implied-eval\": 2,\n        \"no-labels\": 2,\n        \"no-multi-spaces\": 2,\n        \"no-multi-str\": 2,\n        \"no-new-func\": 2,\n        \"no-octal-escape\": 2,\n        \"no-octal\": 2,\n        \"no-redeclare\": 2,\n        \"no-return-assign\": [2, \"except-parens\"],\n        \"no-script-url\": 2,\n        \"no-self-assign\": 2,\n        \"no-throw-literal\": 2,\n        \"no-unused-labels\": 2,\n        \"no-useless-call\": 2,\n        \"no-useless-concat\": 2,\n        \"no-void\": 2,\n        \"no-with\": 2,\n        \"radix\": 2,\n        \"wrap-iife\": [2, \"inside\"],\n        \"yoda\": [2, \"never\", {}],\n\n        \"strict\": [2,\"function\"],\n\n        \"no-delete-var\": 2,\n        \"no-shadow\": [2, { \"builtinGlobals\": false, \"hoist\": \"functions\", \"allow\": [] }],\n        \"no-shadow-restricted-names\": 2,\n        \"no-undef\": 2,\n        \"no-undef-init\": 2,\n        \"no-unused-vars\": 2,\n        \"no-use-before-define\": [2, \"nofunc\"],\n\n        \"array-bracket-spacing\": [2, \"never\"],\n        \"block-spacing\": [2, \"always\"],\n        \"brace-style\": [2, \"stroustrup\", { \"allowSingleLine\": false }],\n        \"comma-spacing\": [2, { \"before\": false, \"after\": true }],\n        \"comma-style\": [2, \"last\"],\n        \"computed-property-spacing\": [2, \"never\"],\n        \"eol-last\": 2,\n        \"func-call-spacing\": [2, \"never\"],\n        \"id-match\": [2, \"^([A-Z])|([A-Z][a-z])|([a-z]+(([A-Z][a-z]+)|(__([A-Z][a-z]+)))*)$\"],\n        \"indent\": [2, 4, { \"SwitchCase\": 1 }],\n        \"key-spacing\": [2, { \"beforeColon\": false, \"afterColon\": true }],\n        \"keyword-spacing\": 2,\n        \"linebreak-style\": [2, \"unix\"],\n        \"new-cap\": 2,\n        \"new-parens\": 2,\n        \"newline-after-var\": [2, \"always\"],\n        \"newline-before-return\": 2,\n        \"no-lonely-if\": 2,\n        \"no-mixed-spaces-and-tabs\": [2, \"smart-tabs\"],\n        \"no-multiple-empty-lines\": [2, { \"max\": 2 }],\n        \"no-nested-ternary\": 2,\n        \"no-tabs\": 1,\n        \"no-trailing-spaces\": [2, { \"skipBlankLines\": false }],\n        \"no-whitespace-before-property\": 2,\n        \"quote-props\": [2, \"as-needed\", { \"unnecessary\": false }],\n        \"quotes\": [1, \"single\"],\n        \"semi\": [2, \"always\"],\n        \"semi-spacing\": [2, { \"before\": false, \"after\": true }],\n        \"space-before-blocks\": [2, \"always\"],\n        \"space-before-function-paren\": [2, \"never\"],\n        \"space-infix-ops\": 2,\n        \"wrap-regex\": 2,\n\n        \"react/jsx-uses-vars\": 2\n    }\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "/coverage\n/dist\n/node_modules\nnpm-debug.log*\n"
  },
  {
    "path": "README.md",
    "content": "# A Dummy's Guide to Redux and Thunk in React\n\nThe demo app for my blog post. It is not an example of writing best-practice markup or React JavaScript, it's just the bare minimum to demonstrate how to use Redux and Redux Thunk.\n\n## Prerequisites\n\n[Node.js](http://nodejs.org/) >= v4 must be installed.\n\n## Installation\n\n- Running `npm install` in the app's root directory will install everything you need for development.\n\n## Development Server\n\n- `npm start` will run the app's development server at [http://localhost:3000](http://localhost:3000) with hot module reloading.\n\n## Building\n\n- `npm run build` creates a production build by default.\n\n   To create a development build, set the `NODE_ENV` environment variable to `development` while running this command.\n\n- `npm run clean` will delete built resources.\n"
  },
  {
    "path": "nwb.config.js",
    "content": "module.exports = {\n  type: 'react-app'\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"dummys-guide-to-redux-and-thunk-react\",\n  \"version\": \"1.0.0\",\n  \"description\": \"A Dummy's Guide to Redux and Thunk in React\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"nwb build-react-app\",\n    \"clean\": \"nwb clean-app\",\n    \"start\": \"nwb serve-react-app\"\n  },\n  \"dependencies\": {\n    \"react\": \"^15.3.2\",\n    \"react-dom\": \"^15.3.2\",\n    \"react-redux\": \"^4.4.5\",\n    \"redux\": \"^3.6.0\",\n    \"redux-thunk\": \"^2.1.0\"\n  },\n  \"devDependencies\": {\n    \"babel-eslint\": \"^7.1.0\",\n    \"eslint\": \"^3.10.0\",\n    \"eslint-plugin-react\": \"^6.6.0\",\n    \"nwb\": \"0.12.x\"\n  },\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"repository\": \"\"\n}\n"
  },
  {
    "path": "public/.gitkeep",
    "content": ""
  },
  {
    "path": "src/actions/items.js",
    "content": "export function itemsHasErrored(bool) {\n    return {\n        type: 'ITEMS_HAS_ERRORED',\n        hasErrored: bool\n    };\n}\n\nexport function itemsIsLoading(bool) {\n    return {\n        type: 'ITEMS_IS_LOADING',\n        isLoading: bool\n    };\n}\n\nexport function itemsFetchDataSuccess(items) {\n    return {\n        type: 'ITEMS_FETCH_DATA_SUCCESS',\n        items\n    };\n}\n\nexport function itemsFetchData(url) {\n    return (dispatch) => {\n        dispatch(itemsIsLoading(true));\n\n        fetch(url)\n            .then((response) => {\n                if (!response.ok) {\n                    throw Error(response.statusText);\n                }\n\n                dispatch(itemsIsLoading(false));\n\n                return response;\n            })\n            .then((response) => response.json())\n            .then((items) => dispatch(itemsFetchDataSuccess(items)))\n            .catch(() => dispatch(itemsHasErrored(true)));\n    };\n}\n"
  },
  {
    "path": "src/components/ItemList.js",
    "content": "import React, { Component, PropTypes } from 'react';\nimport { connect } from 'react-redux';\nimport { itemsFetchData } from '../actions/items';\n\nclass ItemList extends Component {\n    componentDidMount() {\n        this.props.fetchData('http://599167402df2f40011e4929a.mockapi.io/items');\n    }\n\n    render() {\n        if (this.props.hasErrored) {\n            return <p>Sorry! There was an error loading the items</p>;\n        }\n\n        if (this.props.isLoading) {\n            return <p>Loading…</p>;\n        }\n\n        return (\n            <ul>\n                {this.props.items.map((item) => (\n                    <li key={item.id}>\n                        {item.label}\n                    </li>\n                ))}\n            </ul>\n        );\n    }\n}\n\nItemList.propTypes = {\n    fetchData: PropTypes.func.isRequired,\n    items: PropTypes.array.isRequired,\n    hasErrored: PropTypes.bool.isRequired,\n    isLoading: PropTypes.bool.isRequired\n};\n\nconst mapStateToProps = (state) => {\n    return {\n        items: state.items,\n        hasErrored: state.itemsHasErrored,\n        isLoading: state.itemsIsLoading\n    };\n};\n\nconst mapDispatchToProps = (dispatch) => {\n    return {\n        fetchData: (url) => dispatch(itemsFetchData(url))\n    };\n};\n\nexport default connect(mapStateToProps, mapDispatchToProps)(ItemList);\n"
  },
  {
    "path": "src/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\" />\n    <title>A Dummy's Guide to Redux and Thunk in React</title>\n    <style>body { font-family: sans-serif; }</style>\n</head>\n\n<body>\n    <h1>A Dummy's Guide to Redux and Thunk in React</h1>\n    <div id=\"app\"></div>\n</body>\n</html>\n"
  },
  {
    "path": "src/index.js",
    "content": "import React from 'react';\nimport { render } from 'react-dom';\nimport { Provider } from 'react-redux';\nimport configureStore from './store/configureStore';\n\nimport ItemList from './components/ItemList';\n\nconst store = configureStore();\n\nrender(\n    <Provider store={store}>\n        <ItemList />\n    </Provider>,\n    document.getElementById('app')\n);\n"
  },
  {
    "path": "src/reducers/index.js",
    "content": "import { combineReducers } from 'redux';\nimport { items, itemsHasErrored, itemsIsLoading } from './items';\n\nexport default combineReducers({\n    items,\n    itemsHasErrored,\n    itemsIsLoading\n});\n"
  },
  {
    "path": "src/reducers/items.js",
    "content": "export function itemsHasErrored(state = false, action) {\n    switch (action.type) {\n        case 'ITEMS_HAS_ERRORED':\n            return action.hasErrored;\n\n        default:\n            return state;\n    }\n}\n\nexport function itemsIsLoading(state = false, action) {\n    switch (action.type) {\n        case 'ITEMS_IS_LOADING':\n            return action.isLoading;\n\n        default:\n            return state;\n    }\n}\n\nexport function items(state = [], action) {\n    switch (action.type) {\n        case 'ITEMS_FETCH_DATA_SUCCESS':\n            return action.items;\n\n        default:\n            return state;\n    }\n}\n"
  },
  {
    "path": "src/store/configureStore.js",
    "content": "import { createStore, applyMiddleware } from 'redux';\nimport thunk from 'redux-thunk';\nimport rootReducer from '../reducers';\n\nexport default function configureStore(initialState) {\n    return createStore(\n        rootReducer,\n        initialState,\n        applyMiddleware(thunk)\n    );\n}\n"
  }
]