├── .nvmrc ├── static ├── robot.txt └── favicon.ico ├── .dockerignore ├── next.config.js ├── preview.png ├── .flowconfig ├── mock ├── fakeAPI.json └── userInfosMock.json ├── flow-typed └── npm │ ├── flow-bin_v0.x.x.js │ ├── babel-preset-flow_vx.x.x.js │ ├── babel-preset-react_vx.x.x.js │ ├── babel-preset-es2015_vx.x.x.js │ ├── babel-preset-stage-2_vx.x.x.js │ ├── babel-plugin-transform-regenerator_vx.x.x.js │ ├── babel-plugin-transform-async-to-generator_vx.x.x.js │ ├── eslint-plugin-flowtype_vx.x.x.js │ ├── next_vx.x.x.js │ └── eslint-plugin-react_vx.x.x.js ├── .babelrc ├── redux ├── store │ ├── configureStore.js │ ├── configureStore.prod.js │ └── configureStore.dev.js ├── modules │ ├── reducers.js │ ├── persistStore.js │ ├── fakeModuleWithFetch.js │ └── userAuth.js └── middleware │ └── fetchMiddleware.js ├── .editorconfig ├── config └── appConfig.js ├── .prettierrc ├── typings ├── index.d.ts └── globals │ ├── axios │ ├── typings.json │ └── index.d.ts │ ├── redux │ ├── typings.json │ └── index.d.ts │ ├── moment │ ├── typings.json │ └── index.d.ts │ ├── localforage │ ├── typings.json │ └── index.d.ts │ └── redux-thunk │ ├── typings.json │ └── index.d.ts ├── .gitignore ├── CHANGELOG.md ├── ISSUE_TEMPLATE.md ├── typings.json ├── .vscode └── launch.json ├── services ├── fetchTools.js └── auth.js ├── LICENSE.md ├── pages ├── _error.js ├── page1.js ├── private1.js ├── index.js └── login.js ├── components ├── layout │ └── Layout.js ├── privateRoute │ └── PrivateRoute.js └── header │ └── Header.js ├── package.json ├── README.md └── .eslintrc /.nvmrc: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /static/robot.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .git 3 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | // next.config.js 2 | module.exports = { 3 | /* config options here */ 4 | }; 5 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacKentoch/react-redux-nextjs-bootstrap-starter/HEAD/preview.png -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacKentoch/react-redux-nextjs-bootstrap-starter/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [lints] 8 | 9 | [options] 10 | module.system=haste 11 | strip_root=true 12 | -------------------------------------------------------------------------------- /mock/fakeAPI.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "label": "item 1" 5 | }, 6 | { 7 | "id": 2, 8 | "label": "item 2" 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /flow-typed/npm/flow-bin_v0.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 6a5610678d4b01e13bbfbbc62bdaf583 2 | // flow-typed version: 3817bc6980/flow-bin_v0.x.x/flow_>=v0.25.x 3 | 4 | declare module "flow-bin" { 5 | declare module.exports: string; 6 | } 7 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "next/babel", 4 | "es2015", 5 | "react", 6 | "stage-2", 7 | "flow" 8 | ], 9 | "plugins": [ 10 | "transform-regenerator", 11 | "transform-async-to-generator" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /redux/store/configureStore.js: -------------------------------------------------------------------------------- 1 | /* eslint no-process-env:0 */ 2 | 3 | if (process.env.NODE_ENV === 'production') { 4 | module.exports = require('./configureStore.prod'); 5 | } else { 6 | module.exports = require('./configureStore.dev'); 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /config/appConfig.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const AppConfig = { 4 | // flag: set fetch mock or real fetch 5 | DEV_MODE: true, 6 | 7 | // API 8 | api: { 9 | fakeEndPoint: 'api/somewhere' 10 | } 11 | }; 12 | 13 | export default AppConfig; 14 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "all", 4 | "bracketSpacing": true, 5 | "jsxBracketSameLine": false, 6 | "singleQuote": true, 7 | "overrides": [], 8 | "printWidth": 80, 9 | "useTabs": false, 10 | "tabWidth": 2, 11 | "parser": "babylon" 12 | } 13 | -------------------------------------------------------------------------------- /typings/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store* 3 | Icon? 4 | ._* 5 | 6 | # Windows 7 | Thumbs.db 8 | ehthumbs.db 9 | Desktop.ini 10 | 11 | # Linux 12 | .directory 13 | *~ 14 | 15 | # npm 16 | node_modules 17 | *.log 18 | *.gz 19 | 20 | # intelliJ 21 | .idea/ 22 | 23 | # Coveralls 24 | coverage 25 | 26 | # next 27 | .next/ 28 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.3.0 (RELEASED) 2 | - add localforage 3 | 4 | ## 0.2.0 (RELEASED) 5 | - add Private component to handle private page 6 | 7 | ## 0.1.0 (RELEASED) 8 | - add redux store persistance (`redux-persist`) to maintain state accross all application. 9 | - add user authentication 10 | 11 | ## 0.0.1 (RELEASED) 12 | - first bricks of this starter 13 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Version 2 | 1.2.0 3 | 4 | ### Node JS 5 | v7.x | v8.X 6 | 7 | ### Browser 8 | Chrome 64.x | Safari 11.x 9 | 10 | ### OS version 11 | macOS | windows 10 | linux Ubuntu... 12 | 13 | ### Steps to reproduce 14 | 1. 15 | 2. 16 | 3. 17 | 18 | ### Expected behavior 19 | What should happen 20 | 21 | ### Actual behavior 22 | What is happening 23 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalDevDependencies": {}, 3 | "globalDependencies": { 4 | "axios": "registry:dt/axios#0.9.1+20161016142654", 5 | "localforage": "registry:dt/localforage#0.0.0+20161102134758", 6 | "moment": "registry:dt/moment#2.11.1+20161010105546", 7 | "redux": "registry:dt/redux#3.5.2+20160703092728", 8 | "redux-thunk": "registry:dt/redux-thunk#2.1.0+20160703120921" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /typings/globals/axios/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/e6215d4444ef44a38cd760817e955ce19b522032/axios/axios.d.ts", 5 | "raw": "registry:dt/axios#0.9.1+20161016142654", 6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/e6215d4444ef44a38cd760817e955ce19b522032/axios/axios.d.ts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /typings/globals/redux/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/15ddcf312782faf9e7fdfe724a3a29382a5825d7/redux/redux.d.ts", 5 | "raw": "registry:dt/redux#3.5.2+20160703092728", 6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/15ddcf312782faf9e7fdfe724a3a29382a5825d7/redux/redux.d.ts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /redux/modules/reducers.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { combineReducers } from 'redux'; 4 | import fakeModuleWithFetch from './fakeModuleWithFetch'; 5 | import userAuth from './userAuth'; 6 | import persistStore from './persistStore'; 7 | 8 | export const reducers = { 9 | fakeModuleWithFetch, 10 | userAuth, 11 | persistStore 12 | }; 13 | 14 | export default combineReducers({ 15 | ...reducers 16 | }); 17 | -------------------------------------------------------------------------------- /typings/globals/moment/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/637e7d6df755e785387d5269cb9287cdc51b8cb7/moment/moment.d.ts", 5 | "raw": "registry:dt/moment#2.11.1+20161010105546", 6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/637e7d6df755e785387d5269cb9287cdc51b8cb7/moment/moment.d.ts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /typings/globals/localforage/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/20aff2bdb6082f4f51eac9d4e6e64a2be786e346/localForage/localForage.d.ts", 5 | "raw": "registry:dt/localforage#0.0.0+20161102134758", 6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/20aff2bdb6082f4f51eac9d4e6e64a2be786e346/localForage/localForage.d.ts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /typings/globals/redux-thunk/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/d417f687ab0c81ed72bffbc5dace5f643369bb70/redux-thunk/redux-thunk.d.ts", 5 | "raw": "registry:dt/redux-thunk#2.1.0+20160703120921", 6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/d417f687ab0c81ed72bffbc5dace5f643369bb70/redux-thunk/redux-thunk.d.ts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /mock/userInfosMock.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJkZW1vIiwiaWF0IjoxNTAyMzA3MzU0LCJleHAiOjE3MjMyMzIxNTQsImF1ZCI6ImRlbW8tZGVtbyIsInN1YiI6ImRlbW8iLCJHaXZlbk5hbWUiOiJKb2huIiwiU3VybmFtZSI6IkRvZSIsIkVtYWlsIjoiam9obi5kb2VAZXhhbXBsZS5jb20iLCJSb2xlIjpbIlN1cGVyIGNvb2wgZGV2IiwibWFnaWMgbWFrZXIiXX0.6FjgLCypaqmRp4tDjg_idVKIzQw16e-z_rjA3R94IqQ", 3 | "user": { 4 | "id": 111, 5 | "login": "john.doe@fake.mail", 6 | "firstname": "John", 7 | "lastname": "Doe", 8 | "isAdmin": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Utilisez IntelliSense pour en savoir plus sur les attributs possibles. 3 | // Pointez pour afficher la description des attributs existants. 4 | // Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome localhost:3000", 11 | "url": "http://localhost:3000", 12 | "webRoot": "${workspaceRoot}" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /services/fetchTools.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | /** 4 | * getLocationOrigin returns dynamically base url 5 | * 6 | * @export 7 | * @returns {string} location origin 8 | */ 9 | export function getLocationOrigin(): string { 10 | if (typeof window === 'undefined') { 11 | return ''; 12 | } 13 | 14 | if (!window.location.origin) { 15 | window.location.origin = `${window.location.protocol}//${window.location.hostname}${window.location.port ? ':' + window.location.port : ''}`; 16 | } 17 | 18 | return window.location.origin; 19 | } 20 | -------------------------------------------------------------------------------- /typings/globals/redux-thunk/index.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by typings 2 | // Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/d417f687ab0c81ed72bffbc5dace5f643369bb70/redux-thunk/redux-thunk.d.ts 3 | declare namespace Redux { 4 | type ThunkAction = (dispatch: Dispatch, getState: () => S, extraArgument: E) => R; 5 | 6 | interface Dispatch { 7 | (asyncAction: ThunkAction): R; 8 | } 9 | } 10 | 11 | declare module "redux-thunk" { 12 | import { Middleware } from "redux"; 13 | 14 | const thunk: Middleware & { 15 | withExtraArgument(extraArgument: any): Middleware; 16 | }; 17 | 18 | export default thunk; 19 | } 20 | -------------------------------------------------------------------------------- /redux/modules/persistStore.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | // #region imports 4 | import { REHYDRATE } from 'redux-persist/constants'; 5 | // #endregion 6 | 7 | const initialState = {}; 8 | 9 | /** 10 | * redux-persist reducer rehydration logic 11 | * 12 | * NOTE: you need to write on your own!!! 13 | * 14 | * @export 15 | * @param {any} [state=initialState] state 16 | * @param {any} action action 17 | * @returns {any} state 18 | */ 19 | export default function (state = initialState, action) { 20 | switch (action.type) { 21 | case REHYDRATE: { 22 | const incoming = action.payload.myReducer; 23 | if (incoming) { 24 | return { 25 | ...state, 26 | ...incoming 27 | // specialKey: processSpecial(incoming.specialKey) 28 | }; 29 | } 30 | return state; 31 | } 32 | 33 | default: 34 | return state; 35 | } 36 | } 37 | // #endregion 38 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-preset-flow_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 2f58597102bce11ff3a4482d6607d60f 2 | // flow-typed version: <>/babel-preset-flow_v^6.23.0/flow_v0.57.2 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-preset-flow' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'babel-preset-flow' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-preset-flow/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-preset-flow/lib/index.js' { 31 | declare module.exports: $Exports<'babel-preset-flow/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-preset-react_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 1421db38882c7eb42bf18e8dbb388727 2 | // flow-typed version: <>/babel-preset-react_v^6.24.1/flow_v0.57.2 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-preset-react' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'babel-preset-react' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-preset-react/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-preset-react/lib/index.js' { 31 | declare module.exports: $Exports<'babel-preset-react/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-preset-es2015_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 8722dd2bea14809f8f45293872c8f6cf 2 | // flow-typed version: <>/babel-preset-es2015_v^6.24.1/flow_v0.57.2 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-preset-es2015' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'babel-preset-es2015' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-preset-es2015/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-preset-es2015/lib/index.js' { 31 | declare module.exports: $Exports<'babel-preset-es2015/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-preset-stage-2_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: a801d20d6e50d29432634751cde9135d 2 | // flow-typed version: <>/babel-preset-stage-2_v^6.24.1/flow_v0.57.2 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-preset-stage-2' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'babel-preset-stage-2' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-preset-stage-2/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-preset-stage-2/lib/index.js' { 31 | declare module.exports: $Exports<'babel-preset-stage-2/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # LICENSE 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2019 Erwan DATIN 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-plugin-transform-regenerator_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 104fda36b08cda34bbac121973e64b1d 2 | // flow-typed version: <>/babel-plugin-transform-regenerator_v^6.26.0/flow_v0.57.2 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-plugin-transform-regenerator' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'babel-plugin-transform-regenerator' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-plugin-transform-regenerator/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-plugin-transform-regenerator/lib/index.js' { 31 | declare module.exports: $Exports<'babel-plugin-transform-regenerator/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /flow-typed/npm/babel-plugin-transform-async-to-generator_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: b566883b98bb79a75cbf392f24988c4f 2 | // flow-typed version: <>/babel-plugin-transform-async-to-generator_v^6.24.1/flow_v0.57.2 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-plugin-transform-async-to-generator' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'babel-plugin-transform-async-to-generator' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-plugin-transform-async-to-generator/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-plugin-transform-async-to-generator/lib/index.js' { 31 | declare module.exports: $Exports<'babel-plugin-transform-async-to-generator/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /redux/store/configureStore.prod.js: -------------------------------------------------------------------------------- 1 | // @flow weak 2 | 3 | import { 4 | createStore, 5 | compose, 6 | applyMiddleware 7 | } from 'redux'; 8 | import thunkMiddleware from 'redux-thunk'; 9 | import { 10 | persistStore, 11 | autoRehydrate 12 | } from 'redux-persist'; 13 | import localForage from 'localforage'; 14 | import reducer from '../modules/reducers'; 15 | import fetchMiddleware from '../middleware/fetchMiddleware'; 16 | 17 | // #region createStore : enhancer 18 | const enhancer = compose( 19 | applyMiddleware( 20 | thunkMiddleware, 21 | fetchMiddleware 22 | ), 23 | autoRehydrate() 24 | ); 25 | // #endregion 26 | 27 | // #region store initialization 28 | export default function configureStore(initialState) { 29 | const store = createStore(reducer, initialState, enhancer); 30 | 31 | // begin periodically persisting the store 32 | persistStore(store, {storage: localForage}); 33 | 34 | // OPTIONAL: you can blacklist reducers to avoid them to persist, so call 35 | // persistStore( 36 | // store, 37 | // {blacklist: ['someTransientReducer']}, 38 | // () => { 39 | // console.log('rehydration complete') 40 | // } 41 | // ); 42 | 43 | return store; 44 | } 45 | // #endregion 46 | -------------------------------------------------------------------------------- /pages/_error.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | // #region imports 4 | import React, { 5 | PureComponent 6 | } from 'react'; 7 | import Jumbotron from 'react-bootstrap/lib/Jumbotron'; 8 | // #endregion 9 | 10 | // #region flow types 11 | type Props = { 12 | errorCode?: number 13 | }; 14 | 15 | type State = any; 16 | 17 | type NextInitialProps = { 18 | res?: { 19 | statusCode: number 20 | }, 21 | xhr: { 22 | status: number 23 | } 24 | } 25 | // #endregion 26 | 27 | class Error extends PureComponent { 28 | // #region props initialization 29 | static getInitialProps( 30 | {res, xhr}: NextInitialProps 31 | ) { 32 | const errorCode = res ? res.statusCode : xhr.status; 33 | return { errorCode }; 34 | } 35 | // #endregion 36 | 37 | // #region component default props 38 | static defaultProps = { 39 | errorCode: null 40 | }; 41 | // #endregion 42 | 43 | // #region component lifecycle methods 44 | render() { 45 | const { 46 | errorCode 47 | } = this.props; 48 | 49 | return ( 50 | 51 |

