├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .huskyrc
├── .lintstagedrc.js
├── .npmignore
├── .nvmrc
├── .prettierrc
├── .vscode
├── extensions.json
├── launch.json
└── settings.json
├── .vscodeignore
├── README.md
├── commitlint.config.js
├── config
├── aliases.js
├── env.js
├── jest
│ ├── cssTransform.js
│ └── fileTransform.js
├── modules.js
├── paths.js
├── pnpTs.js
├── webpack.config.js
└── webpackDevServer.config.js
├── jest.config.js
├── jsconfig.path.json
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
├── robots.txt
├── signin-callback.html
└── silent-renew.html
├── scripts
├── build.js
├── service-worker
│ ├── builder.js
│ └── sw-template.js
├── start.js
└── test.js
├── src
├── App.test.tsx
├── App.tsx
├── components
│ ├── Maybe
│ │ └── index.tsx
│ ├── PageTitle
│ │ └── index.tsx
│ ├── PrivateRoute
│ │ └── index.tsx
│ └── PublicRoute
│ │ └── index.tsx
├── helpers
│ ├── api.ts
│ ├── endpoints.ts
│ ├── history.ts
│ ├── localStorage.ts
│ └── notify.ts
├── hooks
│ ├── useMedia.ts
│ ├── useOffline.ts
│ └── useUser.ts
├── index.tsx
├── react-app-env.d.ts
├── screens
│ ├── Auth
│ │ ├── components
│ │ │ └── Main
│ │ │ │ ├── index.module.scss
│ │ │ │ └── index.tsx
│ │ ├── index.tsx
│ │ └── screens
│ │ │ └── Login
│ │ │ ├── index.module.scss
│ │ │ └── index.tsx
│ └── Dashboard
│ │ ├── components
│ │ └── Actor
│ │ │ └── index.tsx
│ │ ├── index.module.scss
│ │ ├── index.tsx
│ │ └── screens
│ │ └── Fame
│ │ ├── index.module.scss
│ │ └── index.tsx
├── serviceWorker.ts
├── setupTests.ts
├── state
│ ├── index.app.ts
│ └── reducer.app.ts
└── styles
│ ├── _text-colors.scss
│ ├── _vars.scss
│ ├── app.scss
│ └── index.scss
├── tsconfig.json
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react-app"],
3 | "plugins": [
4 | [
5 | "import",
6 | {
7 | "libraryName": "antd",
8 | "libraryDirectory": "es",
9 | "style": "css"
10 | }
11 | ]
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | indent_size = 4
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 |
14 | [*.json, *.yml]
15 | indent_style = space
16 | indent_size = 2
17 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | build
3 | src/registerServiceWorker.js
4 | src/**/__tests__/**
5 | src/typings
6 | scripts/service-worker/
7 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: "@typescript-eslint/parser",
4 | extends: [
5 | "react-app",
6 | "eslint:recommended",
7 | "plugin:react/recommended",
8 | "plugin:@typescript-eslint/recommended",
9 | "prettier/@typescript-eslint",
10 | "plugin:prettier/recommended",
11 | ],
12 | plugins: [ "react", "@typescript-eslint", "prettier" ],
13 | env: {
14 | commonjs: true,
15 | es6: true,
16 | node: true,
17 | jest: true,
18 | },
19 | parserOptions: {
20 | ecmaVersion: 2018,
21 | sourceType: "module",
22 | ecmaFeatures: {
23 | jsx: true,
24 | },
25 | },
26 | rules: {
27 | "prettier/prettier": 0,
28 | curly: "warn",
29 | "no-console": "off",
30 | strict: [ "error", "global" ],
31 | "no-useless-catch": "off",
32 | "@typescript-eslint/no-var-requires": "off",
33 | quotes: [ "error", "double" ],
34 | "no-tabs": 0,
35 | indent: [ 0, "tab" ],
36 | semi: [ 1, "always" ],
37 | "dot-location": [ "warn", "property" ],
38 | eqeqeq: [ "warn", "allow-null" ],
39 | "@typescript-eslint/explicit-member-accessibility": 0,
40 | "@typescript-eslint/explicit-function-return-type": 0,
41 | "@typescript-eslint/interface-name-prefix": 0,
42 | "@typescript-eslint/ban-ts-ignore": 0,
43 | "react/display-name": 0,
44 | "react/prop-types": 0,
45 | "@typescript-eslint/no-namespace": 0,
46 | "@typescript-eslint/no-explicit-any": 0,
47 | "@typescript-eslint/triple-slash-reference": 0,
48 | "@typescript-eslint/no-unused-vars": "error",
49 | },
50 | settings: {
51 | react: {
52 | pragma: "React",
53 | version: "detect",
54 | },
55 | },
56 | };
57 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/.huskyrc:
--------------------------------------------------------------------------------
1 | {
2 | "hooks": {
3 | "pre-commit": "lint-staged",
4 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.lintstagedrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "src/**/*.{js,jsx,ts,tsx}": [ "npm run test:ci", "prettier --write", "git add" ],
3 | "src/**/*.{css,scss}": [ "prettier --write", "git add" ],
4 | "*.{json,md}": [ "prettier --write", "git add" ]
5 | };
6 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | ./ignore
2 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 10.15.3
2 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "tabWidth": 4,
4 | "useTabs": true,
5 | "semi": true,
6 | "trailingComma": "all",
7 | "overrides": [
8 | {
9 | "files": [".prettierrc", ".json"],
10 | "options": { "parser": "json", "useTabs": false, "tabWidth": 2 }
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "dbaeumer.vscode-eslint",
4 | "esbenp.prettier-vscode",
5 | "editorconfig.editorconfig",
6 | "shinnn.stylelint",
7 | "dsznajder.es7-react-js-snippets",
8 | "wix.vscode-import-cost"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Debug App",
6 | "type": "chrome",
7 | "request": "launch",
8 | "url": "http://localhost:3000",
9 | "webRoot": "${workspaceFolder}/src",
10 | "sourceMapPathOverrides": {
11 | "webpack:///src/*": "${webRoot}/*"
12 | }
13 | },
14 | {
15 | "type": "node",
16 | "request": "launch",
17 | "name": "Debug Tests",
18 | "program": "${workspaceRoot}/node_modules/jest/bin/jest.js",
19 | "cwd": "${workspaceRoot}",
20 | "args": ["--i", "--config", "jest.config.js"]
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib",
3 | "eslint.validate": [
4 | "javascript",
5 | "javascriptreact",
6 | { "language": "typescript", "autoFix": true },
7 | { "language": "typescriptreact", "autoFix": true }
8 | ],
9 | "editor.formatOnSave": true,
10 | "jest.debugMode": true,
11 | "jest.pathToJest": "node_modules/.bin/jest"
12 | }
13 |
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | .vscode/**
2 | .vscode-test/**
3 | src/**
4 | **/*.map
5 | .gitignore
6 | tsconfig.json
7 | **/__mocks__/**
8 | **/tests/**
9 | **/*.ts
10 | **/tsconfig.json
11 | jsconfig.json
12 | jest.json
13 | tslint.json
14 | .travis.yml
15 | yarn.lock
16 | yarn-error.log
17 | scripts/
18 | coverage
19 | .github/**
20 | images/**
21 | !images/vscode-jest.png
22 | webpack.config.js
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | A bare minimum react-typescript-hooks-sample boilerplate.
2 |
3 | ### Technoliges:
4 | - React v^16.11.0
5 | - React hooks and context lifting data between components
6 | - Typescript
7 | - Jest
8 | - React-router
9 | - Axios
10 | - Scss
11 | - Prettier
12 | - Commitlint and lintstaged
13 | - Eslint
14 | - Editorconfig
15 | - Ramda
16 |
17 | Login username/password: `username=test` & `password=test`
18 |
19 | ## Directory Structure:
20 | ```bash
21 | ├── config
22 | ├── public
23 | ├── src
24 | │ ├── components
25 | │ ├── helpers
26 | │ ├── hooks
27 | │ ├── screens
28 | │ ├── state
29 | │ └── styles
30 | ├── build
31 | ├── README.md
32 | ├── .babelrc
33 | ├── .editorconfig
34 | ├── .eslintrc
35 | ├── .nvmrc
36 | ├── .prettier
37 | ├── commitlint.config.js
38 | ├── tsconfig.json
39 | ├── jest.config.js
40 | └── .gitignore
41 | ```
42 |
43 | #### Screens folder
44 | This folder is of great importance and its subfolders are depended on the routes structure that you have created. For namely if you have a route like this:
45 | ```js
46 | http://localhost:3000/auth/login
47 | ```
48 | So you have to create 2 subfolders into **screens** folder as below:
49 | ```bash
50 | ├── screens
51 | │ ├── Auth
52 | │ │ ├── Login
53 | │ │ | ├── index.tsx
54 | | | | index.tsx
55 | └── index.tsx
56 | ```
57 |
58 | ### Available Scripts
59 |
60 | In the project directory, you can run:
61 |
62 | ### `npm start`
63 |
64 | Runs the app in the development mode.
65 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
66 |
67 | ### `npm test`
68 |
69 | Launches the test runner in the interactive watch mode.
70 |
71 | ### `npm run build`
72 |
73 | Builds the app for production to the `build` folder.
74 | It correctly bundles React in production mode and optimizes the build for the best performance.
75 |
76 | ### `npm run eject`
77 |
78 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
79 |
80 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
81 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["@commitlint/config-conventional"],
3 | };
4 |
--------------------------------------------------------------------------------
/config/aliases.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | module.exports = {
4 | src: path.resolve(__dirname, "../src"),
5 | assets: path.resolve(__dirname, "../src/assets"),
6 | state: path.resolve(__dirname, "../src/state"),
7 | hoc: path.resolve(__dirname, "../src/hoc"),
8 | hooks: path.resolve(__dirname, "../src/hooks"),
9 | styles: path.resolve(__dirname, "../src/styles"),
10 | helpers: path.resolve(__dirname, "../src/helpers"),
11 | screens: path.resolve(__dirname, "../src/screens"),
12 | services: path.resolve(__dirname, "../src/services"),
13 | components: path.resolve(__dirname, "../src/components"),
14 | "package.json": path.resolve(__dirname, "..", "package.json"),
15 | };
16 |
--------------------------------------------------------------------------------
/config/env.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const path = require("path");
3 | const paths = require("./paths");
4 |
5 | // Make sure that including paths.js after env.js will read .env variables.
6 | delete require.cache[require.resolve("./paths")];
7 |
8 | const NODE_ENV = process.env.NODE_ENV;
9 | if (!NODE_ENV) {
10 | throw new Error("The NODE_ENV environment variable is required but was not specified.");
11 | }
12 |
13 | // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
14 | const dotenvFiles = [
15 | `${paths.dotenv}.${NODE_ENV}.local`,
16 | `${paths.dotenv}.${NODE_ENV}`,
17 | // Don't include `.env.local` for `test` environment
18 | // since normally you expect tests to produce the same
19 | // results for everyone
20 | NODE_ENV !== "test" && `${paths.dotenv}.local`,
21 | paths.dotenv,
22 | ].filter(Boolean);
23 |
24 | // Load environment variables from .env* files. Suppress warnings using silent
25 | // if this file is missing. dotenv will never modify any environment variables
26 | // that have already been set. Variable expansion is supported in .env files.
27 | // https://github.com/motdotla/dotenv
28 | // https://github.com/motdotla/dotenv-expand
29 | dotenvFiles.forEach(dotenvFile => {
30 | if (fs.existsSync(dotenvFile)) {
31 | require("dotenv-expand")(
32 | require("dotenv").config({
33 | path: dotenvFile,
34 | }),
35 | );
36 | }
37 | });
38 |
39 | // We support resolving modules according to `NODE_PATH`.
40 | // This lets you use absolute paths in imports inside large monorepos:
41 | // https://github.com/facebook/create-react-app/issues/253.
42 | // It works similar to `NODE_PATH` in Node itself:
43 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
44 | // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
45 | // Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
46 | // https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
47 | // We also resolve them to make sure all tools using them work consistently.
48 | const appDirectory = fs.realpathSync(process.cwd());
49 | process.env.NODE_PATH = (process.env.NODE_PATH || "")
50 | .split(path.delimiter)
51 | .filter(folder => folder && !path.isAbsolute(folder))
52 | .map(folder => path.resolve(appDirectory, folder))
53 | .join(path.delimiter);
54 |
55 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
56 | // injected into the application via DefinePlugin in Webpack configuration.
57 | const REACT_APP = /^REACT_APP_/i;
58 |
59 | function getClientEnvironment(publicUrl) {
60 | const raw = Object.keys(process.env)
61 | .filter(key => REACT_APP.test(key))
62 | .reduce(
63 | (env, key) => {
64 | env[key] = process.env[key];
65 | return env;
66 | },
67 | {
68 | // Useful for determining whether we’re running in production mode.
69 | // Most importantly, it switches React into the correct mode.
70 | NODE_ENV: process.env.NODE_ENV || "development",
71 | // Useful for resolving the correct path to static assets in `public`.
72 | // For example,
.
73 | // This should only be used as an escape hatch. Normally you would put
74 | // images into the `src` and `import` them in code to get their paths.
75 | PUBLIC_URL: publicUrl,
76 | },
77 | );
78 | // Stringify all values so we can feed into Webpack DefinePlugin
79 | const stringified = {
80 | "process.env": Object.keys(raw).reduce((env, key) => {
81 | env[key] = JSON.stringify(raw[key]);
82 | return env;
83 | }, {}),
84 | };
85 |
86 | return { raw, stringified };
87 | }
88 |
89 | module.exports = getClientEnvironment;
90 |
--------------------------------------------------------------------------------
/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | // This is a custom Jest transformer turning style imports into empty objects.
2 | // http://facebook.github.io/jest/docs/en/webpack.html
3 |
4 | module.exports = {
5 | process() {
6 | return "module.exports = {};";
7 | },
8 | getCacheKey() {
9 | // The output is always the same.
10 | return "cssTransform";
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const camelcase = require('camelcase');
5 |
6 | // This is a custom Jest transformer turning file imports into filenames.
7 | // http://facebook.github.io/jest/docs/en/webpack.html
8 |
9 | module.exports = {
10 | process(src, filename) {
11 | const assetFilename = JSON.stringify(path.basename(filename));
12 |
13 | if (filename.match(/\.svg$/)) {
14 | // Based on how SVGR generates a component name:
15 | // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
16 | const pascalCaseFileName = camelcase(path.parse(filename).name, {
17 | pascalCase: true,
18 | });
19 | const componentName = `Svg${pascalCaseFileName}`;
20 | return `const React = require('react');
21 | module.exports = {
22 | __esModule: true,
23 | default: ${assetFilename},
24 | ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
25 | return {
26 | $$typeof: Symbol.for('react.element'),
27 | type: 'svg',
28 | ref: ref,
29 | key: null,
30 | props: Object.assign({}, props, {
31 | children: ${assetFilename}
32 | })
33 | };
34 | }),
35 | };`;
36 | }
37 |
38 | return `module.exports = ${assetFilename};`;
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/config/modules.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const paths = require('./paths');
6 | const chalk = require('react-dev-utils/chalk');
7 | const resolve = require('resolve');
8 |
9 | /**
10 | * Get the baseUrl of a compilerOptions object.
11 | *
12 | * @param {Object} options
13 | */
14 | function getAdditionalModulePaths(options = {}) {
15 | const baseUrl = options.baseUrl;
16 |
17 | // We need to explicitly check for null and undefined (and not a falsy value) because
18 | // TypeScript treats an empty string as `.`.
19 | if (baseUrl == null) {
20 | // If there's no baseUrl set we respect NODE_PATH
21 | // Note that NODE_PATH is deprecated and will be removed
22 | // in the next major release of create-react-app.
23 |
24 | const nodePath = process.env.NODE_PATH || '';
25 | return nodePath.split(path.delimiter).filter(Boolean);
26 | }
27 |
28 | const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
29 |
30 | // We don't need to do anything if `baseUrl` is set to `node_modules`. This is
31 | // the default behavior.
32 | if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
33 | return null;
34 | }
35 |
36 | // Allow the user set the `baseUrl` to `appSrc`.
37 | if (path.relative(paths.appSrc, baseUrlResolved) === '') {
38 | return [paths.appSrc];
39 | }
40 |
41 | // Otherwise, throw an error.
42 | throw new Error(
43 | chalk.red.bold(
44 | "Your project's `baseUrl` can only be set to `src` or `node_modules`." +
45 | ' Create React App does not support other values at this time.'
46 | )
47 | );
48 | }
49 |
50 | function getModules() {
51 | // Check if TypeScript is setup
52 | const hasTsConfig = fs.existsSync(paths.appTsConfig);
53 | const hasJsConfig = fs.existsSync(paths.appJsConfig);
54 |
55 | if (hasTsConfig && hasJsConfig) {
56 | throw new Error(
57 | 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
58 | );
59 | }
60 |
61 | let config;
62 |
63 | // If there's a tsconfig.json we assume it's a
64 | // TypeScript project and set up the config
65 | // based on tsconfig.json
66 | if (hasTsConfig) {
67 | const ts = require(resolve.sync('typescript', {
68 | basedir: paths.appNodeModules,
69 | }));
70 | config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
71 | // Otherwise we'll check if there is jsconfig.json
72 | // for non TS projects.
73 | } else if (hasJsConfig) {
74 | config = require(paths.appJsConfig);
75 | }
76 |
77 | config = config || {};
78 | const options = config.compilerOptions || {};
79 |
80 | const additionalModulePaths = getAdditionalModulePaths(options);
81 |
82 | return {
83 | additionalModulePaths: additionalModulePaths,
84 | hasTsConfig,
85 | };
86 | }
87 |
88 | module.exports = getModules();
89 |
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const fs = require("fs");
3 | const url = require("url");
4 |
5 | // Make sure any symlinks in the project folder are resolved:
6 | // https://github.com/facebook/create-react-app/issues/637
7 | const appDirectory = fs.realpathSync(process.cwd());
8 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
9 |
10 | const envPublicUrl = process.env.PUBLIC_URL;
11 |
12 | function ensureSlash (inputPath, needsSlash) {
13 | const hasSlash = inputPath.endsWith("/");
14 | if (hasSlash && !needsSlash) {
15 | return inputPath.substr(0, inputPath.length - 1);
16 | } else if (!hasSlash && needsSlash) {
17 | return `${inputPath}/`;
18 | } else {
19 | return inputPath;
20 | }
21 | }
22 |
23 | const getPublicUrl = appPackageJson =>
24 | envPublicUrl || require(appPackageJson).publicUrl;
25 |
26 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
27 | // "public path" at which the app is served.
28 | // Webpack needs to know it to put the right
15 |
25 |