[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    [\n      \"next/babel\",\n      {\n        \"preset-env\": {\n          \"modules\": \"commonjs\"\n        }\n      }\n    ]\n  ],\n  \"plugins\": [\n    [\n      \"styled-components\",\n      {\n        \"ssr\": true,\n        \"displayName\": true,\n        \"preprocess\": false\n      }\n    ],\n    \"transform-flow-strip-types\",\n    [\n      \"module-resolver\",\n      { \"root\": [\"./\"] }\n    ]\n  ]\n}\n"
  },
  {
    "path": ".eslintignore",
    "content": "/.next/**\n/node_modules/**\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n    \"parser\": \"babel-eslint\",\n    \"extends\": [\n        \"airbnb\",\n        \"prettier\",\n        \"plugin:flowtype/recommended\"\n    ],\n    \"plugins\": [\n        \"flowtype\"\n    ],\n    \"settings\": {\n        \"import/resolver\": {\n            \"babel-module\": {}\n        }\n    },\n    \"rules\": {\n        \"react/jsx-filename-extension\": [1, { \"extensions\": [\".js\", \".jsx\"] }],\n        \"no-unused-vars\": [\"error\", { \"args\": \"none\" }],\n        \"import/no-extraneous-dependencies\": [\"error\", { \"devDependencies\": true }],\n        \"jsx-a11y/anchor-is-valid\": [\"error\", {\n            \"components\": [\"Link\"],\n            \"specialLink\": [\"route\"],\n            \"aspects\": [\"invalidHref\", \"preferButton\"]\n        }],\n        \"import/extensions\": \"off\",\n        \"import/no-unresolved\": \"off\"\n    }\n}\n"
  },
  {
    "path": ".flowconfig",
    "content": "[ignore]\n.*/node_modules/config-chain/test/broken.json\n.*/node_modules/npmconf/test/fixtures/package.json\n[include]\n\n[libs]\n\n[lints]\n\n[options]\nmodule.system.node.resolve_dirname=node_modules\nmodule.system.node.resolve_dirname=.\nmodule.file_ext=.css\nmodule.file_ext=.scss\nmodule.file_ext=.js\nmodule.file_ext=.jsx\nmodule.file_ext=.json\n[strict]\n"
  },
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n\n# testing\n/coverage\n\n# production\n/build\n/dist\n/.next\n\n# misc\n.DS_Store\n.env\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nscss/**/*.css\n"
  },
  {
    "path": ".prettierignore",
    "content": ".next/**\nnode_modules/**\n"
  },
  {
    "path": ".storybook/config.js",
    "content": "import { configure } from \"@storybook/react\";\n\nfunction loadStories() {\n  require(\"../stories\");\n}\n\nconfigure(loadStories, module);\n"
  },
  {
    "path": ".storybook/webpack.config.js",
    "content": "// you can use this file to add your custom webpack plugins, loaders and anything you like.\n// This is just the basic way to add additional webpack configurations.\n// For more information refer the docs: https://storybook.js.org/configurations/custom-webpack-config\n\n// IMPORTANT\n// When you add this file, we won't add the default configurations which is similar\n// to \"React Create App\". This only has babel loader to load JavaScript.\n\nmodule.exports = {\n  plugins: [\n    // your custom plugins\n  ],\n  module: {\n    rules: [\n      // add your custom rules.\n    ]\n  }\n};\n"
  },
  {
    "path": "README.md",
    "content": "# NEXT Boilerplate\nLightweight Next boilerplate!\n## Background\nWe had tough times working with Next to make it our beloved framework. We opened issues (https://github.com/zeit/next.js/issues/3131), make pull requests and discuss a lot in the slack channel of NextJs. Unfortunately some of our must have features was not supported at that time. So we started creating a boilerplate that had all the features we wanted on top of Next.\n\n## Features\n* **redux** for handling application state\n* **redux-saga** for handling async actions and side-effects\n* **next-routes** for handling dynamic routes\n* **axios** for making HTTP requests\n* **dotenv** for using environment variables\n* **express** as the server\n* **redux-devtools** in development\n* **redux-logger** in development for managing actions and state changes they cause\n* **universal-cookie-express** as a middleware for easily writing cookies\n* **compression** for compressing static assets\n* **babel-plugin-module-resolver** for importing modules related to the root directory\n* **prettier** and **eslint** configured with **airbnb**'s styleguide for formating code\n* **husky** and **lint-staged** for autoformatting code before commit\n* **styled-components** allows you to write actual CSS code to style your components.\n\nthis boilerplate also includes **flow** and **storybook** that you can easily remove them if you don't like.\n\nFor more information please read the [docs](https://arefaslani.github.io/next-boilerplate)\n"
  },
  {
    "path": "components/NProgress/index.js",
    "content": "import React from \"react\";\nimport Head from \"next/head\";\nimport NProgress from \"nprogress\";\nimport { Router } from \"routes\";\n\nNProgress.configure({ showSpinner: false });\n\n\nRouter.onRouteChangeStart = url => {\n  NProgress.start();\n};\n\nRouter.onRouteChangeComplete = () => NProgress.done();\nRouter.onRouteChangeError = () => NProgress.done();\n\nexport default () => (\n  <div style={{ marginBottom: 20 }}>\n    <Head>\n      {/* Import CSS for nprogress */}\n      <link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/nprogress.css\" />\n    </Head>\n  </div>\n);\n"
  },
  {
    "path": "next.config.js",
    "content": "const webpack = require(\"webpack\");\nconst { parsed: localEnv } = require(\"dotenv\").config();\nconst withSourceMaps = require(\"@zeit/next-source-maps\");\nconst withImages = require(\"next-images\");\nconst withPlugins = require(\"next-compose-plugins\");\nconst withBundleAnalyzer = require(\"@zeit/next-bundle-analyzer\");\n\nconst plugins = [\n  withSourceMaps,\n  withImages,\n  [\n    withBundleAnalyzer,\n    {\n      analyzeServer: [\"server\", \"both\"].includes(process.env.BUNDLE_ANALYZE),\n      analyzeBrowser: [\"browser\", \"both\"].includes(process.env.BUNDLE_ANALYZE),\n      bundleAnalyzerConfig: {\n        server: {\n          analyzerMode: \"static\",\n          reportFilename: \"../server-analyze.html\"\n        },\n        browser: {\n          analyzerMode: \"static\",\n          reportFilename: \"client-analyze.html\"\n        }\n      }\n    }\n  ]\n];\n\nmodule.exports = withPlugins([...plugins], {\n  webpack: (config, { dev, isServer }) => {\n    const conf = config;\n    // Fixes npm packages that depend on `fs` module\n    conf.node = {\n      fs: \"empty\"\n    };\n\n    conf.plugins.push(new webpack.EnvironmentPlugin(localEnv));\n\n    return conf;\n  }\n});\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"next-boilerplate\",\n  \"version\": \"1.1.0\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"dev\": \"node server\",\n    \"build\": \"next build\",\n    \"start\": \"NODE_ENV=production node server\",\n    \"precommit\": \"lint-staged\",\n    \"storybook\": \"start-storybook -p 6006\",\n    \"build-storybook\": \"build-storybook\"\n  },\n  \"lint-staged\": {\n    \"*.js\": [\n      \"eslint --fix\",\n      \"prettier-eslint --write\",\n      \"git add\"\n    ]\n  },\n  \"dependencies\": {\n    \"@zeit/next-bundle-analyzer\": \"^0.1.1\",\n    \"@zeit/next-source-maps\": \"^0.0.2\",\n    \"axios\": \"^0.18.0\",\n    \"babel-core\": \"^7.0.0-bridge.0\",\n    \"babel-eslint\": \"^8.2.3\",\n    \"babel-plugin-module-resolver\": \"^3.1.1\",\n    \"babel-plugin-styled-components\": \"^1.5.1\",\n    \"compression\": \"^1.7.2\",\n    \"dotenv\": \"^6.0.0\",\n    \"express\": \"^4.16.3\",\n    \"next\": \"^6.0.3\",\n    \"next-compose-plugins\": \"^2.1.1\",\n    \"next-images\": \"^0.10.5\",\n    \"next-redux-saga\": \"^2.0.1\",\n    \"next-redux-wrapper\": \"^1.3.5\",\n    \"next-routes\": \"^1.4.2\",\n    \"nprogress\": \"^0.2.0\",\n    \"prop-types\": \"^15.6.1\",\n    \"react\": \"^16.4.1\",\n    \"react-dom\": \"^16.4.1\",\n    \"react-redux\": \"^5.0.7\",\n    \"redux\": \"^4.0.0\",\n    \"redux-devtools-extension\": \"^2.13.2\",\n    \"redux-logger\": \"^3.0.6\",\n    \"redux-saga\": \"^0.16.0\",\n    \"styled-components\": \"^3.3.2\",\n    \"universal-cookie-express\": \"^2.1.5\",\n    \"webpack\": \"^3.11.0\"\n  },\n  \"devDependencies\": {\n    \"@storybook/addon-actions\": \"^3.4.7\",\n    \"@storybook/addon-links\": \"^3.4.7\",\n    \"@storybook/react\": \"^3.4.7\",\n    \"autoprefixer\": \"^8.6.2\",\n    \"babel-plugin-transform-flow-strip-types\": \"^6.22.0\",\n    \"eslint\": \"^4.19.1\",\n    \"eslint-config-airbnb\": \"^16.1.0\",\n    \"eslint-config-prettier\": \"^2.9.0\",\n    \"eslint-import-resolver-babel-module\": \"^4.0.0\",\n    \"eslint-plugin-flowtype\": \"^2.49.3\",\n    \"eslint-plugin-import\": \"^2.12.0\",\n    \"eslint-plugin-jsx-a11y\": \"^6.0.3\",\n    \"eslint-plugin-react\": \"^7.9.1\",\n    \"flow-bin\": \"^0.74.0\",\n    \"husky\": \"^0.14.3\",\n    \"lint-staged\": \"^7.2.0\",\n    \"node-sass\": \"^4.9.0\",\n    \"postcss-loader\": \"^2.1.5\",\n    \"prettier\": \"^1.13.5\",\n    \"prettier-eslint-cli\": \"^4.7.1\",\n    \"styled-jsx-css-loader\": \"^0.3.0\",\n    \"webpack-bundle-analyzer\": \"^2.13.1\"\n  }\n}\n"
  },
  {
    "path": "pages/_app.js",
    "content": "import React from \"react\";\nimport App, { Container } from \"next/app\";\n\nexport default class MyApp extends App {\n  static async getInitialProps({ Component, ctx }) {\n    let pageProps = {};\n\n    if (Component.getInitialProps) {\n      pageProps = await Component.getInitialProps(ctx);\n    }\n\n    return { pageProps };\n  }\n\n  createUrl = router => {\n    // This is to make sure we don't references the router object at call time\n    const { pathname, asPath, query } = router;\n    return {\n      get query() {\n        return query;\n      },\n      get pathname() {\n        return pathname;\n      },\n      get asPath() {\n        return asPath;\n      },\n      back: () => {\n        router.back();\n      },\n      push: (url, as) => router.push(url, as),\n      pushTo: (href, as) => {\n        const pushRoute = as ? href : null;\n        const pushUrl = as || href;\n\n        return router.push(pushRoute, pushUrl);\n      },\n      replace: (url, as) => router.replace(url, as),\n      replaceTo: (href, as) => {\n        const replaceRoute = as ? href : null;\n        const replaceUrl = as || href;\n\n        return router.replace(replaceRoute, replaceUrl);\n      }\n    };\n  };\n\n  render() {\n    const { Component, pageProps, router } = this.props;\n    const url = this.createUrl(router);\n    return (\n      <Container>\n        <Component {...pageProps} url={url} />\n      </Container>\n    );\n  }\n}\n"
  },
  {
    "path": "pages/_document.js",
    "content": "import React from \"react\";\nimport Document, { Head, Main, NextScript } from \"next/document\";\nimport { ServerStyleSheet } from \"styled-components\";\n\nexport default class MyDocument extends Document {\n  static getInitialProps({ renderPage }) {\n    const sheet = new ServerStyleSheet();\n    const page = renderPage(App => props =>\n      sheet.collectStyles(<App {...props} />)\n    );\n    const styleTags = sheet.getStyleElement();\n    return { ...page, styleTags };\n  }\n\n  render() {\n    return (\n      <html lang=\"en\">\n        <Head>\n          <title>My page</title>\n          {this.props.styleTags}\n        </Head>\n        <body>\n          <Main />\n          <NextScript />\n        </body>\n      </html>\n    );\n  }\n}\n"
  },
  {
    "path": "pages/index.js",
    "content": "import React, { Component } from \"react\";\nimport { bindActionCreators } from \"redux\";\nimport withRedux from \"next-redux-wrapper\";\nimport withReduxSaga from \"next-redux-saga\";\nimport Head from \"next/head\";\nimport PropTypes from \"prop-types\";\nimport styled from \"styled-components\";\nimport Store from \"store\";\nimport { fetchPosts } from \"store/posts/actions\";\nimport { Link } from \"routes\";\nimport NProgress from \"components/NProgress\";\n\nconst H1 = styled.h1`\n  color: #458542;\n`;\n\nclass PostsIndex extends Component {\n  static getInitialProps({ store }) {\n    store.dispatch(fetchPosts());\n  }\n\n  render() {\n    const { posts, fetchPostsAction } = this.props;\n    return (\n      <div>\n        <Head>\n          <title>Posts Index</title>\n        </Head>\n        <NProgress />\n        <button\n          onClick={() => {\n            fetchPostsAction();\n          }}\n        >\n          Click Me\n        </button>\n        <H1>Posts</H1>\n        {posts.length > 0 &&\n          posts.map(post => (\n            <div key={post.id}>\n              <h2>\n                <Link prefetch route=\"post\" params={{ id: post.id }}>\n                  <a>{post.title}</a>\n                </Link>\n              </h2>\n              <p>{post.body}</p>\n            </div>\n          ))}\n      </div>\n    );\n  }\n}\n\nPostsIndex.propTypes = {\n  posts: PropTypes.arrayOf(PropTypes.object).isRequired,\n  fetchPostsAction: PropTypes.func.isRequired\n};\n\nconst mapStateToProps = state => ({\n  posts: state.posts.list\n});\n\nconst mapDispatchToProps = dispatch =>\n  bindActionCreators(\n    {\n      fetchPostsAction: fetchPosts\n    },\n    dispatch\n  );\n\nexport default withRedux(Store, mapStateToProps, mapDispatchToProps)(\n  withReduxSaga(PostsIndex)\n);\n"
  },
  {
    "path": "pages/post.js",
    "content": "import React, { Component } from \"react\";\nimport { bindActionCreators } from \"redux\";\nimport withRedux from \"next-redux-wrapper\";\nimport withReduxSaga from \"next-redux-saga\";\nimport Head from \"next/head\";\nimport PropTypes from \"prop-types\";\n\nimport { fetchPost } from \"store/posts/actions\";\nimport Store from \"store\";\nimport { Router } from \"routes\";\nimport NProgress from \"components/NProgress\";\n\nclass Post extends Component {\n  static getInitialProps({ query, store }) {\n    const { id } = query;\n    store.dispatch(fetchPost(id));\n\n    return { id };\n  }\n\n  render() {\n    const { post } = this.props;\n    return (\n      <div>\n        <Head>{post && <title>{post.title}</title>}</Head>\n        <NProgress />\n        <button onClick={() => Router.back()}>Back</button>\n        {post && (\n          <div key={post.id}>\n            <h2>{post.title}</h2>\n            <p>{post.body}</p>\n          </div>\n        )}\n      </div>\n    );\n  }\n}\n\nPost.propTypes = {\n  post: PropTypes.shape({}).isRequired\n};\n\nconst mapDispatchToProps = dispatch =>\n  bindActionCreators(\n    {\n      fetchPost\n    },\n    dispatch\n  );\n\nconst mapStateToProps = state => ({\n  post: state.posts.currentPost\n});\n\nexport default withRedux(Store, mapStateToProps, mapDispatchToProps)(\n  withReduxSaga(Post)\n);\n"
  },
  {
    "path": "pages/secret.js",
    "content": "import React, { Component } from \"react\";\nimport authenticate from \"services/auth/authenticate\";\n\nexport default class Secret extends Component {\n  static getInitialProps(ctx) {\n    const user = authenticate(ctx);\n    return { user };\n  }\n\n  render() {\n    return <div>Secret Page</div>;\n  }\n}\n"
  },
  {
    "path": "pages/signin.js",
    "content": "import React, { Component } from \"react\";\nimport signIn from \"services/auth/sign_in\";\n\nexport default class Signin extends Component {\n  static getInitialProps(ctx) {\n    signIn(ctx);\n    return {};\n  }\n\n  render() {\n    return <div />;\n  }\n}\n"
  },
  {
    "path": "postcss.config.js",
    "content": "module.exports = {\n  plugins: []\n};\n"
  },
  {
    "path": "routes.js",
    "content": "const routes = require(\"next-routes\")();\n\nmodule.exports = routes;\n\nroutes.add(\"about\").add(\"post\", \"/posts/:id\");\n"
  },
  {
    "path": "server/index.js",
    "content": "// server.js\nconst next = require(\"next\");\nconst cookiesMiddleware = require(\"universal-cookie-express\");\nconst compression = require(\"compression\");\n\nconst routes = require(\"../routes\");\n\nconst app = next({ dev: process.env.NODE_ENV !== \"production\" });\nconst handler = routes.getRequestHandler(app);\n\n// With express\nconst express = require(\"express\");\n\napp.prepare().then(() => {\n  express()\n    .use(cookiesMiddleware())\n    .use(compression())\n    .use(handler)\n    .listen(3000);\n});\n"
  },
  {
    "path": "services/api/index.js",
    "content": "import axios from \"axios\";\n\nconst facade = {};\n\nconst api = axios.create({ baseURL: \"https://jsonplaceholder.typicode.com\" });\n\nfacade.request = config => api.request(config);\n[\"get\", \"head\"].forEach(method => {\n  facade[method] = (url, config) => facade.request({ ...config, method, url });\n});\n[\"delete\", \"post\", \"put\", \"patch\"].forEach(method => {\n  facade[method] = (url, data, config) =>\n    facade.request({ ...config, method, url, data });\n});\n\nclass API {\n  static fetchAllPosts() {\n    return facade.get(\"/posts\");\n  }\n\n  static fetchPost(id) {\n    return facade.get(`/posts/${id}`);\n  }\n}\n\nexport default API;\n"
  },
  {
    "path": "services/auth/authenticate.js",
    "content": "export default ctx => {\n  const { req, res } = ctx;\n  const token = req.universalCookies.get(\"token\");\n  if (!token) {\n    return res.redirect(\"/\");\n  }\n  return { username: \"testUser\" };\n};\n"
  },
  {
    "path": "services/auth/sign_in.js",
    "content": "export default ctx => {\n  const { req, res } = ctx;\n  req.universalCookies.set(\"token\", \"test\");\n  res.redirect(\"/\");\n};\n"
  },
  {
    "path": "static/css/nprogress.css",
    "content": "/* Make clicks pass-through */\n#nprogress {\n  pointer-events: none;\n}\n\n#nprogress .bar {\n  background: #29d;\n\n  position: fixed;\n  z-index: 1031;\n  top: 0;\n  left: 0;\n\n  width: 100%;\n  height: 2px;\n}\n\n/* Fancy blur effect */\n#nprogress .peg {\n  display: block;\n  position: absolute;\n  right: 0px;\n  width: 100px;\n  height: 100%;\n  box-shadow: 0 0 10px #29d, 0 0 5px #29d;\n  opacity: 1.0;\n\n  -webkit-transform: rotate(3deg) translate(0px, -4px);\n      -ms-transform: rotate(3deg) translate(0px, -4px);\n          transform: rotate(3deg) translate(0px, -4px);\n}\n\n/* Remove these to get rid of the spinner */\n#nprogress .spinner {\n  display: block;\n  position: fixed;\n  z-index: 1031;\n  top: 15px;\n  right: 15px;\n}\n\n#nprogress .spinner-icon {\n  width: 18px;\n  height: 18px;\n  box-sizing: border-box;\n\n  border: solid 2px transparent;\n  border-top-color: #29d;\n  border-left-color: #29d;\n  border-radius: 50%;\n\n  -webkit-animation: nprogress-spinner 400ms linear infinite;\n          animation: nprogress-spinner 400ms linear infinite;\n}\n\n.nprogress-custom-parent {\n  overflow: hidden;\n  position: relative;\n}\n\n.nprogress-custom-parent #nprogress .spinner,\n.nprogress-custom-parent #nprogress .bar {\n  position: absolute;\n}\n\n@-webkit-keyframes nprogress-spinner {\n  0%   { -webkit-transform: rotate(0deg); }\n  100% { -webkit-transform: rotate(360deg); }\n}\n@keyframes nprogress-spinner {\n  0%   { transform: rotate(0deg); }\n  100% { transform: rotate(360deg); }\n}\n\n"
  },
  {
    "path": "store/index.js",
    "content": "import { createStore, applyMiddleware } from \"redux\";\nimport { createLogger } from \"redux-logger\";\nimport { composeWithDevTools } from \"redux-devtools-extension/developmentOnly\";\nimport createSagaMiddleware from \"redux-saga\";\nimport rootSaga from \"store/sagas\";\nimport reducer from \"store/reducer\";\n\n// Setup\nconst middleWare = [];\n\n// Saga Middleware\nconst sagaMiddleware = createSagaMiddleware();\nmiddleWare.push(sagaMiddleware);\n\n// Logger Middleware. This always has to be last\nconst loggerMiddleware = createLogger({\n  predicate: () => process.env.NODE_ENV === \"development\"\n});\nmiddleWare.push(loggerMiddleware);\n\nconst createStoreWithMiddleware = composeWithDevTools(\n  applyMiddleware(...middleWare)\n)(createStore);\n\nconst makeStore = (initialState, options) => {\n  const store = createStoreWithMiddleware(reducer, initialState);\n\n  store.runSagaTask = () => {\n    store.sagaTask = sagaMiddleware.run(rootSaga);\n  };\n  // run the rootSaga initially\n  store.runSagaTask();\n\n  return store;\n};\n\nexport default makeStore;\n"
  },
  {
    "path": "store/posts/actions.js",
    "content": "export const FETCH_POSTS = \"FETCH_POSTS\";\nexport const FETCH_POSTS_SUCCEEDED = \"FETCH_POSTS_SUCCEEDED\";\nexport const FETCH_POST = \"FETCH_POST\";\nexport const FETCH_POST_SUCCEEDED = \"FETCH_POST_SUCCEEDED\";\n\nexport function fetchPosts() {\n  return { type: FETCH_POSTS };\n}\n\nexport function fetchPost(id) {\n  return { type: FETCH_POST, payload: id };\n}\n"
  },
  {
    "path": "store/posts/reducer.js",
    "content": "import {\n  FETCH_POSTS_SUCCEEDED,\n  FETCH_POST_SUCCEEDED\n} from \"store/posts/actions\";\n\nexport default function(state = {}, action) {\n  switch (action.type) {\n    case FETCH_POSTS_SUCCEEDED:\n      return { ...state, list: action.payload };\n    case FETCH_POST_SUCCEEDED:\n      return { ...state, currentPost: action.payload };\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "store/posts/sagas.js",
    "content": "import { takeLatest, fork, call, put } from \"redux-saga/effects\";\n\nimport api from \"services/api\";\nimport {\n  FETCH_POSTS,\n  FETCH_POSTS_SUCCEEDED,\n  FETCH_POST,\n  FETCH_POST_SUCCEEDED\n} from \"store/posts/actions\";\n\nfunction* fetchPosts(action) {\n  const posts = yield call(api.fetchAllPosts);\n  yield put({ type: FETCH_POSTS_SUCCEEDED, payload: posts.data });\n}\n\nfunction* fetchPost({ payload }) {\n  const post = yield call(api.fetchPost, payload);\n  yield put({ type: FETCH_POST_SUCCEEDED, payload: post.data });\n}\n\nfunction* watchFetchPosts() {\n  yield takeLatest(FETCH_POSTS, fetchPosts);\n}\n\nfunction* watchFetchPost() {\n  yield takeLatest(FETCH_POST, fetchPost);\n}\n\nexport default function* postsSagas() {\n  yield fork(watchFetchPosts);\n  yield fork(watchFetchPost);\n}\n"
  },
  {
    "path": "store/reducer.js",
    "content": "import { combineReducers } from \"redux\";\n\nimport postsReducer from \"store/posts/reducer\";\n\nconst reducers = {\n  posts: postsReducer\n};\n\nexport default combineReducers(reducers);\n"
  },
  {
    "path": "store/sagas.js",
    "content": "import { all } from \"redux-saga/effects\";\n\nimport postSagas from \"store/posts/sagas\";\n\nexport default function* rootSaga(services = {}) {\n  yield all([postSagas()]);\n}\n"
  },
  {
    "path": "stories/index.js",
    "content": "import React from \"react\";\n\nimport { storiesOf } from \"@storybook/react\";\nimport { action } from \"@storybook/addon-actions\";\nimport { linkTo } from \"@storybook/addon-links\";\n\nimport { Button, Welcome } from \"@storybook/react/demo\";\n\nstoriesOf(\"Welcome\", module).add(\"to Storybook\", () => (\n  <Welcome showApp={linkTo(\"Button\")} />\n));\n\nstoriesOf(\"Button\", module)\n  .add(\"with text\", () => (\n    <Button onClick={action(\"clicked\")}>Hello Button</Button>\n  ))\n  .add(\"with some emoji\", () => (\n    <Button onClick={action(\"clicked\")}>\n      <span role=\"img\" aria-label=\"emoji text\">\n        😀 😎 👍 💯\n      </span>\n    </Button>\n  ));\n"
  }
]