52 | Sorry but this time... It threw an error... 53 |

54 | 55 | Error code: { errorCode ? errorCode : '--' } 56 | 57 |
58 | ); 59 | } 60 | // #endregion 61 | } 62 | 63 | export default Error; 64 | -------------------------------------------------------------------------------- /components/layout/Layout.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | // #region imports 4 | import { PureComponent } from 'react'; 5 | import Head from 'next/head'; 6 | // #endregion 7 | 8 | // #region flow types 9 | type Props = { 10 | children: ReactNode 11 | } 12 | 13 | type State = any; 14 | // #endregion 15 | 16 | class Layout extends PureComponent { 17 | // #region component lifecycle methods 18 | render() { 19 | const { children } = this.props; 20 | 21 | return ( 22 |
23 | 24 | 28 | 31 | 36 | 40 | 44 | 45 | 58 | {children} 59 |
60 | ); 61 | } 62 | // #endregion 63 | } 64 | 65 | export default Layout; 66 | -------------------------------------------------------------------------------- /redux/store/configureStore.dev.js: -------------------------------------------------------------------------------- 1 | // @flow weak 2 | 3 | import { 4 | createStore, 5 | applyMiddleware 6 | } from 'redux'; 7 | import { createLogger } from 'redux-logger'; 8 | import thunkMiddleware from 'redux-thunk'; 9 | import { 10 | persistStore, 11 | autoRehydrate 12 | } from 'redux-persist'; 13 | import localForage from 'localforage'; 14 | import { composeWithDevTools } from 'redux-devtools-extension'; 15 | import reducer from '../modules/reducers'; 16 | import fetchMiddleware from '../middleware/fetchMiddleware'; 17 | 18 | // #region configure logger middleware 19 | const loggerMiddleware = createLogger({ 20 | level: 'info', 21 | collapsed: true 22 | }); 23 | // #endregion 24 | 25 | // #region createStore : enhancer 26 | const enhancer = composeWithDevTools( 27 | applyMiddleware( 28 | thunkMiddleware, 29 | fetchMiddleware, 30 | loggerMiddleware, 31 | ), 32 | autoRehydrate() 33 | ); 34 | // #endregion 35 | 36 | // #region store initialization 37 | export default function configureStore(initialState) { 38 | const store = createStore(reducer, initialState, enhancer); 39 | 40 | // begin periodically persisting the store 41 | persistStore(store, {storage: localForage}); 42 | 43 | // OPTIONAL: you can blacklist reducers to avoid them to persist, so call 44 | // persistStore( 45 | // store, 46 | // {blacklist: ['someTransientReducer']}, 47 | // () => { 48 | // console.log('rehydration complete') 49 | // } 50 | // ); 51 | 52 | return store; 53 | } 54 | // #endregion 55 | -------------------------------------------------------------------------------- /components/privateRoute/PrivateRoute.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | // #region imports 4 | import { PureComponent } from 'react'; 5 | import Router from 'next/router'; 6 | import auth from '../../services/auth'; 7 | // #endregion 8 | 9 | // #region flow types 10 | type Props = { 11 | fromPath: string, 12 | children: ReactNode 13 | } 14 | 15 | type State = any; 16 | // #endregion 17 | 18 | class Private extends PureComponent { 19 | // #region 20 | static defaultProps = { 21 | fromPath: '/' 22 | }; 23 | 24 | // #region component lifecycle methods 25 | componentDidMount() { 26 | const { 27 | fromPath 28 | } = this.props; 29 | 30 | const userIsAuthenticated = this.isAuthenticated(); 31 | const userTokenExpired =this.isExpired(); 32 | 33 | const RoutePayload = { 34 | pathname: '/login', 35 | query: { from: fromPath } 36 | }; 37 | 38 | if (!userIsAuthenticated) { 39 | return Router.replace(RoutePayload); 40 | } 41 | 42 | if (userTokenExpired) { 43 | return Router.replace(RoutePayload); 44 | } 45 | 46 | return true; 47 | } 48 | 49 | render() { 50 | const { children } = this.props; 51 | 52 | return ( 53 |
54 | {children} 55 |
56 | ); 57 | } 58 | // #endregion 59 | 60 | // #region authentication check methods 61 | isAuthenticated(): boolean { 62 | const checkUserHasId = user => user && user.id; 63 | const user = auth.getUserInfo() ? auth.getUserInfo() : null; 64 | const isAuthenticated = auth.getToken() && checkUserHasId(user) ? true : false; 65 | return isAuthenticated; 66 | } 67 | 68 | isExpired(): boolean { 69 | /* eslint-disable no-console */ 70 | // comment me: 71 | console.log('token expires: ', auth.getTokenExpirationDate(auth.getToken())); 72 | /* eslint-enable no-console */ 73 | return auth.isExpiredToken(auth.getToken()); 74 | } 75 | // #endregion 76 | } 77 | 78 | export default Private; 79 | -------------------------------------------------------------------------------- /pages/page1.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | // #region imports 4 | import { PureComponent } from 'react'; 5 | import { bindActionCreators } from 'redux'; 6 | import withRedux from 'next-redux-wrapper'; 7 | import configureStore from '../redux/store/configureStore'; 8 | import * as userAuthActions from '../redux/modules/userAuth'; 9 | import Layout from '../components/layout/Layout'; 10 | import Header from '../components/header/Header'; 11 | import Button from 'react-bootstrap/lib/Button'; 12 | import Router from 'next/router'; 13 | // #endregion 14 | 15 | // #region flow types 16 | type Props = { 17 | // userAuth: 18 | isAuthenticated: boolean, 19 | disconnectUser: () => any, 20 | ...any 21 | }; 22 | 23 | type State = any; 24 | // #endregion 25 | 26 | class Page1 extends PureComponent { 27 | // #region component lifecycle methods 28 | render() { 29 | return ( 30 | 31 |
32 |

