From bce7dce91ef7563985a6afa67b6b55f1842d72df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanislas=20Ormi=C3=A8re?= Date: Mon, 17 Dec 2018 14:18:39 +0100 Subject: [PATCH 01/85] Put the source files in a src folder --- client/{ => src}/App.js | 0 client/{ => src}/components/.keep | 0 .../AutoCompleteAddresses/AutoCompleteAddresses.js | 0 .../AutoCompleteAddresses/FetchAddresses.js | 0 .../autoCompleteAddressesStyle.js | 0 .../Notifications/SnackbarNotificationWrapper.js | 0 .../{ => src}/components/calendar/CreneauEvent.js | 0 client/{ => src}/components/calendar/messages.js | 0 client/{ => src}/index.js | 0 client/{ => src}/lib/regex.js | 0 client/{ => src}/main.css | 0 .../modules/Admin/pages/AdminPage/AdminPage.js | 0 client/{ => src}/modules/Admin/pages/Login/Login.js | 0 .../modules/Admin/pages/WhiteList/ListWhitelist.js | 0 client/{ => src}/modules/App/App.css | 0 client/{ => src}/modules/App/App.js | 0 client/{ => src}/modules/App/AppActions.js | 0 client/{ => src}/modules/App/AppReducer.js | 0 client/{ => src}/modules/App/__tests__/App.spec.js | 0 .../modules/App/__tests__/AppActions.spec.js | 0 .../modules/App/__tests__/AppReducer.spec.js | 0 .../modules/App/__tests__/Components/Footer.spec.js | 0 .../modules/App/__tests__/Components/Header.spec.js | 0 client/{ => src}/modules/App/components/DevTools.js | 0 .../modules/App/components/Footer/Footer.css | 0 .../modules/App/components/Footer/Footer.js | 0 .../modules/App/components/Header/Header.css | 0 .../modules/App/components/Header/Header.js | 0 client/{ => src}/modules/App/header-bk.png | Bin client/{ => src}/modules/Auth/Auth.js | 0 .../modules/Calendar/components/CreneauDialog.js | 0 .../pages/CalendarListPage/CalendarListPage.js | 0 .../modules/Candidat/components/ListCandidats.js | 0 .../modules/Candidat/components/RowDetail.js | 0 .../modules/GeneralConditions/GeneralConditions.css | 0 .../modules/GeneralConditions/GeneralConditions.js | 0 .../modules/Home/components/Login/Login.js | 0 .../modules/Home/components/errors.constants.js | 0 client/{ => src}/modules/Informations/Faq.css | 0 .../{ => src}/modules/Informations/Informations.js | 0 client/{ => src}/reducers.js | 0 client/{ => src}/routes.js | 0 client/{ => src}/store.js | 0 client/{ => src}/theme.js | 0 client/{ => src}/util/PrivateRoute.js | 0 client/{ => src}/util/__tests__/apiCaller.spec.js | 0 client/{ => src}/util/apiCaller.admin.js | 0 client/{ => src}/util/apiCaller.js | 0 client/{ => src}/util/app.constants.js | 0 client/{ => src}/util/storage.js | 0 50 files changed, 0 insertions(+), 0 deletions(-) rename client/{ => src}/App.js (100%) rename client/{ => src}/components/.keep (100%) rename client/{ => src}/components/AutoCompleteAddresses/AutoCompleteAddresses.js (100%) rename client/{ => src}/components/AutoCompleteAddresses/FetchAddresses.js (100%) rename client/{ => src}/components/AutoCompleteAddresses/autoCompleteAddressesStyle.js (100%) rename client/{ => src}/components/Notifications/SnackbarNotificationWrapper.js (100%) rename client/{ => src}/components/calendar/CreneauEvent.js (100%) rename client/{ => src}/components/calendar/messages.js (100%) rename client/{ => src}/index.js (100%) rename client/{ => src}/lib/regex.js (100%) rename client/{ => src}/main.css (100%) rename client/{ => src}/modules/Admin/pages/AdminPage/AdminPage.js (100%) rename client/{ => src}/modules/Admin/pages/Login/Login.js (100%) rename client/{ => src}/modules/Admin/pages/WhiteList/ListWhitelist.js (100%) rename client/{ => src}/modules/App/App.css (100%) rename client/{ => src}/modules/App/App.js (100%) rename client/{ => src}/modules/App/AppActions.js (100%) rename client/{ => src}/modules/App/AppReducer.js (100%) rename client/{ => src}/modules/App/__tests__/App.spec.js (100%) rename client/{ => src}/modules/App/__tests__/AppActions.spec.js (100%) rename client/{ => src}/modules/App/__tests__/AppReducer.spec.js (100%) rename client/{ => src}/modules/App/__tests__/Components/Footer.spec.js (100%) rename client/{ => src}/modules/App/__tests__/Components/Header.spec.js (100%) rename client/{ => src}/modules/App/components/DevTools.js (100%) rename client/{ => src}/modules/App/components/Footer/Footer.css (100%) rename client/{ => src}/modules/App/components/Footer/Footer.js (100%) rename client/{ => src}/modules/App/components/Header/Header.css (100%) rename client/{ => src}/modules/App/components/Header/Header.js (100%) rename client/{ => src}/modules/App/header-bk.png (100%) rename client/{ => src}/modules/Auth/Auth.js (100%) rename client/{ => src}/modules/Calendar/components/CreneauDialog.js (100%) rename client/{ => src}/modules/Calendar/pages/CalendarListPage/CalendarListPage.js (100%) rename client/{ => src}/modules/Candidat/components/ListCandidats.js (100%) rename client/{ => src}/modules/Candidat/components/RowDetail.js (100%) rename client/{ => src}/modules/GeneralConditions/GeneralConditions.css (100%) rename client/{ => src}/modules/GeneralConditions/GeneralConditions.js (100%) rename client/{ => src}/modules/Home/components/Login/Login.js (100%) rename client/{ => src}/modules/Home/components/errors.constants.js (100%) rename client/{ => src}/modules/Informations/Faq.css (100%) rename client/{ => src}/modules/Informations/Informations.js (100%) rename client/{ => src}/reducers.js (100%) rename client/{ => src}/routes.js (100%) rename client/{ => src}/store.js (100%) rename client/{ => src}/theme.js (100%) rename client/{ => src}/util/PrivateRoute.js (100%) rename client/{ => src}/util/__tests__/apiCaller.spec.js (100%) rename client/{ => src}/util/apiCaller.admin.js (100%) rename client/{ => src}/util/apiCaller.js (100%) rename client/{ => src}/util/app.constants.js (100%) rename client/{ => src}/util/storage.js (100%) diff --git a/client/App.js b/client/src/App.js similarity index 100% rename from client/App.js rename to client/src/App.js diff --git a/client/components/.keep b/client/src/components/.keep similarity index 100% rename from client/components/.keep rename to client/src/components/.keep diff --git a/client/components/AutoCompleteAddresses/AutoCompleteAddresses.js b/client/src/components/AutoCompleteAddresses/AutoCompleteAddresses.js similarity index 100% rename from client/components/AutoCompleteAddresses/AutoCompleteAddresses.js rename to client/src/components/AutoCompleteAddresses/AutoCompleteAddresses.js diff --git a/client/components/AutoCompleteAddresses/FetchAddresses.js b/client/src/components/AutoCompleteAddresses/FetchAddresses.js similarity index 100% rename from client/components/AutoCompleteAddresses/FetchAddresses.js rename to client/src/components/AutoCompleteAddresses/FetchAddresses.js diff --git a/client/components/AutoCompleteAddresses/autoCompleteAddressesStyle.js b/client/src/components/AutoCompleteAddresses/autoCompleteAddressesStyle.js similarity index 100% rename from client/components/AutoCompleteAddresses/autoCompleteAddressesStyle.js rename to client/src/components/AutoCompleteAddresses/autoCompleteAddressesStyle.js diff --git a/client/components/Notifications/SnackbarNotificationWrapper.js b/client/src/components/Notifications/SnackbarNotificationWrapper.js similarity index 100% rename from client/components/Notifications/SnackbarNotificationWrapper.js rename to client/src/components/Notifications/SnackbarNotificationWrapper.js diff --git a/client/components/calendar/CreneauEvent.js b/client/src/components/calendar/CreneauEvent.js similarity index 100% rename from client/components/calendar/CreneauEvent.js rename to client/src/components/calendar/CreneauEvent.js diff --git a/client/components/calendar/messages.js b/client/src/components/calendar/messages.js similarity index 100% rename from client/components/calendar/messages.js rename to client/src/components/calendar/messages.js diff --git a/client/index.js b/client/src/index.js similarity index 100% rename from client/index.js rename to client/src/index.js diff --git a/client/lib/regex.js b/client/src/lib/regex.js similarity index 100% rename from client/lib/regex.js rename to client/src/lib/regex.js diff --git a/client/main.css b/client/src/main.css similarity index 100% rename from client/main.css rename to client/src/main.css diff --git a/client/modules/Admin/pages/AdminPage/AdminPage.js b/client/src/modules/Admin/pages/AdminPage/AdminPage.js similarity index 100% rename from client/modules/Admin/pages/AdminPage/AdminPage.js rename to client/src/modules/Admin/pages/AdminPage/AdminPage.js diff --git a/client/modules/Admin/pages/Login/Login.js b/client/src/modules/Admin/pages/Login/Login.js similarity index 100% rename from client/modules/Admin/pages/Login/Login.js rename to client/src/modules/Admin/pages/Login/Login.js diff --git a/client/modules/Admin/pages/WhiteList/ListWhitelist.js b/client/src/modules/Admin/pages/WhiteList/ListWhitelist.js similarity index 100% rename from client/modules/Admin/pages/WhiteList/ListWhitelist.js rename to client/src/modules/Admin/pages/WhiteList/ListWhitelist.js diff --git a/client/modules/App/App.css b/client/src/modules/App/App.css similarity index 100% rename from client/modules/App/App.css rename to client/src/modules/App/App.css diff --git a/client/modules/App/App.js b/client/src/modules/App/App.js similarity index 100% rename from client/modules/App/App.js rename to client/src/modules/App/App.js diff --git a/client/modules/App/AppActions.js b/client/src/modules/App/AppActions.js similarity index 100% rename from client/modules/App/AppActions.js rename to client/src/modules/App/AppActions.js diff --git a/client/modules/App/AppReducer.js b/client/src/modules/App/AppReducer.js similarity index 100% rename from client/modules/App/AppReducer.js rename to client/src/modules/App/AppReducer.js diff --git a/client/modules/App/__tests__/App.spec.js b/client/src/modules/App/__tests__/App.spec.js similarity index 100% rename from client/modules/App/__tests__/App.spec.js rename to client/src/modules/App/__tests__/App.spec.js diff --git a/client/modules/App/__tests__/AppActions.spec.js b/client/src/modules/App/__tests__/AppActions.spec.js similarity index 100% rename from client/modules/App/__tests__/AppActions.spec.js rename to client/src/modules/App/__tests__/AppActions.spec.js diff --git a/client/modules/App/__tests__/AppReducer.spec.js b/client/src/modules/App/__tests__/AppReducer.spec.js similarity index 100% rename from client/modules/App/__tests__/AppReducer.spec.js rename to client/src/modules/App/__tests__/AppReducer.spec.js diff --git a/client/modules/App/__tests__/Components/Footer.spec.js b/client/src/modules/App/__tests__/Components/Footer.spec.js similarity index 100% rename from client/modules/App/__tests__/Components/Footer.spec.js rename to client/src/modules/App/__tests__/Components/Footer.spec.js diff --git a/client/modules/App/__tests__/Components/Header.spec.js b/client/src/modules/App/__tests__/Components/Header.spec.js similarity index 100% rename from client/modules/App/__tests__/Components/Header.spec.js rename to client/src/modules/App/__tests__/Components/Header.spec.js diff --git a/client/modules/App/components/DevTools.js b/client/src/modules/App/components/DevTools.js similarity index 100% rename from client/modules/App/components/DevTools.js rename to client/src/modules/App/components/DevTools.js diff --git a/client/modules/App/components/Footer/Footer.css b/client/src/modules/App/components/Footer/Footer.css similarity index 100% rename from client/modules/App/components/Footer/Footer.css rename to client/src/modules/App/components/Footer/Footer.css diff --git a/client/modules/App/components/Footer/Footer.js b/client/src/modules/App/components/Footer/Footer.js similarity index 100% rename from client/modules/App/components/Footer/Footer.js rename to client/src/modules/App/components/Footer/Footer.js diff --git a/client/modules/App/components/Header/Header.css b/client/src/modules/App/components/Header/Header.css similarity index 100% rename from client/modules/App/components/Header/Header.css rename to client/src/modules/App/components/Header/Header.css diff --git a/client/modules/App/components/Header/Header.js b/client/src/modules/App/components/Header/Header.js similarity index 100% rename from client/modules/App/components/Header/Header.js rename to client/src/modules/App/components/Header/Header.js diff --git a/client/modules/App/header-bk.png b/client/src/modules/App/header-bk.png similarity index 100% rename from client/modules/App/header-bk.png rename to client/src/modules/App/header-bk.png diff --git a/client/modules/Auth/Auth.js b/client/src/modules/Auth/Auth.js similarity index 100% rename from client/modules/Auth/Auth.js rename to client/src/modules/Auth/Auth.js diff --git a/client/modules/Calendar/components/CreneauDialog.js b/client/src/modules/Calendar/components/CreneauDialog.js similarity index 100% rename from client/modules/Calendar/components/CreneauDialog.js rename to client/src/modules/Calendar/components/CreneauDialog.js diff --git a/client/modules/Calendar/pages/CalendarListPage/CalendarListPage.js b/client/src/modules/Calendar/pages/CalendarListPage/CalendarListPage.js similarity index 100% rename from client/modules/Calendar/pages/CalendarListPage/CalendarListPage.js rename to client/src/modules/Calendar/pages/CalendarListPage/CalendarListPage.js diff --git a/client/modules/Candidat/components/ListCandidats.js b/client/src/modules/Candidat/components/ListCandidats.js similarity index 100% rename from client/modules/Candidat/components/ListCandidats.js rename to client/src/modules/Candidat/components/ListCandidats.js diff --git a/client/modules/Candidat/components/RowDetail.js b/client/src/modules/Candidat/components/RowDetail.js similarity index 100% rename from client/modules/Candidat/components/RowDetail.js rename to client/src/modules/Candidat/components/RowDetail.js diff --git a/client/modules/GeneralConditions/GeneralConditions.css b/client/src/modules/GeneralConditions/GeneralConditions.css similarity index 100% rename from client/modules/GeneralConditions/GeneralConditions.css rename to client/src/modules/GeneralConditions/GeneralConditions.css diff --git a/client/modules/GeneralConditions/GeneralConditions.js b/client/src/modules/GeneralConditions/GeneralConditions.js similarity index 100% rename from client/modules/GeneralConditions/GeneralConditions.js rename to client/src/modules/GeneralConditions/GeneralConditions.js diff --git a/client/modules/Home/components/Login/Login.js b/client/src/modules/Home/components/Login/Login.js similarity index 100% rename from client/modules/Home/components/Login/Login.js rename to client/src/modules/Home/components/Login/Login.js diff --git a/client/modules/Home/components/errors.constants.js b/client/src/modules/Home/components/errors.constants.js similarity index 100% rename from client/modules/Home/components/errors.constants.js rename to client/src/modules/Home/components/errors.constants.js diff --git a/client/modules/Informations/Faq.css b/client/src/modules/Informations/Faq.css similarity index 100% rename from client/modules/Informations/Faq.css rename to client/src/modules/Informations/Faq.css diff --git a/client/modules/Informations/Informations.js b/client/src/modules/Informations/Informations.js similarity index 100% rename from client/modules/Informations/Informations.js rename to client/src/modules/Informations/Informations.js diff --git a/client/reducers.js b/client/src/reducers.js similarity index 100% rename from client/reducers.js rename to client/src/reducers.js diff --git a/client/routes.js b/client/src/routes.js similarity index 100% rename from client/routes.js rename to client/src/routes.js diff --git a/client/store.js b/client/src/store.js similarity index 100% rename from client/store.js rename to client/src/store.js diff --git a/client/theme.js b/client/src/theme.js similarity index 100% rename from client/theme.js rename to client/src/theme.js diff --git a/client/util/PrivateRoute.js b/client/src/util/PrivateRoute.js similarity index 100% rename from client/util/PrivateRoute.js rename to client/src/util/PrivateRoute.js diff --git a/client/util/__tests__/apiCaller.spec.js b/client/src/util/__tests__/apiCaller.spec.js similarity index 100% rename from client/util/__tests__/apiCaller.spec.js rename to client/src/util/__tests__/apiCaller.spec.js diff --git a/client/util/apiCaller.admin.js b/client/src/util/apiCaller.admin.js similarity index 100% rename from client/util/apiCaller.admin.js rename to client/src/util/apiCaller.admin.js diff --git a/client/util/apiCaller.js b/client/src/util/apiCaller.js similarity index 100% rename from client/util/apiCaller.js rename to client/src/util/apiCaller.js diff --git a/client/util/app.constants.js b/client/src/util/app.constants.js similarity index 100% rename from client/util/app.constants.js rename to client/src/util/app.constants.js diff --git a/client/util/storage.js b/client/src/util/storage.js similarity index 100% rename from client/util/storage.js rename to client/src/util/storage.js From c09563e9a2c692cba41f5247853e7a62c60c27dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanislas=20Ormi=C3=A8re?= Date: Mon, 17 Dec 2018 14:20:06 +0100 Subject: [PATCH 02/85] Add create-react-app boilerplate --- client/config/env.js | 93 + client/config/jest/cssTransform.js | 14 + client/config/jest/fileTransform.js | 30 + client/config/paths.js | 89 + client/config/webpack.config.dev.js | 423 + client/config/webpack.config.prod.js | 539 + client/config/webpackDevServer.config.js | 105 + client/package-lock.json | 15871 +++++++++++++++++++++ client/package.json | 150 + client/public/favicon.ico | Bin 0 -> 3870 bytes client/public/index.html | 40 + client/public/manifest.json | 15 + client/scripts/build.js | 189 + client/scripts/start.js | 116 + client/scripts/test.js | 53 + 15 files changed, 17727 insertions(+) create mode 100644 client/config/env.js create mode 100644 client/config/jest/cssTransform.js create mode 100644 client/config/jest/fileTransform.js create mode 100644 client/config/paths.js create mode 100644 client/config/webpack.config.dev.js create mode 100644 client/config/webpack.config.prod.js create mode 100644 client/config/webpackDevServer.config.js create mode 100644 client/package-lock.json create mode 100644 client/package.json create mode 100644 client/public/favicon.ico create mode 100644 client/public/index.html create mode 100644 client/public/manifest.json create mode 100644 client/scripts/build.js create mode 100644 client/scripts/start.js create mode 100644 client/scripts/test.js diff --git a/client/config/env.js b/client/config/env.js new file mode 100644 index 0000000..b0344c5 --- /dev/null +++ b/client/config/env.js @@ -0,0 +1,93 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const paths = require('./paths'); + +// Make sure that including paths.js after env.js will read .env variables. +delete require.cache[require.resolve('./paths')]; + +const NODE_ENV = process.env.NODE_ENV; +if (!NODE_ENV) { + throw new Error( + 'The NODE_ENV environment variable is required but was not specified.' + ); +} + +// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use +var dotenvFiles = [ + `${paths.dotenv}.${NODE_ENV}.local`, + `${paths.dotenv}.${NODE_ENV}`, + // Don't include `.env.local` for `test` environment + // since normally you expect tests to produce the same + // results for everyone + NODE_ENV !== 'test' && `${paths.dotenv}.local`, + paths.dotenv, +].filter(Boolean); + +// Load environment variables from .env* files. Suppress warnings using silent +// if this file is missing. dotenv will never modify any environment variables +// that have already been set. Variable expansion is supported in .env files. +// https://github.com/motdotla/dotenv +// https://github.com/motdotla/dotenv-expand +dotenvFiles.forEach(dotenvFile => { + if (fs.existsSync(dotenvFile)) { + require('dotenv-expand')( + require('dotenv').config({ + path: dotenvFile, + }) + ); + } +}); + +// We support resolving modules according to `NODE_PATH`. +// This lets you use absolute paths in imports inside large monorepos: +// https://github.com/facebook/create-react-app/issues/253. +// It works similar to `NODE_PATH` in Node itself: +// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders +// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. +// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims. +// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421 +// We also resolve them to make sure all tools using them work consistently. +const appDirectory = fs.realpathSync(process.cwd()); +process.env.NODE_PATH = (process.env.NODE_PATH || '') + .split(path.delimiter) + .filter(folder => folder && !path.isAbsolute(folder)) + .map(folder => path.resolve(appDirectory, folder)) + .join(path.delimiter); + +// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be +// injected into the application via DefinePlugin in Webpack configuration. +const REACT_APP = /^REACT_APP_/i; + +function getClientEnvironment(publicUrl) { + const raw = Object.keys(process.env) + .filter(key => REACT_APP.test(key)) + .reduce( + (env, key) => { + env[key] = process.env[key]; + return env; + }, + { + // Useful for determining whether we’re running in production mode. + // Most importantly, it switches React into the correct mode. + NODE_ENV: process.env.NODE_ENV || 'development', + // Useful for resolving the correct path to static assets in `public`. + // For example, . + // This should only be used as an escape hatch. Normally you would put + // images into the `src` and `import` them in code to get their paths. + PUBLIC_URL: publicUrl, + } + ); + // Stringify all values so we can feed into Webpack DefinePlugin + const stringified = { + 'process.env': Object.keys(raw).reduce((env, key) => { + env[key] = JSON.stringify(raw[key]); + return env; + }, {}), + }; + + return { raw, stringified }; +} + +module.exports = getClientEnvironment; diff --git a/client/config/jest/cssTransform.js b/client/config/jest/cssTransform.js new file mode 100644 index 0000000..8f65114 --- /dev/null +++ b/client/config/jest/cssTransform.js @@ -0,0 +1,14 @@ +'use strict'; + +// This is a custom Jest transformer turning style imports into empty objects. +// http://facebook.github.io/jest/docs/en/webpack.html + +module.exports = { + process() { + return 'module.exports = {};'; + }, + getCacheKey() { + // The output is always the same. + return 'cssTransform'; + }, +}; diff --git a/client/config/jest/fileTransform.js b/client/config/jest/fileTransform.js new file mode 100644 index 0000000..07010e3 --- /dev/null +++ b/client/config/jest/fileTransform.js @@ -0,0 +1,30 @@ +'use strict'; + +const path = require('path'); + +// This is a custom Jest transformer turning file imports into filenames. +// http://facebook.github.io/jest/docs/en/webpack.html + +module.exports = { + process(src, filename) { + const assetFilename = JSON.stringify(path.basename(filename)); + + if (filename.match(/\.svg$/)) { + return `module.exports = { + __esModule: true, + default: ${assetFilename}, + ReactComponent: (props) => ({ + $$typeof: Symbol.for('react.element'), + type: 'svg', + ref: null, + key: null, + props: Object.assign({}, props, { + children: ${assetFilename} + }) + }), + };`; + } + + return `module.exports = ${assetFilename};`; + }, +}; diff --git a/client/config/paths.js b/client/config/paths.js new file mode 100644 index 0000000..c24b4dd --- /dev/null +++ b/client/config/paths.js @@ -0,0 +1,89 @@ +'use strict'; + +const path = require('path'); +const fs = require('fs'); +const url = require('url'); + +// Make sure any symlinks in the project folder are resolved: +// https://github.com/facebook/create-react-app/issues/637 +const appDirectory = fs.realpathSync(process.cwd()); +const resolveApp = relativePath => path.resolve(appDirectory, relativePath); + +const envPublicUrl = process.env.PUBLIC_URL; + +function ensureSlash(inputPath, needsSlash) { + const hasSlash = inputPath.endsWith('/'); + if (hasSlash && !needsSlash) { + return inputPath.substr(0, inputPath.length - 1); + } else if (!hasSlash && needsSlash) { + return `${inputPath}/`; + } else { + return inputPath; + } +} + +const getPublicUrl = appPackageJson => + envPublicUrl || require(appPackageJson).homepage; + +// We use `PUBLIC_URL` environment variable or "homepage" field to infer +// "public path" at which the app is served. +// Webpack needs to know it to put the right - - - - - `; -}; - -const renderError = (err) => { - const softTab = ' '; - const errTrace = isProdMode - ? `:

${softTab}${err.stack.replace(
-        /\n/g,
-        `
${softTab}`, - )}
` - : ''; - return renderFullPage(`Server Error${errTrace}`, {}); -}; - -// Server Side Rendering based on routes matched by React-router. -app.use((req, res, next) => { - match({ routes, location: req.url }, (err, redirectLocation, renderProps) => { - if (err) { - return res.status(500).end(renderError(err)); - } - - if (redirectLocation) { - return res.redirect( - 302, - redirectLocation.pathname + redirectLocation.search, - ); - } - - if (!renderProps) { - return next(); - } - - // PrivateRoute - if (typeof routes.props.children === 'object') { - const childrenPrivateRoute = routes.props.children.find((child) => { - return ( - child.type !== undefined - && child.props !== undefined - && renderProps !== undefined - && renderProps.location !== undefined - && child.type.name === 'PrivateRoute' - && child.props.path === renderProps.location.pathname.toLowerCase() - && renderProps.location.pathname !== '/auth' - ); - }); - if (childrenPrivateRoute !== undefined) { - return res.redirect( - 302, - '/auth?redirect=' + renderProps.location.pathname, - ); - } - } - - const store = configureStore(); - - return fetchComponentData(store, renderProps.components, renderProps.params) - .then(() => { - const initialView = renderToString( - - - , - ); - const finalState = store.getState(); - - res - .set('Content-Type', 'text/html') - .status(200) - .end(renderFullPage(initialView, finalState)); - }) - .catch(error => next(error)); - }); -}); - // start app app.listen(serverConfig.port, (error) => { if (!error) { console.log( - `Candilib is running on port: ${process.env.PORT - || serverConfig.port}! Build something amazing!`, + `Candilib is running on port: ${process.env.PORT || serverConfig.port}!`, ); // eslint-disable-line } }); diff --git a/webpack.config.dev.js b/webpack.config.dev.js deleted file mode 100644 index aaf409a..0000000 --- a/webpack.config.dev.js +++ /dev/null @@ -1,108 +0,0 @@ -var webpack = require('webpack'); -var postcssPresetEnv = require('postcss-preset-env'); -var postcssFocus = require('postcss-focus'); -var postcssReporter = require('postcss-reporter'); - -module.exports = { - devtool: 'cheap-module-eval-source-map', - - entry: { - app: [ - 'eventsource-polyfill', - 'webpack-hot-middleware/client', - 'webpack/hot/only-dev-server', - 'react-hot-loader/patch', - './client/index.js', - ], - vendor: [ - 'react', - 'react-dom', - ], - }, - - output: { - path: __dirname, - filename: 'app.js', - }, - - resolve: { - extensions: ['.js', '.jsx'], - modules: [ - 'client', - 'node_modules', - ], - }, - - module: { - rules: [ - { - test: /\.s?css$/, - exclude: /node_modules/, - use: [ - { - loader: 'style-loader', - }, - { - loader: 'css-loader', - options: { - localIdentName: '[name]__[local]__[hash:base64:5]', - modules: true, - importLoaders: 1, - sourceMap: true, - }, - }, - { - loader: 'postcss-loader', - options: { - plugins: () => [ - postcssFocus(), - postcssPresetEnv({ - browsers: ['last 2 versions', 'IE > 10'], - }), - postcssReporter({ - clearMessages: true, - }), - ], - }, - }, - ], - }, - { - test: /\.css$/, - include: /node_modules/, - use: ['style-loader', 'css-loader'], - }, - { - test: /\.jsx*$/, - exclude: [/node_modules/, /.+\.config.js/], - use: 'babel-loader', - }, - { - test: /\.(jpe?g|gif|png|svg)$/i, - use: [ - { - loader: 'url-loader', - options: { - limit: 10000, - }, - }, - ], - }, - ], - }, - - plugins: [ - new webpack.HotModuleReplacementPlugin(), - new webpack.optimize.CommonsChunkPlugin({ - name: 'vendor', - minChunks: Infinity, - filename: 'vendor.js', - }), - new webpack.DefinePlugin({ - 'process.env': { - CLIENT: JSON.stringify(true), - 'NODE_ENV': JSON.stringify('development'), - } - }), - ], -}; From c5f2533f22da05a825da5bce09695a30acfe7d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanislas=20Ormi=C3=A8re?= Date: Mon, 17 Dec 2018 19:48:08 +0100 Subject: [PATCH 04/85] Upgrade react-router and use redux --- client/src/App.js | 37 ++--- client/src/App.test.js | 9 ++ client/src/api/api-paths.js | 15 ++ client/src/api/index.js | 152 ++++++++++++++++++ client/src/components/Button.js | 17 ++ client/src/config/constants.js | 2 + client/src/config/theme.js | 20 +++ client/src/index.js | 42 ++--- client/src/main.css | 24 +-- .../modules/App/components/Footer/Footer.js | 2 +- .../modules/App/components/Header/Header.js | 2 +- client/src/pages/Candilib.js | 113 +++++++++++++ client/src/pages/Home.js | 41 +++++ client/src/pages/NoMatch.js | 9 ++ client/src/reducers.js | 12 -- client/src/routes.js | 51 ------ client/src/serviceWorker.js | 135 ++++++++++++++++ client/src/store.js | 24 --- client/src/store/Auth/Auth.actions.js | 65 ++++++++ client/src/store/Auth/Auth.reducer.js | 81 ++++++++++ client/src/store/Auth/Auth.saga.js | 121 ++++++++++++++ client/src/store/index.js | 30 ++++ client/src/store/reducers.js | 7 + client/src/store/sagas/index.js | 8 + 24 files changed, 871 insertions(+), 148 deletions(-) create mode 100644 client/src/App.test.js create mode 100644 client/src/api/api-paths.js create mode 100644 client/src/api/index.js create mode 100644 client/src/components/Button.js create mode 100644 client/src/config/constants.js create mode 100644 client/src/config/theme.js create mode 100644 client/src/pages/Candilib.js create mode 100644 client/src/pages/Home.js create mode 100644 client/src/pages/NoMatch.js delete mode 100644 client/src/reducers.js delete mode 100644 client/src/routes.js create mode 100644 client/src/serviceWorker.js delete mode 100644 client/src/store.js create mode 100644 client/src/store/Auth/Auth.actions.js create mode 100644 client/src/store/Auth/Auth.reducer.js create mode 100644 client/src/store/Auth/Auth.saga.js create mode 100644 client/src/store/index.js create mode 100644 client/src/store/reducers.js create mode 100644 client/src/store/sagas/index.js diff --git a/client/src/App.js b/client/src/App.js index 9274f13..d8fc8c7 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -1,27 +1,24 @@ -/** - * Root Component - */ +// @flow import React from 'react'; -import PropTypes from 'prop-types'; import { Provider } from 'react-redux'; -import { Router, browserHistory } from 'react-router'; +import { BrowserRouter as Router } from 'react-router-dom'; +import MuiThemeProvider from '@material-ui/core/styles/MuiThemeProvider'; +import 'moment/locale/fr'; -// Import Routes -import routes from './routes'; +import store from './store'; +import theme from './theme'; +import Candilib from './pages/Candilib'; -// Base stylesheet -require('./main.css'); +const basename = process.env.NODE_ENV === 'development' ? '' : '/candilib' -export default function MainApp({ store }) { - return ( - - - {routes} +const App = () => ( + + + + - - ); -} + + +); -MainApp.propTypes = { - store: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types -}; +export default App; diff --git a/client/src/App.test.js b/client/src/App.test.js new file mode 100644 index 0000000..a754b20 --- /dev/null +++ b/client/src/App.test.js @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); +}); diff --git a/client/src/api/api-paths.js b/client/src/api/api-paths.js new file mode 100644 index 0000000..2d2eb61 --- /dev/null +++ b/client/src/api/api-paths.js @@ -0,0 +1,15 @@ +const apiPrefix = `${process.env.PUBLIC_PATH || ''}/api` + +export default { + login: `${apiPrefix}/users/login`, + sendMagicLink: `${apiPrefix}/candidats/login`, + verifyToken: `${apiPrefix}/auth/verify-token`, + creneaux: `${apiPrefix}/auth/creneaux`, + signup: `${apiPrefix}/candidats/signup`, + admin: { + candidats: `${apiPrefix}/auth/candidats`, + uploadCandidatsJson: `${apiPrefix}/admin/candidats/upload/json`, + uploadCandidatsCsv: `${apiPrefix}/admin/candidats/upload/csv`, + exportCsv: `${apiPrefix}/admin/candidats/export`, + } +} diff --git a/client/src/api/index.js b/client/src/api/index.js new file mode 100644 index 0000000..17a919f --- /dev/null +++ b/client/src/api/index.js @@ -0,0 +1,152 @@ +import 'whatwg-fetch'; + +import store from '../store'; +import { resetToken } from '../store/Auth/Auth.actions'; +import apiPaths from './api-paths'; +import { ADMIN_STORAGE_TOKEN_KEY, STORAGE_TOKEN_KEY } from '../config/constants'; + +const checkStatus = async (response) => { + if (response.status === 401) { + store.dispatch(resetToken()) + throw new Error('unauthorized') + } + return response; +} + +const checkValidJson = async (response) => { + let data; + try { + data = await response.json() + } catch (e) { + throw new Error('invalid_json') + } + if (response.ok) { + return data; + } + + throw new Error(data.message || 'Une erreur inattendue est survenue. Veuillez réessayer plus tard.'); +} + +export const fetchClient = (url, options) => fetch(url, options).then(checkStatus) +export const jsonClient = (url, options) => fetchClient(url, options).then(checkValidJson) + +const apiClient = { + post: (url, options) => ( + jsonClient(url, { ...options, method: 'POST'}) + ), + get: (url, options) => ( + jsonClient(url, { ...options, method: 'GET'}) + ), + getRaw: (url, options) => ( + fetchClient(url, { ...options, method: 'GET'}) + ), + put: (url, options) => ( + jsonClient(url, { ...options, method: 'PUT'}) + ), + delete: (url, options) => ( + jsonClient(url, { ...options, method: 'DELETE'}) + ), +} + +const getAdminHeadersForJson = () => { + const token = localStorage.getItem(ADMIN_STORAGE_TOKEN_KEY) + return { + 'Content-Type': 'application/json', + 'x-access-token': token, + } +}; + +const getAdminHeaders = () => { + const token = localStorage.getItem(ADMIN_STORAGE_TOKEN_KEY) + return { + 'x-access-token': token, + } +}; + +const getCandidatHeaders = () => { + const token = localStorage.getItem(STORAGE_TOKEN_KEY) + return { + 'Content-Type': 'application/json', + 'x-access-token': token, + } +}; + +export default { + auth: { + async sendMagicLink (email) { + const json = await apiClient.post(apiPaths.sendMagicLink, { + headers: getCandidatHeaders(), + body: JSON.stringify({ + email, + }), + }); + return json + }, + + async requestToken (email, password) { + const json = await apiClient.post(apiPaths.login, { + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + email, + password, + }), + }) + return json; + }, + + async signup (formData) { + const json = await apiClient.post(apiPaths.signup, { + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(formData), + }) + return json; + }, + + async verifyToken(token) { + const json = await apiClient.post(apiPaths.verifyToken, { + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + token, + }), + }) + return json; + } + }, + + admin: { + async getCandidats () { + const json = await apiClient.get(apiPaths.admin.candidats, { + headers: getAdminHeadersForJson(), + }); + return json; + }, + + async getCreneaux () { + const json = await apiClient.get(apiPaths.creneaux, { + headers: getAdminHeadersForJson(), + }); + return json; + }, + + async uploadCandidatsJson (body) { + const json = await apiClient.post(apiPaths.admin.uploadCandidatsJson, { + headers: getAdminHeaders(), + body, + }); + return json; + }, + + async exportCsv () { + const json = await apiClient.getRaw(apiPaths.admin.exportCsv, { + headers: getAdminHeaders(), + }); + return json; + }, + } +} diff --git a/client/src/components/Button.js b/client/src/components/Button.js new file mode 100644 index 0000000..3131500 --- /dev/null +++ b/client/src/components/Button.js @@ -0,0 +1,17 @@ +import React from 'react'; +import Button from '@material-ui/core/Button'; +import { withStyles } from '@material-ui/core/styles'; + +const styles = theme => ({ + button: { + margin: theme.spacing.unit, + }, +}); + +const CustomButton = ({ children, classes, ...props }) => ( + +); + +export default withStyles(styles)(CustomButton); diff --git a/client/src/config/constants.js b/client/src/config/constants.js new file mode 100644 index 0000000..c337c1b --- /dev/null +++ b/client/src/config/constants.js @@ -0,0 +1,2 @@ +export const ADMIN_STORAGE_TOKEN_KEY = 'admin_token'; +export const STORAGE_TOKEN_KEY = 'token'; diff --git a/client/src/config/theme.js b/client/src/config/theme.js new file mode 100644 index 0000000..c612d45 --- /dev/null +++ b/client/src/config/theme.js @@ -0,0 +1,20 @@ + +import createMuiTheme from '@material-ui/core/styles/createMuiTheme' +import blue from '@material-ui/core/colors/blue'; + + +const theme = createMuiTheme({ + typography: { + useNextVariants: true, + }, + palette: { + primary: { + light: blue[200], + main: blue[300], + dark: blue[400], + contrastText: 'rgb(0,0,0)', + }, + }, +}); + +export default theme; diff --git a/client/src/index.js b/client/src/index.js index 44da64c..f7e5741 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -1,35 +1,21 @@ -/** - * Client entry point - */ import React from 'react'; -import { render } from 'react-dom'; -import { AppContainer } from 'react-hot-loader'; -import { MuiThemeProvider } from '@material-ui/core'; - +import ReactDOM from 'react-dom'; +import 'normalize.css' +import './main.css'; import App from './App'; -import configureStore from './store'; -import theme from './theme'; - -// Initialize store -const store = configureStore(window.__INITIAL_STATE__); -const mountApp = document.getElementById('root'); +import * as serviceWorker from './serviceWorker'; -const renderApp = () => ( - render( - - - - - , - mountApp, - ) -); +const rootElement = document.getElementById('root'); -renderApp(); +const renderApp = () => { ReactDOM.render(, rootElement); }; -// For hot reloading of react components if (module.hot) { - module.hot.accept('./index', () => { - renderApp(); - }); + module.hot.accept('./App', renderApp); } + +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: http://bit.ly/CRA-PWA +serviceWorker.unregister(); + +renderApp(); diff --git a/client/src/main.css b/client/src/main.css index b8ed686..cf1a745 100644 --- a/client/src/main.css +++ b/client/src/main.css @@ -1,27 +1,29 @@ -/* - Global CSS file -*/ -*{ - margin: 0; - padding: 0; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - line-height: normal; +html, +body, +#root { + height: 100%; +} + +#root { + display: flex; + flex-direction: column; } ::-webkit-input-placeholder { color:#aaa; font-weight: 300; } + ::-moz-placeholder { color:#aaa; font-weight: 300; } + :-ms-input-placeholder { color:#aaa; font-weight: 300; } + input:-moz-placeholder { color:#aaa; font-weight: 300; @@ -40,7 +42,7 @@ input[type=number]::-webkit-outer-spin-button { } body { - background: #FFF; + background: #fff; font-family: 'Lato', sans-serif; font-size: 16px; } diff --git a/client/src/modules/App/components/Footer/Footer.js b/client/src/modules/App/components/Footer/Footer.js index 45324e5..289dc5e 100644 --- a/client/src/modules/App/components/Footer/Footer.js +++ b/client/src/modules/App/components/Footer/Footer.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Link } from 'react-router'; +import { Link } from 'react-router-dom'; import { withStyles } from '@material-ui/core'; import bg from '../../header-bk.png'; diff --git a/client/src/modules/App/components/Header/Header.js b/client/src/modules/App/components/Header/Header.js index 419c571..15dc4c1 100644 --- a/client/src/modules/App/components/Header/Header.js +++ b/client/src/modules/App/components/Header/Header.js @@ -1,5 +1,5 @@ import React from 'react'; -import { Link } from 'react-router'; +import { Link } from 'react-router-dom'; import { Toolbar, AppBar, Button } from '@material-ui/core'; // Import Style diff --git a/client/src/pages/Candilib.js b/client/src/pages/Candilib.js new file mode 100644 index 0000000..bb50ce6 --- /dev/null +++ b/client/src/pages/Candilib.js @@ -0,0 +1,113 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { Redirect, Route, Switch, withRouter } from 'react-router-dom'; +import { withStyles } from "@material-ui/core/styles"; + +import Admin from '../modules/Admin/pages/AdminPage/AdminPage'; +import AdminLogin from '../modules/Admin/pages/Login/Login'; +import CandidatLogin from '../modules/Home/components/Login/Login'; +import Candidat from '../modules/App/App'; +import Home from './Home'; +import NoMatch from './NoMatch' +import Header from '../modules/App/components/Header/Header' // TODO: Refactor this path +import Footer from '../modules/App/components/Footer/Footer' // TODO: Refactor this path +import GeneralConditions from '../modules/GeneralConditions/GeneralConditions' +import Informations from '../modules/Informations/Informations' +import { checkToken as checkTokenAC } from '../store/Auth/Auth.actions' +import { checkAdminToken as checkAdminTokenAC } from '../store/Auth/Auth.actions' + +const styles = theme => ({ + wrapper: { + padding: '1em', + flexGrow: 1, + }, +}) + +const AdminRoute = ({ component: Component, ...routeProps }) => ( + ( + routeProps.isAuthenticated ? ( + + ) : ( + + ) + )} + /> +); + +const PrivateRoute = ({ component: Component, ...routeProps }) => ( + ( + routeProps.isAuthenticated ? ( + + ) : ( + + ) + )} + /> +); + +class Candilib extends Component { + componentDidMount () { + const params = new URLSearchParams(this.props.location.search) + const token = params.get('token') + this.props.checkToken(token) + this.props.checkAdminToken() + } + + render () { + const { classes, isAdminAuthenticated, isAuthenticated, isCheckingToken } = this.props + return ( + +
+
+ + + {/* TODO: Refactor this */} + {/* TODO: Refactor this */} + + + + + + + +
+