├── .babelrc ├── .dockerignore ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .flowconfig ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .vscode └── launch.json ├── CHANGELOG.md ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── README.md ├── assets ├── Paypal-button.png ├── Paypal-button@2x.png └── Paypal-button@3x.png ├── components ├── header │ ├── Header.js │ └── index.js ├── layout │ ├── Layout.js │ └── index.js └── privateRoute │ ├── PrivateRoute.js │ └── index.js ├── config ├── appConfig.js └── theme.js ├── docs ├── _next │ └── static │ │ ├── Q0JVIO_wUTVKoda1tiL4i │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _error.js │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── page1.js │ │ │ └── private1.js │ │ ├── chunks │ │ ├── 0.js │ │ ├── 0.js.map │ │ └── commons.b192840d4295db06bd92.js │ │ ├── development │ │ ├── dll │ │ │ └── dll_0a5735af42686c2a38b2.js │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _app.js.map │ │ │ ├── _error.js │ │ │ ├── _error.js.map │ │ │ ├── index.js │ │ │ ├── index.js.map │ │ │ ├── login.js │ │ │ ├── login.js.map │ │ │ ├── page1.js │ │ │ ├── page1.js.map │ │ │ ├── private1.js │ │ │ └── private1.js.map │ │ ├── runtime │ │ ├── main-4888d1fc3b6b523c2e7d.js │ │ ├── main.js │ │ ├── main.js.map │ │ ├── webpack-42652fa8b82c329c0559.js │ │ ├── webpack.js │ │ └── webpack.js.map │ │ └── webpack │ │ ├── 2b67f5f537bd59709cfa.hot-update.json │ │ ├── 80544a9968c67138357d.hot-update.json │ │ ├── ae14abc119ea9d1e3a5a.hot-update.json │ │ └── b0dd31550cc436381fd4.hot-update.json ├── index.html ├── login │ └── index.html ├── page1 │ └── index.html ├── private1 │ └── index.html ├── service-worker.js └── static │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── browserconfig.xml │ ├── css │ └── bootstrap.min.css │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── manifest.json │ ├── mstile-150x150.png │ ├── robot.txt │ ├── safari-pinned-tab.svg │ └── splashscreen-icon-512x512.png ├── flow-typed └── npm │ ├── babel-plugin-transform-async-to-generator_vx.x.x.js │ ├── babel-plugin-transform-regenerator_vx.x.x.js │ ├── babel-preset-es2015_vx.x.x.js │ ├── babel-preset-flow_vx.x.x.js │ ├── babel-preset-react_vx.x.x.js │ ├── babel-preset-stage-2_vx.x.x.js │ ├── eslint-plugin-flowtype_vx.x.x.js │ ├── eslint-plugin-react_vx.x.x.js │ ├── eslint_vx.x.x.js │ ├── flow-bin_v0.x.x.js │ └── next_vx.x.x.js ├── lighthouse-0.1.1.png ├── lighthouse-test.png ├── mock ├── fakeAPI.json └── userInfosMock.json ├── next.config.js ├── out ├── 404.html ├── _next │ └── static │ │ ├── 8Ch3BaHLClZes2TshMjtO │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _error.js │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── page1.js │ │ │ └── private1.js │ │ ├── E8A3lEOVgy6tVT4xFsF3A │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _error.js │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── page1.js │ │ │ └── private1.js │ │ ├── ETV0yduCoHZQSRvXa1kES │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _error.js │ │ │ ├── dynamicPage │ │ │ └── [counter].js │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── page1.js │ │ │ └── private1.js │ │ ├── Jk9jgxKuHpiIQbnW1eVrf │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _error.js │ │ │ ├── dynamicPage │ │ │ └── [counter].js │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── page1.js │ │ │ └── private1.js │ │ ├── OZL-5jOmfz85RjoqpvO_b │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _error.js │ │ │ ├── dynamicPage │ │ │ └── [counter].js │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── page1.js │ │ │ └── private1.js │ │ ├── USOnSTBlp3bpEJu1grJrb │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _error.js │ │ │ ├── dynamicPage │ │ │ └── [counter].js │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── page1.js │ │ │ └── private1.js │ │ ├── ZTxuxVox1tjFqEKeVXToj │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _error.js │ │ │ ├── dynamicPage │ │ │ └── [counter].js │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── page1.js │ │ │ └── private1.js │ │ ├── cHnXSbNTyPGpdBtPjBW9K │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _error.js │ │ │ ├── dynamicPage │ │ │ └── [counter].js │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── page1.js │ │ │ └── private1.js │ │ ├── chunks │ │ ├── 0.js │ │ ├── 0.js.map │ │ └── commons.cbbc5cda5d9c1e5f29c2.js │ │ ├── development │ │ ├── dll │ │ │ ├── dll_b9dcb1e8da809739c7e4.js │ │ │ └── dll_b9dcb1e8da809739c7e4.js.map │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _app.js.map │ │ │ ├── _error.js │ │ │ ├── _error.js.map │ │ │ ├── index.js │ │ │ ├── index.js.map │ │ │ ├── login.js │ │ │ ├── login.js.map │ │ │ ├── page1.js │ │ │ └── page1.js.map │ │ ├── o3_mrJnwnQsdrtluok-i1 │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _error.js │ │ │ ├── dynamicPage │ │ │ └── [counter].js │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── page1.js │ │ │ └── private1.js │ │ ├── pg_jSjSEGmeN3hq7f8YoC │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _error.js │ │ │ ├── dynamicPage │ │ │ └── [counter].js │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── page1.js │ │ │ └── private1.js │ │ ├── runtime │ │ ├── amp.js │ │ ├── amp.js.map │ │ ├── main-5676d46b107b105eec22.js │ │ ├── main.js │ │ ├── main.js.map │ │ ├── webpack-3df6523e264ff2ac6548.js │ │ ├── webpack.js │ │ └── webpack.js.map │ │ ├── uqEdtzFbZBMDEf_37_jDb │ │ └── pages │ │ │ ├── _app.js │ │ │ ├── _error.js │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── page1.js │ │ │ └── private1.js │ │ └── webpack │ │ ├── 712641909e13af060bf1.hot-update.json │ │ ├── cf4f576164d133d12b4a.hot-update.json │ │ └── fee1c80e30f9756052df.hot-update.json ├── dynamicPage │ └── [counter].html ├── index.html ├── login.html ├── page1.html ├── private1.html ├── service-worker.js └── static │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── browserconfig.xml │ ├── css │ └── bootstrap.min.css │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── manifest.json │ ├── mstile-150x150.png │ ├── robot.txt │ ├── safari-pinned-tab.svg │ └── splashscreen-icon-512x512.png ├── package.json ├── pages ├── _app.js ├── _document.js ├── _error.js ├── dynamicPage │ └── [counter].js ├── index.js ├── login.js ├── page1.js └── private1.js ├── preview.png ├── redux ├── middleware │ └── fetchMiddleware.js ├── modules │ ├── fakeModuleWithFetch.js │ ├── persistStore.js │ ├── reducers.js │ └── userAuth.js └── store │ ├── configureStore.dev.js │ ├── configureStore.js │ └── configureStore.prod.js ├── server ├── index.js └── static.js ├── static ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── browserconfig.xml ├── css │ └── bootstrap.min.css ├── favicon-16x16.png ├── favicon-32x32.png ├── manifest.json ├── mstile-150x150.png ├── robot.txt ├── safari-pinned-tab.svg └── splashscreen-icon-512x512.png ├── style └── globalStyle.js ├── types ├── nextjs │ └── index.js └── redux │ ├── modules │ ├── fakeModuleWithFetch │ │ └── index.js │ └── userAuth │ │ └── index.js │ └── redux-thunk │ └── index.js ├── typings.json ├── typings ├── globals │ ├── axios │ │ ├── index.d.ts │ │ └── typings.json │ ├── bootstrap │ │ ├── index.d.ts │ │ └── typings.json │ ├── classnames │ │ ├── index.d.ts │ │ └── typings.json │ ├── localforage │ │ ├── index.d.ts │ │ └── typings.json │ ├── modernizr │ │ ├── index.d.ts │ │ └── typings.json │ ├── popper.js │ │ ├── index.d.ts │ │ └── typings.json │ ├── react-ga │ │ ├── index.d.ts │ │ └── typings.json │ ├── recompose │ │ ├── index.d.ts │ │ └── typings.json │ ├── redux-thunk │ │ ├── index.d.ts │ │ └── typings.json │ ├── redux │ │ ├── index.d.ts │ │ └── typings.json │ └── reselect │ │ ├── index.d.ts │ │ └── typings.json └── index.d.ts ├── utils ├── auth │ └── index.js ├── fetchTools │ └── index.js └── sw │ └── index.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/preset-env", { 4 | "modules": false, 5 | "targets": "> 0.25%, not dead" 6 | }], 7 | "@babel/preset-react", 8 | "next/babel", 9 | "@babel/preset-flow" 10 | ], 11 | "plugins": [ 12 | "@babel/plugin-proposal-class-properties", 13 | "@babel/plugin-proposal-object-rest-spread", 14 | "@babel/plugin-transform-regenerator", 15 | "@babel/plugin-transform-async-to-generator", 16 | "@babel/plugin-syntax-dynamic-import" 17 | ], 18 | "env": { 19 | "test": { 20 | "presets": [ 21 | "@babel/preset-env", 22 | "@babel/preset-react", 23 | "next/babel", 24 | "@babel/preset-flow" 25 | ], 26 | "plugins": [ 27 | "@babel/plugin-transform-modules-commonjs", 28 | "@babel/plugin-proposal-class-properties", 29 | "@babel/plugin-proposal-object-rest-spread", 30 | "@babel/plugin-transform-regenerator", 31 | "@babel/plugin-transform-async-to-generator", 32 | "@babel/plugin-syntax-dynamic-import" 33 | ] 34 | }, 35 | "production": { 36 | "plugins": ["transform-remove-console"], 37 | "comments": false 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .git 3 | -------------------------------------------------------------------------------- /.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 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | coverage/* 3 | .next/* 4 | .vscode/* 5 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [lints] 8 | 9 | [options] 10 | module.file_ext=.css 11 | module.name_mapper='.*\(.css\)' -> 'CSSModule' 12 | module.system=haste 13 | suppress_comment= \\(.\\|\n\\)*\\$FlowIgnore 14 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.json 2 | **/*.txt 3 | **/*.xml 4 | **/*.svg 5 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## 1.0.0 (RELEASED) 4 | 5 | - upgade to `NextJS 9+` 6 | - move to `pure function` + `hook` (_as much as possible since some components like pages/_App needs to extends NextJS class App_) 7 | - add `styled-components` 8 | - improved `seo` (_= just better use of NextJS Head_) 9 | - improved `Flow types` (_Typescript is available in NextJS 9 but this can be **too much** for **little application**_) 10 | 11 | ## 0.1.1 (RELEASED) 12 | 13 | - feature browser cookie disabled 14 | - feature nojavascript 15 | 16 | ## 0.1.0 (RELEASED) 17 | 18 | - better PWA (*add to home screen...*) 19 | 20 | ## 0.0.1 (RELEASED) 21 | 22 | - first bricks of this starter 23 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # ISSUES TEMPLATE 2 | 3 | ## Version 4 | 5 | 1.2.0 6 | 7 | ## Node JS 8 | 9 | v7.x | v8.X 10 | 11 | ## Browser 12 | 13 | Chrome 64.x | Safari 11.x 14 | 15 | ## OS version 16 | 17 | macOS | windows 10 | linux Ubuntu... 18 | 19 | ## Steps to reproduce 20 | 21 | 1. explantion 1... 22 | 23 | 2. explantion 2... 24 | 25 | 3. explantion 3... 26 | 27 | ## Expected behavior 28 | 29 | What should happen 30 | 31 | ## Actual behavior 32 | 33 | What is happening 34 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /assets/Paypal-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacKentoch/react-redux-nextjs-bootstrap-pwa-starter/a93fb9713100e8ecdfbbcca26e669ff0286f7a70/assets/Paypal-button.png -------------------------------------------------------------------------------- /assets/Paypal-button@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacKentoch/react-redux-nextjs-bootstrap-pwa-starter/a93fb9713100e8ecdfbbcca26e669ff0286f7a70/assets/Paypal-button@2x.png -------------------------------------------------------------------------------- /assets/Paypal-button@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacKentoch/react-redux-nextjs-bootstrap-pwa-starter/a93fb9713100e8ecdfbbcca26e669ff0286f7a70/assets/Paypal-button@3x.png -------------------------------------------------------------------------------- /components/header/Header.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React, { useState, useCallback } from 'react'; 4 | import { useRouter } from 'next/router'; 5 | import { connect } from 'react-redux'; 6 | import { bindActionCreators } from 'redux'; 7 | import { 8 | Collapse, 9 | Navbar, 10 | NavbarToggler, 11 | NavbarBrand, 12 | Nav, 13 | NavItem, 14 | NavLink, 15 | } from 'reactstrap'; 16 | import * as userAuthActions from '../../redux/modules/userAuth'; 17 | 18 | // #region types 19 | type Props = { 20 | // userAuth: 21 | isAuthenticated: boolean, 22 | disconnectUser: (...any) => any, 23 | }; 24 | // #endregion 25 | 26 | function Header({ isAuthenticated, disconnectUser }: Props) { 27 | const [isOpen, setIsOpen] = useState(false); 28 | const { push, replace } = useRouter(); 29 | 30 | // #region callbacks 31 | const toggle = useCallback(() => setIsOpen(!isOpen), [isOpen]); 32 | 33 | const navigateTo = useCallback((to: string = '/') => () => push(to), []); 34 | 35 | const handlesDisconnectUser = useCallback((event?: SyntheticEvent<>) => { 36 | event && event.preventDefault(); 37 | disconnectUser(); 38 | replace('/login'); 39 | }, []); 40 | // #endregion 41 | 42 | return ( 43 | <> 44 | 45 | react-redux-next-bootstrap starter 46 | 47 | 48 |