33 | Page1 here 34 |

35 | 41 | 42 | ); 43 | } 44 | // #endregion 45 | 46 | // html elements events 47 | goBackHome = ( 48 | event: SyntheticEvent<> 49 | ): void => { 50 | if (event) { 51 | event.preventDefault(); 52 | } 53 | 54 | Router.push('/'); 55 | } 56 | // #endregion 57 | } 58 | 59 | 60 | // #region redux state and dispatch map to props 61 | const mapStateToProps = ( 62 | state: any 63 | ) => ({ 64 | // userAuth: 65 | isAuthenticated: state.userAuth.isAuthenticated 66 | }); 67 | 68 | const mapDispatchToProps = ( 69 | dispatch: (...any) => any 70 | ) => { 71 | return { 72 | ...bindActionCreators( 73 | { 74 | // userAuth: 75 | ...userAuthActions 76 | }, 77 | dispatch) 78 | }; 79 | }; 80 | // #endregion 81 | 82 | export default withRedux( 83 | configureStore, 84 | mapStateToProps, 85 | mapDispatchToProps 86 | )(Page1); 87 | -------------------------------------------------------------------------------- /pages/private1.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | // #region imports 4 | import { PureComponent } from 'react'; 5 | import { bindActionCreators } from 'redux'; 6 | import withRedux from 'next-redux-wrapper'; 7 | import configureStore from '../redux/store/configureStore'; 8 | import * as userAuthActions from '../redux/modules/userAuth'; 9 | import Layout from '../components/layout/Layout'; 10 | import Header from '../components/header/Header'; 11 | import Button from 'react-bootstrap/lib/Button'; 12 | import Router from 'next/router'; 13 | import Private from '../components/privateRoute/PrivateRoute'; 14 | // #endregion 15 | 16 | // #region flow types 17 | type Props = { 18 | // from next/Router: 19 | url: { 20 | asPath: string, 21 | pathname: string, 22 | ...any 23 | }, 24 | 25 | // userAuth: 26 | isAuthenticated: boolean, 27 | disconnectUser: () => any, 28 | ...any 29 | }; 30 | 31 | type State = any; 32 | // #endregion 33 | 34 | class Private1 extends PureComponent { 35 | // #region component lifecycle methods 36 | render() { 37 | const { 38 | url: { 39 | pathname 40 | } 41 | } = this.props; 42 | 43 | return ( 44 | 47 | 48 |
49 |

50 | Private1 here 51 |

52 | 58 | 59 | 60 | ); 61 | } 62 | // #endregion 63 | 64 | // #region html elements events 65 | goBackHome = ( 66 | event: SyntheticEvent<> 67 | ): void => { 68 | if (event) { 69 | event.preventDefault(); 70 | } 71 | 72 | Router.push('/'); 73 | } 74 | // #endregion 75 | } 76 | 77 | 78 | // #region redux state and dispatch map to props 79 | const mapStateToProps = ( 80 | state: any 81 | ) => ({ 82 | // userAuth: 83 | isAuthenticated: state.userAuth.isAuthenticated 84 | }); 85 | 86 | const mapDispatchToProps = ( 87 | dispatch: (...any) => any 88 | ) => { 89 | return { 90 | ...bindActionCreators( 91 | { 92 | // userAuth: 93 | ...userAuthActions 94 | }, 95 | dispatch) 96 | }; 97 | }; 98 | // #endregion 99 | 100 | export default withRedux( 101 | configureStore, 102 | mapStateToProps, 103 | mapDispatchToProps 104 | )(Private1); 105 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-redux-nextjs-bootstrap-starter", 3 | "version": "0.3.0", 4 | "description": "react + redux + next js + bootstrap starter", 5 | "author": "Erwan DATIN (http://www.erwan-datin.com)", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/MacKentoch/react-redux-nextjs-bootstrap-starter.git" 10 | }, 11 | "bugs": { 12 | "url": "https://github.com/MacKentoch/react-redux-nextjs-bootstrap-starter/issues" 13 | }, 14 | "keywords": [ 15 | "react", 16 | "next", 17 | "zeit", 18 | "next.js", 19 | "next js", 20 | "now", 21 | "redux", 22 | "react-redux", 23 | "ES6", 24 | "ES7", 25 | "ES8", 26 | "ES2015", 27 | "ES2016", 28 | "ES2017", 29 | "bootstrap", 30 | "starter", 31 | "persist", 32 | "redux-persist", 33 | "hot-reload" 34 | ], 35 | "engines": { 36 | "node": ">=8.6.0", 37 | "npm": ">=5.4.2" 38 | }, 39 | "main": "index.js", 40 | "scripts": { 41 | "dev": "next", 42 | "build": "next build", 43 | "start": "next start", 44 | "deploy": "now --public" 45 | }, 46 | "dependencies": { 47 | "axios": "^0.16.2", 48 | "jwt-decode": "^2.2.0", 49 | "localforage": "^1.5.2", 50 | "moment": "^2.19.1", 51 | "next": "^4.0.3", 52 | "next-redux-wrapper": "^1.3.4", 53 | "normalize.css": "^7.0.0", 54 | "react": "^16.0.0", 55 | "react-bootstrap": "^0.31.3", 56 | "react-dom": "^16.0.0", 57 | "react-redux": "^5.0.6", 58 | "redux": "^3.7.2", 59 | "redux-persist": "^4.10.1", 60 | "redux-thunk": "^2.2.0" 61 | }, 62 | "devDependencies": { 63 | "@types/axios": "^0.14.0", 64 | "@types/jwt-decode": "^2.2.1", 65 | "@types/moment": "^2.13.0", 66 | "@types/next": "^2.4.3", 67 | "@types/next-redux-wrapper": "^1.3.3", 68 | "@types/react": "^16.0.10", 69 | "@types/react-bootstrap": "^0.31.4", 70 | "@types/react-dom": "^16.0.1", 71 | "@types/react-redux": "^5.0.10", 72 | "@types/redux": "^3.6.0", 73 | "@types/redux-persist": "^4.3.1", 74 | "@types/redux-thunk": "^2.1.0", 75 | "babel-eslint": "^8.0.1", 76 | "babel-plugin-transform-async-to-generator": "^6.24.1", 77 | "babel-plugin-transform-regenerator": "^6.26.0", 78 | "babel-preset-es2015": "^6.24.1", 79 | "babel-preset-flow": "^6.23.0", 80 | "babel-preset-react": "^6.24.1", 81 | "babel-preset-stage-2": "^6.24.1", 82 | "eslint": "^4.8.0", 83 | "eslint-plugin-flowtype": "^2.39.1", 84 | "eslint-plugin-react": "^7.4.0", 85 | "flow-bin": "^0.57.2", 86 | "redux-devtools-extension": "^2.13.2", 87 | "redux-logger": "^3.0.6" 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /redux/modules/fakeModuleWithFetch.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | // #region imports 4 | import moment from 'moment'; 5 | import fakeData from '../../mock/fakeAPI.json'; 6 | import AppConfig from '../../config/appConfig'; 7 | import { getLocationOrigin } from '../../services/fetchTools'; 8 | // #endregion 9 | 10 | // #region CONSTANTS 11 | const REQUEST_FAKE_FETCH = 'REQUEST_FAKE_FETCH'; 12 | const RECEIVED_FAKE_FETCH = 'RECEIVED_FAKE_FETCH'; 13 | const ERROR_FAKE_FETCH = 'ERROR_FAKE_FETCH'; 14 | // #endregion 15 | 16 | // #region REDUCER 17 | const initialState = { 18 | isFetching: false, 19 | actionTime: '', 20 | data: [], 21 | error: {} 22 | }; 23 | 24 | export default function (state = initialState, action) { 25 | const currentTime = moment().format(); 26 | 27 | switch (action.type) { 28 | case REQUEST_FAKE_FETCH: 29 | return { 30 | ...state, 31 | actionTime: currentTime, 32 | isFetching: true 33 | }; 34 | 35 | case RECEIVED_FAKE_FETCH: 36 | return { 37 | ...state, 38 | actionTime: currentTime, 39 | isFetching: false, 40 | data: [...action.payload] 41 | }; 42 | 43 | case ERROR_FAKE_FETCH: 44 | return { 45 | ...state, 46 | actionTime: currentTime, 47 | isFetching: false, 48 | error: action.error ? { ...action.error } : {} 49 | }; 50 | 51 | default: 52 | return state; 53 | } 54 | } 55 | // #endregion 56 | 57 | // #region ACTIONS CREATORS 58 | function fakeFetch() { 59 | return dispatch => { 60 | const shouldFetchMock = AppConfig.DEV_MODE; 61 | const fetchType = shouldFetchMock ? 'FETCH_MOCK': 'FETCH'; 62 | const mockResult = fakeData; 63 | 64 | const url = `${getLocationOrigin()}/${AppConfig.api.fakeEndPoint}`; 65 | const method = 'get'; 66 | const options = {}; 67 | 68 | // fetch middleware 69 | // -> you handles pure front or with back-end asyncs just by disaptching a single object 70 | // -> just change config: AppConfig.DEV_MODE 71 | return Promise.resolve( 72 | dispatch({ 73 | // type name is not important here since fetchMiddleware will intercept this action: 74 | type: 'FETCH_MIDDLEWARE', 75 | // here are fetch middleware props: 76 | fetch: { 77 | type: fetchType, 78 | actionTypes: { 79 | request: REQUEST_FAKE_FETCH, 80 | success: RECEIVED_FAKE_FETCH, 81 | fail: ERROR_FAKE_FETCH 82 | }, 83 | // props only used when type = FETCH_MOCK: 84 | mockResult, 85 | // props only used when type = FETCH: 86 | url, 87 | method, 88 | options 89 | } 90 | }) 91 | ); 92 | }; 93 | } 94 | 95 | export function fakeFetchIfNeeded() { 96 | return (dispatch, getState) => { 97 | if (shouldFakeFetch(getState())) { 98 | return dispatch(fakeFetch()); 99 | } 100 | return Promise.resolve(); 101 | }; 102 | } 103 | 104 | function shouldFakeFetch(state) { 105 | const isFetching = state.fakeModuleWithFetch.isFetching; 106 | // prevents fetching twice while already fetching: 107 | if (isFetching) { 108 | return false; 109 | } 110 | return true; 111 | } 112 | // #endregion 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/MacKentoch/react-redux-nextjs-bootstrap-starter) 2 | 3 | # Next JS + React + Redux + Redux persist + redux-devtools-extension + Bootstrap starter 4 | 5 | > A NextJS starter with redux and bootstrap 6 | 7 | 8 | 9 | ![preview](./preview.png) 10 | 11 | 12 | 13 | [See it in action deployed with `now`](https://react-redux-nextjs-bootstrap-starter-xfdpqhzseq.now.sh/) 14 | 15 | ## Detailed Content 16 | 17 | **Front:** 18 | - Next js (4.x+ [github :link:](https://github.com/zeit/next.js)) 19 | - React JS (16.x+ - [github :link:](https://github.com/facebook/react)) 20 | - redux (*as your application grows managing state will be a serious concern, save pain with Redux*) 21 | - redux-persist (*simplifies your NextJS state share between pages* [github :link:](https://github.com/rt2zz/redux-persist)) 22 | - localforage (*for better performances than localStorage*) 23 | - react-redux (*Redux is not specific to ReactJS, you could easily use it with Angular2 for instance*) 24 | - redux-thunk (*simple and does the job*) 25 | - next-redux-wrapper 26 | - redux-devtools-extension ([github :link:](https://github.com/zalmoxisus/redux-devtools-extension#redux-devtools-extension)) 27 | - react-bootstrap ([github :link:](https://github.com/react-bootstrap/react-bootstrap)) 28 | - axios ([github :link:](https://github.com/mzabriskie/axios) *Why: simple, complete, isomorphic ...*) 29 | 30 | **Tool chain:** 31 | - Next js (4.x+ [github :link:](https://github.com/zeit/next.js)) 32 | - Flow JS types 33 | 34 | ## Usage 35 | 36 | IMPORTANT: `Next JS` when `redux` connected 37 | 38 | - **you are forced to connect each page** (*even if you don't need redux in that page*) with `withRedux` from `next-redux-wrapper` (*[see page1 as an example](https://github.com/MacKentoch/react-redux-nextjs-bootstrap-starter/blob/master/pages/page1.js)*). 39 | - **each sub component you may want to connect** should be connected by usual `connect` from `redux` (*[see Header component as an example](https://github.com/MacKentoch/react-redux-nextjs-bootstrap-starter/blob/master/components/header/Header.js)*) 40 | 41 | 42 | ### Install 43 | 44 | ```bash 45 | npm install 46 | ``` 47 | 48 | ### Scripts 49 | 50 |
51 | run dev with hot reload 52 | 53 | Clone this repository, then install dependencies: 54 | 55 | ```bash 56 | npm run start 57 | ``` 58 | 59 |
60 | 61 |
62 | build dev bundle 63 | 64 | ```bash 65 | npm run build 66 | ``` 67 | 68 |
69 | 70 |
71 | start dev (no hot reload) 72 | 73 | 74 | *NOTE: ensure you built first before starting* 75 | 76 | ```bash 77 | npm run start 78 | ``` 79 | 80 |
81 | 82 | ## LICENSE 83 | 84 | The MIT License (MIT) 85 | 86 | Copyright (c) 2017 Erwan DATIN 87 | 88 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 89 | 90 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 91 | 92 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 93 | -------------------------------------------------------------------------------- /typings/globals/localforage/index.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by typings 2 | // Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/20aff2bdb6082f4f51eac9d4e6e64a2be786e346/localForage/localForage.d.ts 3 | interface LocalForageOptions { 4 | driver?: string | LocalForageDriver | LocalForageDriver[]; 5 | 6 | name?: string; 7 | 8 | size?: number; 9 | 10 | storeName?: string; 11 | 12 | version?: number; 13 | 14 | description?: string; 15 | } 16 | 17 | interface LocalForageDbMethods { 18 | getItem(key: string): Promise; 19 | getItem(key: string, callback: (err: any, value: T) => void): void; 20 | 21 | setItem(key: string, value: T): Promise; 22 | setItem(key: string, value: T, callback: (err: any, value: T) => void): void; 23 | 24 | removeItem(key: string): Promise; 25 | removeItem(key: string, callback: (err: any) => void): void; 26 | 27 | clear(): Promise; 28 | clear(callback: (err: any) => void): void; 29 | 30 | length(): Promise; 31 | length(callback: (err: any, numberOfKeys: number) => void): void; 32 | 33 | key(keyIndex: number): Promise; 34 | key(keyIndex: number, callback: (err: any, key: string) => void): void; 35 | 36 | keys(): Promise; 37 | keys(callback: (err: any, keys: string[]) => void): void; 38 | 39 | iterate(iteratee: (value: any, key: string, iterationNumber: number) => any): Promise; 40 | iterate(iteratee: (value: any, key: string, iterationNumber: number) => any, 41 | callback: (err: any, result: any) => void): void; 42 | } 43 | 44 | interface LocalForageDriverSupportFunc { 45 | (): Promise; 46 | } 47 | 48 | interface LocalForageDriver extends LocalForageDbMethods { 49 | _driver: string; 50 | 51 | _initStorage(options: LocalForageOptions): void; 52 | 53 | _support?: boolean | LocalForageDriverSupportFunc; 54 | } 55 | 56 | interface LocalForageSerializer { 57 | serialize(value: T | ArrayBuffer | Blob, callback: (value: string, error: any) => void): void; 58 | 59 | deserialize(value: string): T | ArrayBuffer | Blob; 60 | 61 | stringToBuffer(serializedString: string): ArrayBuffer; 62 | 63 | bufferToString(buffer: ArrayBuffer): string; 64 | } 65 | 66 | interface LocalForage extends LocalForageDbMethods { 67 | LOCALSTORAGE: string; 68 | WEBSQL: string; 69 | INDEXEDDB: string; 70 | 71 | /** 72 | * Set and persist localForage options. This must be called before any other calls to localForage are made, but can be called after localForage is loaded. 73 | * If you set any config values with this method they will persist after driver changes, so you can call config() then setDriver() 74 | * @param {LocalForageOptions} options? 75 | */ 76 | config(options: LocalForageOptions): boolean; 77 | 78 | /** 79 | * Create a new instance of localForage to point to a different store. 80 | * All the configuration options used by config are supported. 81 | * @param {LocalForageOptions} options 82 | */ 83 | createInstance(options: LocalForageOptions): LocalForage; 84 | 85 | driver(): string; 86 | /** 87 | * Force usage of a particular driver or drivers, if available. 88 | * @param {string} driver 89 | */ 90 | setDriver(driver: string | string[]): Promise; 91 | setDriver(driver: string | string[], callback: () => void, errorCallback: (error: any) => void): void; 92 | defineDriver(driver: LocalForageDriver): Promise; 93 | defineDriver(driver: LocalForageDriver, callback: () => void, errorCallback: (error: any) => void): void; 94 | /** 95 | * Return a particular driver 96 | * @param {string} driver 97 | */ 98 | getDriver(driver: string): Promise; 99 | 100 | getSerializer(): Promise; 101 | getSerializer(callback: (serializer: LocalForageSerializer) => void): void; 102 | 103 | supports(driverName: string): boolean; 104 | 105 | ready(callback: () => void): void; 106 | ready(): Promise; 107 | } 108 | 109 | declare module "localforage" { 110 | let localforage: LocalForage; 111 | export = localforage; 112 | } 113 | -------------------------------------------------------------------------------- /components/header/Header.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | // #region imports 4 | import Link from 'next/link'; 5 | import Router from 'next/router'; 6 | import { connect } from 'react-redux'; 7 | import { bindActionCreators } from 'redux'; 8 | import * as userAuthActions from '../../redux/modules/userAuth'; 9 | import Navbar from 'react-bootstrap/lib/Navbar'; 10 | import Nav from 'react-bootstrap/lib/Nav'; 11 | import NavItem from 'react-bootstrap/lib/NavItem'; 12 | // import NavDropdown from 'react-bootstrap/lib/NavDropdown'; 13 | // import MenuItem from 'react-bootstrap/lib/MenuItem'; 14 | import { PureComponent } from 'react'; 15 | // #endregion 16 | 17 | // #region flow types 18 | type Props = { 19 | // userAuth: 20 | isAuthenticated: boolean, 21 | disconnectUser: (...any) => any, 22 | 23 | ...any 24 | }; 25 | 26 | type State = any; 27 | // #endregion 28 | 29 | class Header extends PureComponent { 30 | // #region default props 31 | static defaultProps = { 32 | isAuthenticated: false 33 | }; 34 | 35 | // #region component lifecycle methods 36 | render() { 37 | const { 38 | isAuthenticated 39 | } = this.props; 40 | 41 | return ( 42 | 47 | 48 | 49 | 52 | react-redux-next-bootstrap starter 53 | 54 | 55 | 56 | 57 | 58 |