From bb134fad3e06b149f2c13011ec27b7c8ce4c0c37 Mon Sep 17 00:00:00 2001 From: denkondratiev Date: Thu, 16 Jul 2020 06:45:31 +0300 Subject: [PATCH 1/7] first solution --- .eslintignore | 2 + .eslintrc.js | 26 + README.md | 69 +-- package-lock.json | 816 +++++++++++++++++-------- package.json | 24 +- src/App.js | 10 - src/App.jsx | 15 + src/components/Buttons/Buttons.css | 14 + src/components/Buttons/Buttons.jsx | 60 ++ src/components/Form/Form.css | 21 + src/components/Form/Form.jsx | 143 +++++ src/components/Table/Table.css | 4 + src/components/Table/Table.jsx | 100 +++ src/components/TableItem/TableItem.css | 3 + src/components/TableItem/TableItem.jsx | 85 +++ src/helpers/helpers.js | 8 + src/helpers/shapes.js | 30 + src/index.css | 2 +- src/index.js | 9 - src/index.jsx | 15 + src/store/actions.js | 38 ++ src/store/reducers.js | 77 +++ 22 files changed, 1210 insertions(+), 361 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc.js delete mode 100644 src/App.js create mode 100644 src/App.jsx create mode 100644 src/components/Buttons/Buttons.css create mode 100644 src/components/Buttons/Buttons.jsx create mode 100644 src/components/Form/Form.css create mode 100644 src/components/Form/Form.jsx create mode 100644 src/components/Table/Table.css create mode 100644 src/components/Table/Table.jsx create mode 100644 src/components/TableItem/TableItem.css create mode 100644 src/components/TableItem/TableItem.jsx create mode 100644 src/helpers/helpers.js create mode 100644 src/helpers/shapes.js delete mode 100644 src/index.js create mode 100644 src/index.jsx create mode 100644 src/store/actions.js create mode 100644 src/store/reducers.js diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..7d5b7a9 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +/build +/node_modules diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..a085aef --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,26 @@ +module.exports = { + env: { + browser: true, + es6: true + }, + extends: [ + 'plugin:react/recommended', + 'standard' + ], + globals: { + Atomics: 'readonly', + SharedArrayBuffer: 'readonly' + }, + parserOptions: { + ecmaFeatures: { + jsx: true + }, + ecmaVersion: 2018, + sourceType: 'module' + }, + plugins: [ + 'react' + ], + rules: { + } +} diff --git a/README.md b/README.md index 54ef094..c2dec12 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,3 @@ -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). +## Dinamic spreadsheet (React + Redux ) -## Available Scripts - -In the project directory, you can run: - -### `npm start` - -Runs the app in the development mode.
-Open [http://localhost:3000](http://localhost:3000) to view it in the browser. - -The page will reload if you make edits.
-You will also see any lint errors in the console. - -### `npm test` - -Launches the test runner in the interactive watch mode.
-See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. - -### `npm run build` - -Builds the app for production to the `build` folder.
-It correctly bundles React in production mode and optimizes the build for the best performance. - -The build is minified and the filenames include the hashes.
-Your app is ready to be deployed! - -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. - -### `npm run eject` - -**Note: this is a one-way operation. Once you `eject`, you can’t go back!** - -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. - -Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. - -You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. - -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). - -### Code Splitting - -This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting - -### Analyzing the Bundle Size - -This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size - -### Making a Progressive Web App - -This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app - -### Advanced Configuration - -This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration - -### Deployment - -This section has moved here: https://facebook.github.io/create-react-app/docs/deployment - -### `npm run build` fails to minify - -This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify +[DEMO](https://denkondratiev.github.io/react_table/) diff --git a/package-lock.json b/package-lock.json index 37f346a..a4939c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,9 +13,9 @@ } }, "@babel/compat-data": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.10.4.tgz", - "integrity": "sha512-t+rjExOrSVvjQQXNp5zAIYDp00KjdvGl/TpDX5REPr0S9IAIPQMTilcfG6q8c0QFmj9lSTVySV2VTsyggvtNIw==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.10.5.tgz", + "integrity": "sha512-mPVoWNzIpYJHbWje0if7Ck36bpbtTvIxOi9+6WSK9wjGEXearAqlwBoTQvVjsAY2VIwgcs8V940geY3okzRCEw==", "requires": { "browserslist": "^4.12.0", "invariant": "^2.2.4", @@ -56,18 +56,29 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, "@babel/generator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.4.tgz", - "integrity": "sha512-toLIHUIAgcQygFZRAQcsLQV3CBuX6yOIru1kJk/qqqvcRmZrYe6WavZTSG+bB8MxhnL9YPf+pKQfuiP161q7ng==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.5.tgz", + "integrity": "sha512-3vXxr3FEW7E7lJZiWQ3bM4+v/Vyr9C+hpolQ8BGFr9Y8Ri2tFLWTixmwKBafDujO1WVah4fhZBeU1bieKdghig==", "requires": { - "@babel/types": "^7.10.4", + "@babel/types": "^7.10.5", "jsesc": "^2.5.1", - "lodash": "^4.17.13", "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } } }, "@babel/helper-annotate-as-pure": { @@ -97,13 +108,13 @@ } }, "@babel/helper-builder-react-jsx-experimental": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.10.4.tgz", - "integrity": "sha512-LyacH/kgQPgLAuaWrvvq1+E7f5bLyT8jXCh7nM67sRsy2cpIGfgWJ+FCnAKQXfY+F0tXUaN6FqLkp4JiCzdK8Q==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.10.5.tgz", + "integrity": "sha512-Buewnx6M4ttG+NLkKyt7baQn7ScC/Td+e99G914fRU8fGIUivDDgVIQeDHFa5e4CRSJQt58WpNHhsAZgtzVhsg==", "requires": { "@babel/helper-annotate-as-pure": "^7.10.4", "@babel/helper-module-imports": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/types": "^7.10.5" } }, "@babel/helper-compilation-targets": { @@ -126,12 +137,12 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.4.tgz", - "integrity": "sha512-9raUiOsXPxzzLjCXeosApJItoMnX3uyT4QdM2UldffuGApNrF8e938MwNpDCK9CPoyxrEoCgT+hObJc3mZa6lQ==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz", + "integrity": "sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==", "requires": { "@babel/helper-function-name": "^7.10.4", - "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-member-expression-to-functions": "^7.10.5", "@babel/helper-optimise-call-expression": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4", "@babel/helper-replace-supers": "^7.10.4", @@ -149,13 +160,13 @@ } }, "@babel/helper-define-map": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.4.tgz", - "integrity": "sha512-nIij0oKErfCnLUCWaCaHW0Bmtl2RO9cN7+u2QT8yqTywgALKlyUVOvHDElh+b5DwVC6YB1FOYFOTWcN/+41EDA==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", + "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", "requires": { "@babel/helper-function-name": "^7.10.4", - "@babel/types": "^7.10.4", - "lodash": "^4.17.13" + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" } }, "@babel/helper-explode-assignable-expression": { @@ -194,11 +205,11 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.4.tgz", - "integrity": "sha512-m5j85pK/KZhuSdM/8cHUABQTAslV47OjfIB9Cc7P+PvlAoBzdb79BGNfw8RhT5Mq3p+xGd0ZfAKixbrUZx0C7A==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.5.tgz", + "integrity": "sha512-HiqJpYD5+WopCXIAbQDG0zye5XYVvcO9w/DHp5GsaGkRUaamLj2bEtu6i8rnGGprAhHM3qidCMgp71HF4endhA==", "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.10.5" } }, "@babel/helper-module-imports": { @@ -210,17 +221,17 @@ } }, "@babel/helper-module-transforms": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.4.tgz", - "integrity": "sha512-Er2FQX0oa3nV7eM1o0tNCTx7izmQtwAQsIiaLRWtavAAEcskb0XJ5OjJbVrYXWOTr8om921Scabn4/tzlx7j1Q==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.5.tgz", + "integrity": "sha512-4P+CWMJ6/j1W915ITJaUkadLObmCRRSC234uctJfn/vHrsLNxsR8dwlcXv9ZhJWzl77awf+mWXSZEKt5t0OnlA==", "requires": { "@babel/helper-module-imports": "^7.10.4", "@babel/helper-replace-supers": "^7.10.4", "@babel/helper-simple-access": "^7.10.4", "@babel/helper-split-export-declaration": "^7.10.4", "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4", - "lodash": "^4.17.13" + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" } }, "@babel/helper-optimise-call-expression": { @@ -237,11 +248,11 @@ "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" }, "@babel/helper-regex": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.4.tgz", - "integrity": "sha512-inWpnHGgtg5NOF0eyHlC0/74/VkdRITY9dtTpB2PrxKKn+AkVMRiZz/Adrx+Ssg+MLDesi2zohBW6MVq6b4pOQ==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", + "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", "requires": { - "lodash": "^4.17.13" + "lodash": "^4.17.19" } }, "@babel/helper-remap-async-to-generator": { @@ -321,14 +332,14 @@ } }, "@babel/parser": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.4.tgz", - "integrity": "sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==" + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.5.tgz", + "integrity": "sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==" }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.4.tgz", - "integrity": "sha512-MJbxGSmejEFVOANAezdO39SObkURO5o/8b6fSH6D1pi9RZQt+ldppKPXfqgUWpSQ9asM6xaSaSJIaeWMDRP0Zg==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz", + "integrity": "sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==", "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/helper-remap-async-to-generator": "^7.10.4", @@ -575,12 +586,11 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.4.tgz", - "integrity": "sha512-J3b5CluMg3hPUii2onJDRiaVbPtKFPLEaV5dOPY5OeAbDi1iU/UbbFFTgwb7WnanaDy7bjU35kc26W3eM5Qa0A==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.5.tgz", + "integrity": "sha512-6Ycw3hjpQti0qssQcA6AMSFDHeNJ++R6dIMnpRqUjFeBBTmTDPa8zgF90OVfTvAo11mXZTlVUViY1g8ffrURLg==", "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "lodash": "^4.17.13" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-classes": { @@ -683,11 +693,11 @@ } }, "@babel/plugin-transform-modules-amd": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.4.tgz", - "integrity": "sha512-3Fw+H3WLUrTlzi3zMiZWp3AR4xadAEMv6XRCYnd5jAlLM61Rn+CRJaZMaNvIpcJpQ3vs1kyifYvEVPFfoSkKOA==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz", + "integrity": "sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw==", "requires": { - "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-module-transforms": "^7.10.5", "@babel/helper-plugin-utils": "^7.10.4", "babel-plugin-dynamic-import-node": "^2.3.3" } @@ -704,12 +714,12 @@ } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.4.tgz", - "integrity": "sha512-Tb28LlfxrTiOTGtZFsvkjpyjCl9IoaRI52AEU/VIwOwvDQWtbNJsAqTXzh+5R7i74e/OZHH2c2w2fsOqAfnQYQ==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz", + "integrity": "sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw==", "requires": { "@babel/helper-hoist-variables": "^7.10.4", - "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-module-transforms": "^7.10.5", "@babel/helper-plugin-utils": "^7.10.4", "babel-plugin-dynamic-import-node": "^2.3.3" } @@ -749,9 +759,9 @@ } }, "@babel/plugin-transform-parameters": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.4.tgz", - "integrity": "sha512-RurVtZ/D5nYfEg0iVERXYKEgDFeesHrHfx8RT05Sq57ucj2eOYAP6eu5fynL4Adju4I/mP/I6SO0DqNWAXjfLQ==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz", + "integrity": "sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==", "requires": { "@babel/helper-get-function-arity": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4" @@ -812,9 +822,9 @@ } }, "@babel/plugin-transform-react-jsx-source": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.10.4.tgz", - "integrity": "sha512-FTK3eQFrPv2aveerUSazFmGygqIdTtvskG50SnGnbEUnRPcGx2ylBhdFIzoVS1ty44hEgcPoCAyw5r3VDEq+Ug==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.10.5.tgz", + "integrity": "sha512-wTeqHVkN1lfPLubRiZH3o73f4rfon42HpgxUSs86Nc+8QIcm/B9s8NNVXu/gwGcOyd7yDib9ikxoDLxJP0UiDA==", "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-jsx": "^7.10.4" @@ -889,9 +899,9 @@ } }, "@babel/plugin-transform-template-literals": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.4.tgz", - "integrity": "sha512-4NErciJkAYe+xI5cqfS8pV/0ntlY5N5Ske/4ImxAVX7mk9Rxt2bwDTGv1Msc2BRJvWQcmYEC+yoMLdX22aE4VQ==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz", + "integrity": "sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw==", "requires": { "@babel/helper-annotate-as-pure": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4" @@ -906,11 +916,11 @@ } }, "@babel/plugin-transform-typescript": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.10.4.tgz", - "integrity": "sha512-3WpXIKDJl/MHoAN0fNkSr7iHdUMHZoppXjf2HJ9/ed5Xht5wNIsXllJXdityKOxeA3Z8heYRb1D3p2H5rfCdPw==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.10.5.tgz", + "integrity": "sha512-YCyYsFrrRMZ3qR7wRwtSSJovPG5vGyG4ZdcSAivGwTfoasMp3VOB/AKhohu3dFtmB4cCDcsndCSxGtrdliCsZQ==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-create-class-features-plugin": "^7.10.5", "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-typescript": "^7.10.4" } @@ -1046,17 +1056,17 @@ } }, "@babel/runtime": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.4.tgz", - "integrity": "sha512-UpTN5yUJr9b4EX2CnGNWIvER7Ab83ibv0pcvvHc4UOdrBI5jb8bj+32cCwPX6xu0mt2daFNjYhoi+X7beH0RSw==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.5.tgz", + "integrity": "sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg==", "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/runtime-corejs3": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.10.4.tgz", - "integrity": "sha512-BFlgP2SoLO9HJX9WBwN67gHWMBhDX/eDz64Jajd6mR/UAUzqrNMm99d4qHnVaKscAElZoFiPv+JpR/Siud5lXw==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.10.5.tgz", + "integrity": "sha512-RMafpmrNB5E/bwdSphLr8a8++9TosnyJp98RZzI6VOx2R2CCMpsXXXRvmI700O9oEKpXdZat6oEK68/F0zjd4A==", "requires": { "core-js-pure": "^3.0.0", "regenerator-runtime": "^0.13.4" @@ -1073,28 +1083,28 @@ } }, "@babel/traverse": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.4.tgz", - "integrity": "sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.5.tgz", + "integrity": "sha512-yc/fyv2gUjPqzTz0WHeRJH2pv7jA9kA7mBX2tXl/x5iOE81uaVPuGPtaYk7wmkx4b67mQ7NqI8rmT2pF47KYKQ==", "requires": { "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.4", + "@babel/generator": "^7.10.5", "@babel/helper-function-name": "^7.10.4", "@babel/helper-split-export-declaration": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4", + "@babel/parser": "^7.10.5", + "@babel/types": "^7.10.5", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.13" + "lodash": "^4.17.19" } }, "@babel/types": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.4.tgz", - "integrity": "sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", + "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", "requires": { "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.13", + "lodash": "^4.17.19", "to-fast-properties": "^2.0.0" } }, @@ -1250,13 +1260,6 @@ "slash": "^2.0.0", "source-map": "^0.6.0", "string-length": "^2.0.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "@jest/source-map": { @@ -1273,11 +1276,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -1323,13 +1321,6 @@ "slash": "^2.0.0", "source-map": "^0.6.1", "write-file-atomic": "2.4.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "@jest/types": { @@ -1503,6 +1494,11 @@ "@types/yargs-parser": "*" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -1512,15 +1508,6 @@ "color-convert": "^2.0.1" } }, - "aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "requires": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - } - }, "chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -1683,15 +1670,21 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==" }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" }, "@types/node": { - "version": "14.0.22", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.22.tgz", - "integrity": "sha512-emeGcJvdiZ4Z3ohbmw93E/64jRzUHAItSHt8nF7M4TGgQTiWqFVGB8KNpLGFmUHmHLvjvBgFwVlqNcq+VuGv9g==" + "version": "14.0.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.23.tgz", + "integrity": "sha512-Z4U8yDAl5TFkmYsZdFPdjeMa57NOvnaf1tljHzhouaPEp7LCj2JKkejpI1ODviIAQuW4CcQmxkQ77rnLsOOoKw==" }, "@types/parse-json": { "version": "4.0.0", @@ -1767,6 +1760,11 @@ "@types/yargs-parser": "*" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -2212,9 +2210,9 @@ "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=" }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, "ansi-styles": { "version": "3.2.1", @@ -2247,12 +2245,12 @@ } }, "aria-query": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", - "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", "requires": { - "ast-types-flow": "0.0.7", - "commander": "^2.11.0" + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" } }, "arity-n": { @@ -2322,6 +2320,17 @@ "es-abstract": "^1.17.0-next.1" } }, + "array.prototype.flatmap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.3.tgz", + "integrity": "sha512-OOEk+lkePcg+ODXIpvuU9PAryCikCJyo7GlDG1upleEpQRx6mzL9puEBkozQ5iAx20KV0l3DbyQwqciJtqe5Pg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1" + } + }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -3007,6 +3016,11 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, + "bootstrap": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.5.0.tgz", + "integrity": "sha512-Z93QoXvodoVslA+PWNdk23Hze4RBYIkpb5h8I2HY2Tu2h7A0LpAgLcyrhrSUyo2/Oxm2l1fRZPs1e5hnxnliXA==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3306,9 +3320,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001099", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001099.tgz", - "integrity": "sha512-sdS9A+sQTk7wKoeuZBN/YMAHVztUfVnjDi4/UV3sDE8xoh7YR12hKW+pIdB3oqKGwr9XaFL2ovfzt9w8eUI5CA==" + "version": "1.0.30001100", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001100.tgz", + "integrity": "sha512-0eYdp1+wFCnMlCj2oudciuQn2B9xAFq3WpgpcBIZTxk/1HNA/O2YA7rpeYhnOqsqAJq1AHUgx6i1jtafg7m2zA==" }, "capture-exit": { "version": "2.0.0", @@ -3457,13 +3471,6 @@ "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", "requires": { "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "clean-stack": { @@ -3909,13 +3916,6 @@ "source-map": "^0.6.1", "source-map-resolve": "^0.5.2", "urix": "^0.1.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "css-blank-pseudo": { @@ -4023,13 +4023,6 @@ "requires": { "mdn-data": "2.0.4", "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "css-what": { @@ -4144,11 +4137,6 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.6.tgz", "integrity": "sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -4624,9 +4612,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.3.496", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.496.tgz", - "integrity": "sha512-TXY4mwoyowwi4Lsrq9vcTUYBThyc1b2hXaTZI13p8/FRhY2CTaq5lK+DVjhYkKiTLsKt569Xes+0J5JsVXFurQ==" + "version": "1.3.498", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.498.tgz", + "integrity": "sha512-W1hGwaQEU8j9su2jeAr3aabkPuuXw+j8t73eajGAkEJWbfWiwbxBwQN/8Qmv2qCy3uCDm2rOAaZneYQM8VGC4w==" }, "elliptic": { "version": "6.5.3", @@ -4800,9 +4788,9 @@ } }, "escalade": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.1.tgz", - "integrity": "sha512-DR6NO3h9niOT+MZs7bjxlj2a1k+POu5RN8CLTPX2+i78bRi9eLe7+0zXgUHMnGXWybYcL61E9hGhPKqedy8tQA==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz", + "integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==" }, "escape-html": { "version": "1.0.3", @@ -4824,14 +4812,6 @@ "esutils": "^2.0.2", "optionator": "^0.8.1", "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true - } } }, "eslint": { @@ -4923,6 +4903,12 @@ "confusing-browser-globals": "^1.0.9" } }, + "eslint-config-standard": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz", + "integrity": "sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg==", + "dev": true + }, "eslint-import-resolver-node": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", @@ -5029,6 +5015,16 @@ } } }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + } + }, "eslint-plugin-flowtype": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.6.0.tgz", @@ -5038,28 +5034,31 @@ } }, "eslint-plugin-import": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz", - "integrity": "sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==", + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", + "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", + "dev": true, "requires": { - "array-includes": "^3.0.3", - "array.prototype.flat": "^1.2.1", + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", "contains-path": "^0.1.0", "debug": "^2.6.9", "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.1", + "eslint-import-resolver-node": "^0.3.3", + "eslint-module-utils": "^2.6.0", "has": "^1.0.3", "minimatch": "^3.0.4", - "object.values": "^1.1.0", + "object.values": "^1.1.1", "read-pkg-up": "^2.0.0", - "resolve": "^1.12.0" + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" }, "dependencies": { "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -5068,6 +5067,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, "requires": { "esutils": "^2.0.2", "isarray": "^1.0.0" @@ -5077,6 +5077,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, "requires": { "locate-path": "^2.0.0" } @@ -5085,6 +5086,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", @@ -5096,6 +5098,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" @@ -5104,12 +5107,14 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, "requires": { "p-try": "^1.0.0" } @@ -5118,6 +5123,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, "requires": { "p-limit": "^1.1.0" } @@ -5125,12 +5131,14 @@ "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, "requires": { "error-ex": "^1.2.0" } @@ -5139,6 +5147,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, "requires": { "pify": "^2.0.0" } @@ -5146,12 +5155,14 @@ "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, "requires": { "load-json-file": "^2.0.0", "normalize-package-data": "^2.3.2", @@ -5162,10 +5173,20 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, "requires": { "find-up": "^2.0.0", "read-pkg": "^2.0.0" } + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } } } }, @@ -5185,6 +5206,15 @@ "jsx-ast-utils": "^2.2.1" }, "dependencies": { + "aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "requires": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", @@ -5192,29 +5222,58 @@ } } }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + } + } + }, + "eslint-plugin-promise": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", + "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", + "dev": true + }, "eslint-plugin-react": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz", - "integrity": "sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==", + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.20.3.tgz", + "integrity": "sha512-txbo090buDeyV0ugF3YMWrzLIUqpYTsWSDZV9xLSmExE1P/Kmgg9++PD931r+KEWS66O1c9R4srLVVHmeHpoAg==", + "dev": true, "requires": { "array-includes": "^3.1.1", + "array.prototype.flatmap": "^1.2.3", "doctrine": "^2.1.0", "has": "^1.0.3", - "jsx-ast-utils": "^2.2.3", - "object.entries": "^1.1.1", + "jsx-ast-utils": "^2.4.1", + "object.entries": "^1.1.2", "object.fromentries": "^2.0.2", "object.values": "^1.1.1", "prop-types": "^15.7.2", - "resolve": "^1.15.1", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.2", - "xregexp": "^4.3.0" + "resolve": "^1.17.0", + "string.prototype.matchall": "^4.0.2" }, "dependencies": { "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, "requires": { "esutils": "^2.0.2" } @@ -5223,6 +5282,7 @@ "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, "requires": { "path-parse": "^1.0.6" } @@ -5234,6 +5294,12 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz", "integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==" }, + "eslint-plugin-standard": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz", + "integrity": "sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==", + "dev": true + }, "eslint-scope": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", @@ -6401,6 +6467,14 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, "hosted-git-info": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", @@ -6732,9 +6806,9 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inquirer": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.1.tgz", - "integrity": "sha512-/+vOpHQHhoh90Znev8BXiuw1TDQ7IDxWsQnFafUEoK5+4uN5Eoz1p+3GqOj/NtzEi9VzWKQcV9Bm+i8moxedsA==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.2.tgz", + "integrity": "sha512-DF4osh1FM6l0RJc5YWYhSDB6TawiBRlbV9Cox8MWlidU218Tb7fm3lQTULyUJDfJ0tjbzl0W4q651mrCCEM55w==", "requires": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.0", @@ -6751,6 +6825,11 @@ "through": "^2.3.6" }, "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -7162,13 +7241,6 @@ "make-dir": "^2.1.0", "rimraf": "^2.6.3", "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "istanbul-reports": { @@ -7610,11 +7682,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -9303,11 +9370,6 @@ "supports-color": "^6.1.0" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -10251,13 +10313,6 @@ "ansi-regex": "^4.0.0", "ansi-styles": "^3.2.0", "react-is": "^16.8.4" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - } } }, "process": { @@ -10525,11 +10580,6 @@ "@babel/highlight": "^7.8.3" } }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, "browserslist": { "version": "4.10.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.10.0.tgz", @@ -10708,6 +10758,18 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-redux": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.0.tgz", + "integrity": "sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA==", + "requires": { + "@babel/runtime": "^7.5.5", + "hoist-non-react-statics": "^3.3.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^16.9.0" + } + }, "react-scripts": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.4.1.tgz", @@ -10766,6 +10828,175 @@ "webpack-dev-server": "3.10.3", "webpack-manifest-plugin": "2.2.0", "workbox-webpack-plugin": "4.3.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "eslint-plugin-import": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz", + "integrity": "sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==", + "requires": { + "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.1", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.12.0" + } + }, + "eslint-plugin-react": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz", + "integrity": "sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==", + "requires": { + "array-includes": "^3.1.1", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.2.3", + "object.entries": "^1.1.1", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.15.1", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.2", + "xregexp": "^4.3.0" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + } } }, "read-pkg": { @@ -10830,6 +11061,41 @@ "strip-indent": "^3.0.0" } }, + "redux": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", + "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", + "requires": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + } + }, + "redux-devtools": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/redux-devtools/-/redux-devtools-3.5.0.tgz", + "integrity": "sha512-pGU8TZNvWxPaCCE432AGm6H6alQbAz80gQM5CzM3SjX9/oSNu/HPF17xFdPQJOXasqyih1Gv167kZDTRe7r0iQ==", + "dev": true, + "requires": { + "lodash": "^4.2.0", + "prop-types": "^15.5.7", + "redux-devtools-instrument": "^1.9.0" + } + }, + "redux-devtools-extension": { + "version": "2.13.8", + "resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz", + "integrity": "sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg==" + }, + "redux-devtools-instrument": { + "version": "1.9.6", + "resolved": "https://registry.npmjs.org/redux-devtools-instrument/-/redux-devtools-instrument-1.9.6.tgz", + "integrity": "sha512-MwvY4cLEB2tIfWWBzrUR02UM9qRG2i7daNzywRvabOSVdvAY7s9BxSwMmVRH1Y/7QWjplNtOwgT0apKhHg2Qew==", + "dev": true, + "requires": { + "lodash": "^4.2.0", + "symbol-observable": "^1.0.2" + } + }, "regenerate": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", @@ -11014,6 +11280,13 @@ "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "request-promise-core": { @@ -11125,11 +11398,6 @@ "supports-color": "^6.1.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -11665,6 +11933,11 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, @@ -11734,6 +12007,13 @@ "requires": { "faye-websocket": "^0.10.0", "uuid": "^3.0.1" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "sockjs-client": { @@ -11781,9 +12061,9 @@ "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" }, "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-resolve": { "version": "0.5.3", @@ -11804,13 +12084,6 @@ "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "source-map-url": { @@ -12070,6 +12343,11 @@ "strip-ansi": "^6.0.0" }, "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", @@ -12149,13 +12427,6 @@ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "requires": { "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - } } }, "strip-bom": { @@ -12281,6 +12552,11 @@ "util.promisify": "~1.0.0" } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -12332,13 +12608,6 @@ "commander": "^2.20.0", "source-map": "~0.6.1", "source-map-support": "~0.5.12" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "terser-webpack-plugin": { @@ -12427,11 +12696,6 @@ "find-up": "^4.0.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", @@ -12606,6 +12870,29 @@ "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz", "integrity": "sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ==" }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, "tslib": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", @@ -12881,9 +13168,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz", + "integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q==" }, "v8-compile-cache": { "version": "2.1.1", @@ -13177,11 +13464,6 @@ "randombytes": "^2.1.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, "ssri": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", @@ -13528,6 +13810,13 @@ "requires": { "ansi-colors": "^3.0.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "webpack-manifest-plugin": { @@ -13560,13 +13849,6 @@ "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } } }, "websocket-driver": { diff --git a/package.json b/package.json index ffbaee6..9f10f0c 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "homepage": "", + "homepage": "https://denkondratiev.github.io/react_table", "name": "react_table", "version": "0.1.0", "private": true, @@ -7,9 +7,14 @@ "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", "@testing-library/user-event": "^7.2.1", + "bootstrap": "^4.5.0", "react": "^16.13.1", "react-dom": "^16.13.1", - "react-scripts": "3.4.1" + "react-redux": "^7.2.0", + "react-scripts": "3.4.1", + "redux": "^4.0.5", + "redux-devtools-extension": "^2.13.8", + "uuid": "^8.2.0" }, "scripts": { "start": "react-scripts start", @@ -17,10 +22,8 @@ "test": "react-scripts test", "eject": "react-scripts eject", "predeploy": "npm run build", - "deploy": "gh-pages -d build" - }, - "eslintConfig": { - "extends": "react-app" + "deploy": "gh-pages -d build", + "lint": "eslint --ext .jsx,.js ./src/ --fix" }, "browserslist": { "production": [ @@ -35,6 +38,13 @@ ] }, "devDependencies": { - "gh-pages": "^3.1.0" + "eslint-config-standard": "^14.1.1", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-react": "^7.20.3", + "eslint-plugin-standard": "^4.0.1", + "gh-pages": "^3.1.0", + "redux-devtools": "^3.5.0" } } diff --git a/src/App.js b/src/App.js deleted file mode 100644 index d0139c2..0000000 --- a/src/App.js +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; -import './App.css'; - -function App() { - return ( -

React Table

- ); -} - -export default App; diff --git a/src/App.jsx b/src/App.jsx new file mode 100644 index 0000000..0ef4884 --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,15 @@ +import React from 'react' +import Form from './components/Form/Form' +import Table from './components/Table/Table' +import Buttons from './components/Buttons/Buttons' +import './App.css' + +const App = () => ( +
+
+ + + +) + +export default App diff --git a/src/components/Buttons/Buttons.css b/src/components/Buttons/Buttons.css new file mode 100644 index 0000000..66b3697 --- /dev/null +++ b/src/components/Buttons/Buttons.css @@ -0,0 +1,14 @@ +.buttons { + display: flex; + justify-content: center; + margin-bottom: 10px; +} + +.btn { + max-width: 120px; + margin-right: 5px; +} + +.btn:last-child { + margin-right: 0; +} diff --git a/src/components/Buttons/Buttons.jsx b/src/components/Buttons/Buttons.jsx new file mode 100644 index 0000000..047faca --- /dev/null +++ b/src/components/Buttons/Buttons.jsx @@ -0,0 +1,60 @@ +import React from 'react' +import store from '../../store/reducers' +import { connect } from 'react-redux' +import { setRows, setTable } from '../../store/actions' +import { randomGenerate } from '../../helpers/helpers' +import { ButtonsShape } from '../../helpers/shapes' +import './Buttons.css' + +const Buttons = (props) => { + const { showButtons, rows, columns, table } = props + + const deleteRow = (event) => { + if (rows > 1) { + store.dispatch(setRows(rows - 1)) + store.dispatch(setTable(table.splice(0, table.length - columns))) + } + } + + const addRow = (event) => { + store.dispatch(setRows(rows + 1)) + + const newRow = [...Array(columns).keys()].map(randomGenerate) + + store.dispatch(setTable([...table, ...newRow])) + } + + return ( + <> + {showButtons && ( +
+ + +
+ )} + + ) +} + +Buttons.propTypes = ButtonsShape.isRequired + +const mapStateToProps = state => ({ + showButtons: state.showButtons, + rows: state.rows, + columns: state.columns, + table: state.table +}) + +export default connect(mapStateToProps)(Buttons) diff --git a/src/components/Form/Form.css b/src/components/Form/Form.css new file mode 100644 index 0000000..9453bbd --- /dev/null +++ b/src/components/Form/Form.css @@ -0,0 +1,21 @@ +form { + position: relative; + display: block; + max-width: 200px; + margin: 0 auto; + + padding: 30px 0; +} + +.form-control { + margin-right: 20px; + margin-bottom: 20px; +} + +.form-control:last-child { + margin-right: 0; +} + +.error { + border: 1px solid red !important; +} diff --git a/src/components/Form/Form.jsx b/src/components/Form/Form.jsx new file mode 100644 index 0000000..fb5a3a3 --- /dev/null +++ b/src/components/Form/Form.jsx @@ -0,0 +1,143 @@ +import React, { useState } from 'react' +import { FormShape } from '../../helpers/shapes' +import { randomGenerate } from '../../helpers/helpers' +import { connect } from 'react-redux' +import store from '../../store/reducers' +import './Form.css' +import { + setColumns, + setRows, + setHighlights, + setTable, + setShowTable, + setShowButtons +} from '../../store/actions' + +const Form = (props) => { + const { rows, columns, highlights } = props + + const [showForm, setShowForm] = useState(true) + const [error, setError] = useState({ rows: false, columns: false, highlights: false }) + + const handleAddData = (event) => { + event.preventDefault() + + if (rows && columns && highlights) { + const matrix = [...Array(columns * rows).keys()].map(randomGenerate) + + store.dispatch(setTable(matrix)) + store.dispatch(setShowTable(true)) + store.dispatch(setShowButtons(true)) + + setShowForm(false) + } + + const errorObj = { + rows: null, + columns: null, + highlight: null + } + + if (!rows) { + errorObj.rows = true + } + + if (!columns) { + errorObj.columns = true + } + + if (!highlights) { + errorObj.highlights = true + } + + setError({ + rows: errorObj.rows, + columns: errorObj.columns, + highlights: errorObj.highlights + }) + } + + const setColumnsHandler = ({ name, value }) => { + setError({ columns: false }) + store.dispatch(setColumns(value.replace(/[^1-9]/, ''))) + } + const setRowsHandler = ({ name, value }) => { + setError({ rows: false }) + store.dispatch(setRows(value.replace(/[^1-9]/, ''))) + } + const setHighlightsHandler = ({ name, value }) => { + setError({ highlights: false }) + store.dispatch(setHighlights(value.replace(/[^1-9]/, ''))) + } + + return ( + showForm && ( + handleAddData(event)}> + { + error.rows && ( +
+ Please add rows value +
+ ) + } + setRowsHandler(event.target)} + value={rows} + /> + { + error.columns && ( +
+ Please add columns value +
+ ) + } + setColumnsHandler(event.target)} + value={columns} + /> + { + error.highlights && ( +
+ Please add highlight value +
+ ) + } + setHighlightsHandler(event.target)} + value={highlights} + /> + + + ) + ) +} + +Form.propTypes = FormShape.isRequired + +const mapStateToProps = state => ({ + columns: state.columns, + rows: state.rows, + highlights: state.highlights +}) + +export default connect(mapStateToProps)(Form) diff --git a/src/components/Table/Table.css b/src/components/Table/Table.css new file mode 100644 index 0000000..80da376 --- /dev/null +++ b/src/components/Table/Table.css @@ -0,0 +1,4 @@ +.table { + cursor: pointer; + text-align: right; +} diff --git a/src/components/Table/Table.jsx b/src/components/Table/Table.jsx new file mode 100644 index 0000000..fe9daa3 --- /dev/null +++ b/src/components/Table/Table.jsx @@ -0,0 +1,100 @@ +import React from 'react' +import './Table.css' +import { v4 as uuidv4 } from 'uuid' +import { connect } from 'react-redux' +import store from '../../store/reducers' +import { setTable } from '../../store/actions' +import { TableShape } from '../../helpers/shapes' +import TableItem from '../TableItem/TableItem' + +const Table = (props) => { + const { + rows, + columns, + table, + showTable + } = props + + const tableCopy = [...table] + const rowLine = [...Array(rows).keys()] + const columnLine = [...Array(columns).keys()] + const onlyAmount = table.map(item => item.amount) + + const averageColumnSum = columnLine.map((_, index) => { + let sum = 0 + for (let i = index; i < onlyAmount.length; i += columns) { + sum += onlyAmount[i] + } + return Math.floor(sum / rows) + }) + + const onMouseOverHandler = (id) => { + const lightArray = table.slice(id * columns, (id * columns) + columns) + + const newTable = table.map(item => ( + lightArray.some(lightItem => lightItem.id === item.id) + ? { ...item, showPercent: true } + : { ...item, showPercent: false } + )) + + store.dispatch(setTable(newTable)) + } + + const onMouseOutHandler = () => { + const newTable = table.map(item => ({ + ...item, + showPercent: false + })) + + store.dispatch(setTable(newTable)) + } + + return ( + <> + {showTable && ( +
+ + {rowLine.map(row => { + const oneRow = tableCopy.splice(0, columns) + const rowSum = oneRow.map(item => item.amount).reduce((prev, cur) => prev + cur, 0) + return ( + + {oneRow.map(item => ( + + ))} + + + ) + })} + {{averageColumnSum.map(item => ( + + ))} + } + +
onMouseOverHandler(event.target.id)} + onMouseOut ={onMouseOutHandler} + >Sum: {rowSum}
Average sum: {item}
+ )} + + ) +} + +Table.propTypes = TableShape.isRequired + +const mapStateToProps = (state) => ({ + columns: state.columns, + table: state.table, + rows: state.rows, + showTable: state.showTable +}) + +export default connect(mapStateToProps)(Table) diff --git a/src/components/TableItem/TableItem.css b/src/components/TableItem/TableItem.css new file mode 100644 index 0000000..57b608a --- /dev/null +++ b/src/components/TableItem/TableItem.css @@ -0,0 +1,3 @@ +.table-item--light { + background-color: #6c757d; +} diff --git a/src/components/TableItem/TableItem.jsx b/src/components/TableItem/TableItem.jsx new file mode 100644 index 0000000..90fd000 --- /dev/null +++ b/src/components/TableItem/TableItem.jsx @@ -0,0 +1,85 @@ +import React from 'react' +import { connect } from 'react-redux' +import store from '../../store/reducers' +import { setTable } from '../../store/actions' +import { TableItemShape } from '../../helpers/shapes' +import './TableItem.css' + +const TableItem = (props) => { + const { + amount, + id, + percent, + table, + highlights, + isLight, + showPercent + } = props + + const stylePercent = { + backgroundImage: `linear-gradient(90deg, rgba(220,53,69,1) ${percent}%, rgba(108,117,125,1) ${percent}%)` + } + + const incrementCell = (id) => { + const newTable = table.map(item => ( + item.id === id + ? { + ...item, + amount: item.amount + 1 + } + : item + )) + + store.dispatch(setTable(newTable)) + } + + const onMouseOverHandler = () => { + const lightArray = table.map(item => ({ + ...item, + difference: Math.abs(item.amount - amount) + })).sort((a, b) => a.difference - b.difference).slice(0, highlights + 1) + + const newTable = table.map(item => ( + lightArray.some(lightItem => lightItem.id === item.id) + ? { ...item, isLight: true } + : { ...item, isLight: false } + )) + + store.dispatch(setTable(newTable)) + } + + const onMouseOutHandler = () => { + const newTable = table.map(item => ({ + ...item, + isLight: false + })) + + store.dispatch(setTable(newTable)) + } + + return ( + incrementCell(event.target.id)} + onMouseOver={onMouseOverHandler} + onMouseOut={onMouseOutHandler} + style={showPercent ? stylePercent : {}} + > + { + showPercent + ? `${percent}%` + : amount + } + + ) +} + +TableItem.propTypes = TableItemShape.isRequired + +const mapStateToProps = state => ({ + table: state.table, + highlights: state.highlights +}) + +export default connect(mapStateToProps)(TableItem) diff --git a/src/helpers/helpers.js b/src/helpers/helpers.js new file mode 100644 index 0000000..892792e --- /dev/null +++ b/src/helpers/helpers.js @@ -0,0 +1,8 @@ +import { v4 as uuidv4 } from 'uuid' + +export const randomGenerate = item => ({ + amount: Math.floor(Math.random() * 999), + id: uuidv4(), + isLight: false, + showPercent: false +}) diff --git a/src/helpers/shapes.js b/src/helpers/shapes.js new file mode 100644 index 0000000..c8da562 --- /dev/null +++ b/src/helpers/shapes.js @@ -0,0 +1,30 @@ +import PropTypes from 'prop-types' + +export const TableShape = PropTypes.shape({ + rows: PropTypes.number, + columns: PropTypes.number, + table: PropTypes.array, + showTable: PropTypes.bool +}) + +export const FormShape = PropTypes.shape({ + rows: PropTypes.number, + columns: PropTypes.number, + highlights: PropTypes.number +}) + +export const TableItemShape = PropTypes.shape({ + amount: PropTypes.number, + id: PropTypes.number, + percent: PropTypes.number, + table: PropTypes.array, + highlights: PropTypes.number, + isLight: PropTypes.bool +}) + +export const ButtonsShape = PropTypes.shape({ + showButtons: PropTypes.bool, + rows: PropTypes.number, + columns: PropTypes.number, + table: PropTypes.array +}) diff --git a/src/index.css b/src/index.css index 293d3b1..2b1b240 100644 --- a/src/index.css +++ b/src/index.css @@ -1,3 +1,3 @@ body { - margin: 0; + margin: 10px; } diff --git a/src/index.js b/src/index.js deleted file mode 100644 index bd0ed77..0000000 --- a/src/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import './index.css'; -import App from './App'; - -ReactDOM.render( - , - document.getElementById('root') -); diff --git a/src/index.jsx b/src/index.jsx new file mode 100644 index 0000000..af363c1 --- /dev/null +++ b/src/index.jsx @@ -0,0 +1,15 @@ +import React from 'react' +import ReactDOM from 'react-dom' +import { Provider } from 'react-redux' +import store from './store/reducers' +import App from './App' + +import 'bootstrap/dist/css/bootstrap.css' +import './index.css' + +ReactDOM.render( + + + , + document.getElementById('root') +) diff --git a/src/store/actions.js b/src/store/actions.js new file mode 100644 index 0000000..87b8661 --- /dev/null +++ b/src/store/actions.js @@ -0,0 +1,38 @@ +export const ACTION_TYPES = { + SET_COLUMNS: 'SET::COLUMNS', + SET_ROWS: 'SET::ROWS', + SET_TABLE: 'SET::TABLE', + SET_HIGHLIGHT: 'SET::HIGHLIGHT', + SET_SHOW_TABLE: 'SET::SHOW::TABLE', + SET_SHOW_BUTTONS: 'SET::SHOW::BUTTONS' +} + +export const setColumns = (param) => ({ + payload: param === '' ? '' : Number(param), + type: ACTION_TYPES.SET_COLUMNS +}) + +export const setRows = (param) => ({ + payload: param === '' ? '' : Number(param), + type: ACTION_TYPES.SET_ROWS +}) + +export const setHighlights = (param) => ({ + payload: param === '' ? '' : Number(param), + type: ACTION_TYPES.SET_HIGHLIGHT +}) + +export const setTable = (param) => ({ + payload: param, + type: ACTION_TYPES.SET_TABLE +}) + +export const setShowTable = (param) => ({ + payload: param, + type: ACTION_TYPES.SET_SHOW_TABLE +}) + +export const setShowButtons = (param) => ({ + payload: param, + type: ACTION_TYPES.SET_SHOW_BUTTONS +}) diff --git a/src/store/reducers.js b/src/store/reducers.js new file mode 100644 index 0000000..1571b22 --- /dev/null +++ b/src/store/reducers.js @@ -0,0 +1,77 @@ +import { createStore } from 'redux' +import { ACTION_TYPES } from './actions' + +function rootReducer (state, action) { + const { + SET_COLUMNS, + SET_ROWS, + SET_HIGHLIGHT, + SET_TABLE, + SET_SHOW_TABLE, + SET_SHOW_BUTTONS + } = ACTION_TYPES + + switch (action.type) { + case SET_TABLE: { + return { + ...state, + table: action.payload + } + } + + case SET_COLUMNS: { + return { + ...state, + columns: action.payload + } + } + + case SET_ROWS: { + return { + ...state, + rows: action.payload + } + } + + case SET_HIGHLIGHT: { + return { + ...state, + highlights: action.payload + } + } + + case SET_SHOW_TABLE: { + return { + ...state, + showTable: action.payload + } + } + + case SET_SHOW_BUTTONS: { + return { + ...state, + showButtons: action.payload + } + } + + default: + return state + } +} + +const initialState = { + rows: '', + columns: '', + highlights: '', + table: [], + showTable: false, + showButtons: false +} + +const store = createStore( + rootReducer, + initialState, + window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() +) + +export default store From d2ef236d31b300a328b8fce42b7a3a33f3962fa9 Mon Sep 17 00:00:00 2001 From: Denys Kondratiev <37929214+denkondratiev@users.noreply.github.com> Date: Thu, 16 Jul 2020 17:57:00 +0300 Subject: [PATCH 2/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c2dec12..341d90d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -## Dinamic spreadsheet (React + Redux ) +## Dynamic spreadsheet (React + Redux ) [DEMO](https://denkondratiev.github.io/react_table/) From ca97fb0a9fecd6c4f31fd4b771f6c923dba74b13 Mon Sep 17 00:00:00 2001 From: denkondratiev Date: Wed, 22 Jul 2020 18:25:24 +0300 Subject: [PATCH 3/7] start refactoring --- .../AverageColumns/AverageColumns.jsx | 40 +++++++++++ src/components/ButtonAdd/ButtonAdd.jsx | 18 +++++ src/components/ButtonDelete/ButtonDelete.jsx | 18 +++++ src/components/Buttons/Buttons.jsx | 18 ++--- src/components/Form/Form.jsx | 66 ++++++++++++++++--- src/components/RowSumItem/RowSumItem.jsx | 50 ++++++++++++++ src/components/Table/Table.jsx | 50 ++------------ src/helpers/shapes.js | 21 ++++++ 8 files changed, 214 insertions(+), 67 deletions(-) create mode 100644 src/components/AverageColumns/AverageColumns.jsx create mode 100644 src/components/ButtonAdd/ButtonAdd.jsx create mode 100644 src/components/ButtonDelete/ButtonDelete.jsx create mode 100644 src/components/RowSumItem/RowSumItem.jsx diff --git a/src/components/AverageColumns/AverageColumns.jsx b/src/components/AverageColumns/AverageColumns.jsx new file mode 100644 index 0000000..c279354 --- /dev/null +++ b/src/components/AverageColumns/AverageColumns.jsx @@ -0,0 +1,40 @@ +import React from 'react' +import { v4 as uuidv4 } from 'uuid' +import { AverageColumnsShape } from '../../helpers/shapes' +import { connect } from 'react-redux' + +const AverageColumns = (props) => { + // eslint-disable-next-line react/prop-types + const { columns, rows, table } = props + + const columnLine = [...Array(columns).keys()] + // eslint-disable-next-line react/prop-types + const onlyAmount = table.map(item => item.amount) + + const averageColumnSum = columnLine.map((_, index) => { + let sum = 0 + for (let i = index; i < onlyAmount.length; i += columns) { + sum += onlyAmount[i] + } + return Math.floor(sum / rows) + }) + + return ( + <> + {{averageColumnSum.map(item => ( + Average sum: {item} + ))} + } + + ) +} + +AverageColumnsShape.propTypes = AverageColumnsShape.isRequired + +const mapStateToProps = (state) => ({ + columns: state.columns, + rows: state.rows, + table: state.table +}) + +export default connect(mapStateToProps)(AverageColumns) diff --git a/src/components/ButtonAdd/ButtonAdd.jsx b/src/components/ButtonAdd/ButtonAdd.jsx new file mode 100644 index 0000000..e58314b --- /dev/null +++ b/src/components/ButtonAdd/ButtonAdd.jsx @@ -0,0 +1,18 @@ +import React from 'react' +import { ButtonAddShape } from '../../helpers/shapes' + +export const ButtonAdd = (props) => { + const { addRow } = props + + return ( + + ) +} + +ButtonAdd.propTypes = ButtonAddShape.isRequired diff --git a/src/components/ButtonDelete/ButtonDelete.jsx b/src/components/ButtonDelete/ButtonDelete.jsx new file mode 100644 index 0000000..d8c3bca --- /dev/null +++ b/src/components/ButtonDelete/ButtonDelete.jsx @@ -0,0 +1,18 @@ +import React from 'react' +import { ButtonDeleteShape } from '../../helpers/shapes' + +export const ButtonDelete = (props) => { + const { deleteRow } = props + + return ( + + ) +} + +ButtonDelete.propTypes = ButtonDeleteShape.isRequired diff --git a/src/components/Buttons/Buttons.jsx b/src/components/Buttons/Buttons.jsx index 047faca..d379be6 100644 --- a/src/components/Buttons/Buttons.jsx +++ b/src/components/Buttons/Buttons.jsx @@ -4,6 +4,8 @@ import { connect } from 'react-redux' import { setRows, setTable } from '../../store/actions' import { randomGenerate } from '../../helpers/helpers' import { ButtonsShape } from '../../helpers/shapes' +import { ButtonDelete } from '../ButtonDelete/ButtonDelete' +import { ButtonAdd } from '../ButtonAdd/ButtonAdd' import './Buttons.css' const Buttons = (props) => { @@ -28,20 +30,8 @@ const Buttons = (props) => { <> {showButtons && (
- - + +
)} diff --git a/src/components/Form/Form.jsx b/src/components/Form/Form.jsx index fb5a3a3..4b80246 100644 --- a/src/components/Form/Form.jsx +++ b/src/components/Form/Form.jsx @@ -19,11 +19,31 @@ const Form = (props) => { const [showForm, setShowForm] = useState(true) const [error, setError] = useState({ rows: false, columns: false, highlights: false }) + // const isInteger = (value) => Math.abs(Math.floor(Number(value))) + // const number = parseInt(numString, 10); + // replace(/^[0|\D]*/,''); + + // const checkValue = (value) => ( + // parseInt(value.trim().replace(/[^0-9]/, ''), 10) + // ) + + // var matrix = new Array(rows).fill(0).map(row => new Array(columns).fill(0)); + const handleAddData = (event) => { event.preventDefault() + console.log(typeof rows, typeof columns, typeof highlights) if (rows && columns && highlights) { - const matrix = [...Array(columns * rows).keys()].map(randomGenerate) + const matrix = [] + for (let i = 0; i < rows; ++i) { + matrix[i] = [] + for (let j = 0; j < columns; ++j) { + matrix[i][j] = randomGenerate() + } + } + + console.log(matrix) + // const matrix = [...Array(columns * rows).keys()].map(randomGenerate) store.dispatch(setTable(matrix)) store.dispatch(setShowTable(true)) @@ -58,16 +78,42 @@ const Form = (props) => { } const setColumnsHandler = ({ name, value }) => { + console.log(name, value) + + if (value === '') { + store.dispatch(setColumns('')) + + return false + } + setError({ columns: false }) - store.dispatch(setColumns(value.replace(/[^1-9]/, ''))) + store.dispatch(setColumns(value.replace(/[^0-9]/, ''))) } + const setRowsHandler = ({ name, value }) => { + console.log(name, value) + + if (value === '') { + store.dispatch(setRows('')) + + return false + } + setError({ rows: false }) - store.dispatch(setRows(value.replace(/[^1-9]/, ''))) + store.dispatch(setRows(value.replace(/[^0-9]/, ''))) } + const setHighlightsHandler = ({ name, value }) => { + console.log(name, value) + + if (value === '') { + store.dispatch(setHighlights('')) + + return false + } + setError({ highlights: false }) - store.dispatch(setHighlights(value.replace(/[^1-9]/, ''))) + store.dispatch(setHighlights(value.replace(/[^0-9]/, ''))) } return ( @@ -76,7 +122,7 @@ const Form = (props) => { { error.rows && (
- Please add rows value + Please add correct rows value
) } @@ -85,14 +131,14 @@ const Form = (props) => { name="rows" className={`form-control ${error.rows && 'error'}`} placeholder="Rows..." - maxLength="2" + // maxLength="2" onChange={(event) => setRowsHandler(event.target)} value={rows} /> { error.columns && (
- Please add columns value + Please add correct columns value
) } @@ -101,14 +147,14 @@ const Form = (props) => { name="columns" className={`form-control ${error.columns && 'error'}`} placeholder="Columns..." - maxLength="2" + // maxLength="2" onChange={(event) => setColumnsHandler(event.target)} value={columns} /> { error.highlights && (
- Please add highlight value + Please add correct highlight value
) } @@ -117,7 +163,7 @@ const Form = (props) => { name="highlights" className={`form-control ${error.highlights && 'error'}`} placeholder="Highlight cells..." - maxLength="2" + // maxLength="2" onChange={(event) => setHighlightsHandler(event.target)} value={highlights} /> diff --git a/src/components/RowSumItem/RowSumItem.jsx b/src/components/RowSumItem/RowSumItem.jsx new file mode 100644 index 0000000..feec9a4 --- /dev/null +++ b/src/components/RowSumItem/RowSumItem.jsx @@ -0,0 +1,50 @@ +import React from 'react' +import { connect } from 'react-redux' +import store from '../../store/reducers' +import { setTable } from '../../store/actions' +import { RowSumItemShape } from '../../helpers/shapes' + +const RowSumItem = (props) => { + const { table, cellValue, columns, rowSum } = props + + const onMouseOverHandler = (id) => { + const lightArray = table.slice(id * columns, (id * columns) + columns) + + const newTable = table.map(item => ( + lightArray.some(lightItem => lightItem.id === item.id) + ? { ...item, showPercent: true } + : { ...item, showPercent: false } + )) + + store.dispatch(setTable(newTable)) + } + + const onMouseOutHandler = () => { + const newTable = table.map(item => ({ + ...item, + showPercent: false + })) + + store.dispatch(setTable(newTable)) + } + + return ( + onMouseOverHandler(event.target.id)} + onMouseOut ={onMouseOutHandler} + > + Sum: {rowSum} + + + ) +} + +RowSumItem.propTypes = RowSumItemShape.isRequired + +const mapStateToProps = (state) => ({ + table: state.table, + columns: state.columns +}) + +export default connect(mapStateToProps)(RowSumItem) diff --git a/src/components/Table/Table.jsx b/src/components/Table/Table.jsx index fe9daa3..57acfd6 100644 --- a/src/components/Table/Table.jsx +++ b/src/components/Table/Table.jsx @@ -1,11 +1,10 @@ import React from 'react' import './Table.css' -import { v4 as uuidv4 } from 'uuid' import { connect } from 'react-redux' -import store from '../../store/reducers' -import { setTable } from '../../store/actions' import { TableShape } from '../../helpers/shapes' import TableItem from '../TableItem/TableItem' +import AverageColumns from '../AverageColumns/AverageColumns' +import RowSumItem from '../RowSumItem/RowSumItem' const Table = (props) => { const { @@ -17,37 +16,6 @@ const Table = (props) => { const tableCopy = [...table] const rowLine = [...Array(rows).keys()] - const columnLine = [...Array(columns).keys()] - const onlyAmount = table.map(item => item.amount) - - const averageColumnSum = columnLine.map((_, index) => { - let sum = 0 - for (let i = index; i < onlyAmount.length; i += columns) { - sum += onlyAmount[i] - } - return Math.floor(sum / rows) - }) - - const onMouseOverHandler = (id) => { - const lightArray = table.slice(id * columns, (id * columns) + columns) - - const newTable = table.map(item => ( - lightArray.some(lightItem => lightItem.id === item.id) - ? { ...item, showPercent: true } - : { ...item, showPercent: false } - )) - - store.dispatch(setTable(newTable)) - } - - const onMouseOutHandler = () => { - const newTable = table.map(item => ({ - ...item, - showPercent: false - })) - - store.dispatch(setTable(newTable)) - } return ( <> @@ -69,18 +37,14 @@ const Table = (props) => { showPercent={item.showPercent} /> ))} - onMouseOverHandler(event.target.id)} - onMouseOut ={onMouseOutHandler} - >Sum: {rowSum} + ) })} - {{averageColumnSum.map(item => ( - Average sum: {item} - ))} - } + )} diff --git a/src/helpers/shapes.js b/src/helpers/shapes.js index c8da562..12cf94c 100644 --- a/src/helpers/shapes.js +++ b/src/helpers/shapes.js @@ -13,6 +13,19 @@ export const FormShape = PropTypes.shape({ highlights: PropTypes.number }) +export const AverageColumnsShape = PropTypes.shape({ + rows: PropTypes.number, + columns: PropTypes.number, + table: PropTypes.number +}) + +export const RowSumItemShape = PropTypes.shape({ + table: PropTypes.number, + columns: PropTypes.number, + cellValue: PropTypes.number, + rowSum: PropTypes.number +}) + export const TableItemShape = PropTypes.shape({ amount: PropTypes.number, id: PropTypes.number, @@ -28,3 +41,11 @@ export const ButtonsShape = PropTypes.shape({ columns: PropTypes.number, table: PropTypes.array }) + +export const ButtonDeleteShape = PropTypes.shape({ + deleteRow: PropTypes.func +}) + +export const ButtonAddShape = PropTypes.shape({ + addRow: PropTypes.func +}) From d71dddcbe3d0da6e31aecb6f1f04b777e3edf7a6 Mon Sep 17 00:00:00 2001 From: denkondratiev Date: Fri, 24 Jul 2020 20:31:33 +0300 Subject: [PATCH 4/7] arr in arr matrix --- .../AverageColumns/AverageColumns.jsx | 24 ++- src/components/Form/Form.jsx | 147 +++++++----------- src/components/RowSumItem/RowSumItem.jsx | 50 ------ src/components/Table/Table.jsx | 40 ++--- .../TableItem.css => TableCell/TableCell.css} | 2 +- src/components/TableCell/TableCell.jsx | 91 +++++++++++ src/components/TableItem/TableItem.jsx | 85 ---------- src/components/TableRow/TableRow.jsx | 42 +++++ src/components/TableSumCell/TableSumCell.jsx | 52 +++++++ src/helpers/helpers.js | 14 +- src/helpers/shapes.js | 33 ++-- src/store/actions.js | 24 ++- src/store/reducers.js | 57 ++++++- 13 files changed, 369 insertions(+), 292 deletions(-) delete mode 100644 src/components/RowSumItem/RowSumItem.jsx rename src/components/{TableItem/TableItem.css => TableCell/TableCell.css} (59%) create mode 100644 src/components/TableCell/TableCell.jsx delete mode 100644 src/components/TableItem/TableItem.jsx create mode 100644 src/components/TableRow/TableRow.jsx create mode 100644 src/components/TableSumCell/TableSumCell.jsx diff --git a/src/components/AverageColumns/AverageColumns.jsx b/src/components/AverageColumns/AverageColumns.jsx index c279354..ec3f3f8 100644 --- a/src/components/AverageColumns/AverageColumns.jsx +++ b/src/components/AverageColumns/AverageColumns.jsx @@ -4,20 +4,18 @@ import { AverageColumnsShape } from '../../helpers/shapes' import { connect } from 'react-redux' const AverageColumns = (props) => { - // eslint-disable-next-line react/prop-types - const { columns, rows, table } = props + const { table } = props - const columnLine = [...Array(columns).keys()] - // eslint-disable-next-line react/prop-types - const onlyAmount = table.map(item => item.amount) + const onlyAmount = table.map(row => row.map(cell => cell.amount)) - const averageColumnSum = columnLine.map((_, index) => { - let sum = 0 - for (let i = index; i < onlyAmount.length; i += columns) { - sum += onlyAmount[i] + const res = [] + for (let i = 0; i < onlyAmount.length; i++) { + for (let j = 0; j < onlyAmount[i].length; j++) { + res[j] = (res[j] || 0) + Math.floor(onlyAmount[i][j] / onlyAmount.length) } - return Math.floor(sum / rows) - }) + } + + const averageColumnSum = res return ( <> @@ -29,11 +27,9 @@ const AverageColumns = (props) => { ) } -AverageColumnsShape.propTypes = AverageColumnsShape.isRequired +AverageColumns.propTypes = AverageColumnsShape.isRequired const mapStateToProps = (state) => ({ - columns: state.columns, - rows: state.rows, table: state.table }) diff --git a/src/components/Form/Form.jsx b/src/components/Form/Form.jsx index 4b80246..c0eb3da 100644 --- a/src/components/Form/Form.jsx +++ b/src/components/Form/Form.jsx @@ -1,6 +1,6 @@ import React, { useState } from 'react' import { FormShape } from '../../helpers/shapes' -import { randomGenerate } from '../../helpers/helpers' +import { generateMatrix } from '../../helpers/helpers' import { connect } from 'react-redux' import store from '../../store/reducers' import './Form.css' @@ -16,40 +16,24 @@ import { const Form = (props) => { const { rows, columns, highlights } = props - const [showForm, setShowForm] = useState(true) - const [error, setError] = useState({ rows: false, columns: false, highlights: false }) + const [isGenerate, setIsGenerate] = useState(false) + const [error, setError] = useState({ + rows: false, + columns: false, + highlights: false + }) - // const isInteger = (value) => Math.abs(Math.floor(Number(value))) - // const number = parseInt(numString, 10); - // replace(/^[0|\D]*/,''); - - // const checkValue = (value) => ( - // parseInt(value.trim().replace(/[^0-9]/, ''), 10) - // ) - - // var matrix = new Array(rows).fill(0).map(row => new Array(columns).fill(0)); - - const handleAddData = (event) => { + const handleGenerateTable = (event) => { event.preventDefault() - console.log(typeof rows, typeof columns, typeof highlights) if (rows && columns && highlights) { - const matrix = [] - for (let i = 0; i < rows; ++i) { - matrix[i] = [] - for (let j = 0; j < columns; ++j) { - matrix[i][j] = randomGenerate() - } - } - - console.log(matrix) - // const matrix = [...Array(columns * rows).keys()].map(randomGenerate) + const matrix = generateMatrix(rows, columns) store.dispatch(setTable(matrix)) store.dispatch(setShowTable(true)) store.dispatch(setShowButtons(true)) - setShowForm(false) + setIsGenerate(true) } const errorObj = { @@ -78,8 +62,6 @@ const Form = (props) => { } const setColumnsHandler = ({ name, value }) => { - console.log(name, value) - if (value === '') { store.dispatch(setColumns('')) @@ -91,8 +73,6 @@ const Form = (props) => { } const setRowsHandler = ({ name, value }) => { - console.log(name, value) - if (value === '') { store.dispatch(setRows('')) @@ -104,8 +84,6 @@ const Form = (props) => { } const setHighlightsHandler = ({ name, value }) => { - console.log(name, value) - if (value === '') { store.dispatch(setHighlights('')) @@ -117,64 +95,59 @@ const Form = (props) => { } return ( - showForm && ( -
handleAddData(event)}> - { - error.rows && ( -
+ handleGenerateTable(event)}> + { + error.rows && ( +
Please add correct rows value -
- ) - } - setRowsHandler(event.target)} - value={rows} - /> - { - error.columns && ( -
+
+ ) + } + setRowsHandler(event.target)} + value={isGenerate ? '' : rows} + /> + { + error.columns && ( +
Please add correct columns value -
- ) - } - setColumnsHandler(event.target)} - value={columns} - /> - { - error.highlights && ( -
+
+ ) + } + setColumnsHandler(event.target)} + value={isGenerate ? '' : columns} + /> + { + error.highlights && ( +
Please add correct highlight value -
- ) - } - setHighlightsHandler(event.target)} - value={highlights} - /> - - - ) +
+ ) + } + setHighlightsHandler(event.target)} + value={isGenerate ? '' : highlights} + /> + + ) } diff --git a/src/components/RowSumItem/RowSumItem.jsx b/src/components/RowSumItem/RowSumItem.jsx deleted file mode 100644 index feec9a4..0000000 --- a/src/components/RowSumItem/RowSumItem.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react' -import { connect } from 'react-redux' -import store from '../../store/reducers' -import { setTable } from '../../store/actions' -import { RowSumItemShape } from '../../helpers/shapes' - -const RowSumItem = (props) => { - const { table, cellValue, columns, rowSum } = props - - const onMouseOverHandler = (id) => { - const lightArray = table.slice(id * columns, (id * columns) + columns) - - const newTable = table.map(item => ( - lightArray.some(lightItem => lightItem.id === item.id) - ? { ...item, showPercent: true } - : { ...item, showPercent: false } - )) - - store.dispatch(setTable(newTable)) - } - - const onMouseOutHandler = () => { - const newTable = table.map(item => ({ - ...item, - showPercent: false - })) - - store.dispatch(setTable(newTable)) - } - - return ( - onMouseOverHandler(event.target.id)} - onMouseOut ={onMouseOutHandler} - > - Sum: {rowSum} - - - ) -} - -RowSumItem.propTypes = RowSumItemShape.isRequired - -const mapStateToProps = (state) => ({ - table: state.table, - columns: state.columns -}) - -export default connect(mapStateToProps)(RowSumItem) diff --git a/src/components/Table/Table.jsx b/src/components/Table/Table.jsx index 57acfd6..e0c16e9 100644 --- a/src/components/Table/Table.jsx +++ b/src/components/Table/Table.jsx @@ -1,49 +1,31 @@ import React from 'react' import './Table.css' +import { v4 as uuidv4 } from 'uuid' import { connect } from 'react-redux' import { TableShape } from '../../helpers/shapes' -import TableItem from '../TableItem/TableItem' import AverageColumns from '../AverageColumns/AverageColumns' -import RowSumItem from '../RowSumItem/RowSumItem' +import { TableRow } from '../TableRow/TableRow' const Table = (props) => { const { - rows, - columns, table, showTable } = props - const tableCopy = [...table] - const rowLine = [...Array(rows).keys()] + console.log(table) return ( <> {showTable && ( - {rowLine.map(row => { - const oneRow = tableCopy.splice(0, columns) - const rowSum = oneRow.map(item => item.amount).reduce((prev, cur) => prev + cur, 0) - return ( - - {oneRow.map(item => ( - - ))} - - - ) - })} + {table.map((row, rowIndex) => ( + + ))}
@@ -55,9 +37,7 @@ const Table = (props) => { Table.propTypes = TableShape.isRequired const mapStateToProps = (state) => ({ - columns: state.columns, table: state.table, - rows: state.rows, showTable: state.showTable }) diff --git a/src/components/TableItem/TableItem.css b/src/components/TableCell/TableCell.css similarity index 59% rename from src/components/TableItem/TableItem.css rename to src/components/TableCell/TableCell.css index 57b608a..907b27a 100644 --- a/src/components/TableItem/TableItem.css +++ b/src/components/TableCell/TableCell.css @@ -1,3 +1,3 @@ -.table-item--light { +.table-cell--light { background-color: #6c757d; } diff --git a/src/components/TableCell/TableCell.jsx b/src/components/TableCell/TableCell.jsx new file mode 100644 index 0000000..b633614 --- /dev/null +++ b/src/components/TableCell/TableCell.jsx @@ -0,0 +1,91 @@ +import React from 'react' +import './TableCell.css' +import { TableCellShape } from '../../helpers/shapes' +import { connect } from 'react-redux' +// import store from '../../store/reducers' +import { increment, setLightCells } from '../../store/actions' + +const TableCell = (props) => { + const { + // id, + // table, + amount, + percent, + isLight, + cellIndex, + rowIndex, + showPercent, + increment + // setLightCells, + // highlights + } = props + + const stylePercent = { + backgroundImage: `linear-gradient(90deg, rgba(220,53,69,1) ${percent}%, rgba(108,117,125,1) ${percent}%)` + } + + const onClickHandler = ({ id, cellIndex }) => { + increment(Number(id), cellIndex) + } + + // const onMouseOverHandler = ({ id, cellIndex }) => { + // setLightCells(Number(id), cellIndex, amount, highlights) + // } + + // const onMouseOverHandler = () => { + // const lightArray = table.map(item => ({ + // ...item, + // difference: Math.abs(item.amount - amount) + // })).sort((a, b) => a.difference - b.difference).slice(0, highlights + 1) + + // const newTable = table.map(item => ( + // lightArray.some(lightItem => lightItem.id === item.id) + // ? { ...item, isLight: true } + // : { ...item, isLight: false } + // )) + + // store.dispatch(setTable(newTable)) + // } + + // const onMouseOutHandler = () => { + // const newTable = table.map(item => ({ + // ...item, + // isLight: false + // })) + + // store.dispatch(setTable(newTable)) + // } + + return ( + onClickHandler(event.target)} + // onMouseOver={(event) => onMouseOverHandler(event.target)} + // onMouseOut={onMouseOutHandler} + > + { + showPercent + ? `${percent}%` + : amount + } + + ) +} + +TableCell.propTypes = TableCellShape.isRequired + +const mapStateToProps = (state) => ({ + table: state.table, + highlights: state.highlights +}) + +const mapDispatchToProps = (dispatch) => ({ + increment: (id, cellIndex) => dispatch(increment(id, cellIndex)), + setLightCells: (id, cellIndex, amount, highlights) => dispatch(setLightCells(id, cellIndex, amount, highlights)) +}) + +export default connect(mapStateToProps, mapDispatchToProps)(TableCell) diff --git a/src/components/TableItem/TableItem.jsx b/src/components/TableItem/TableItem.jsx deleted file mode 100644 index 90fd000..0000000 --- a/src/components/TableItem/TableItem.jsx +++ /dev/null @@ -1,85 +0,0 @@ -import React from 'react' -import { connect } from 'react-redux' -import store from '../../store/reducers' -import { setTable } from '../../store/actions' -import { TableItemShape } from '../../helpers/shapes' -import './TableItem.css' - -const TableItem = (props) => { - const { - amount, - id, - percent, - table, - highlights, - isLight, - showPercent - } = props - - const stylePercent = { - backgroundImage: `linear-gradient(90deg, rgba(220,53,69,1) ${percent}%, rgba(108,117,125,1) ${percent}%)` - } - - const incrementCell = (id) => { - const newTable = table.map(item => ( - item.id === id - ? { - ...item, - amount: item.amount + 1 - } - : item - )) - - store.dispatch(setTable(newTable)) - } - - const onMouseOverHandler = () => { - const lightArray = table.map(item => ({ - ...item, - difference: Math.abs(item.amount - amount) - })).sort((a, b) => a.difference - b.difference).slice(0, highlights + 1) - - const newTable = table.map(item => ( - lightArray.some(lightItem => lightItem.id === item.id) - ? { ...item, isLight: true } - : { ...item, isLight: false } - )) - - store.dispatch(setTable(newTable)) - } - - const onMouseOutHandler = () => { - const newTable = table.map(item => ({ - ...item, - isLight: false - })) - - store.dispatch(setTable(newTable)) - } - - return ( - incrementCell(event.target.id)} - onMouseOver={onMouseOverHandler} - onMouseOut={onMouseOutHandler} - style={showPercent ? stylePercent : {}} - > - { - showPercent - ? `${percent}%` - : amount - } - - ) -} - -TableItem.propTypes = TableItemShape.isRequired - -const mapStateToProps = state => ({ - table: state.table, - highlights: state.highlights -}) - -export default connect(mapStateToProps)(TableItem) diff --git a/src/components/TableRow/TableRow.jsx b/src/components/TableRow/TableRow.jsx new file mode 100644 index 0000000..fdf66c0 --- /dev/null +++ b/src/components/TableRow/TableRow.jsx @@ -0,0 +1,42 @@ +import React from 'react' +import { v4 as uuidv4 } from 'uuid' +import { TableRowShape } from '../../helpers/shapes' +import TableCell from '../TableCell/TableCell' +import TableSumCell from '../TableSumCell/TableSumCell' + +export const TableRow = (props) => { + const { row, rowIndex } = props + + let rowSum = null + + return ( + + {row.map((cell, cellIndex) => { + rowSum = row.map(cell => cell.amount).reduce((prev, cur) => prev + cur, 0) + return ( + + + ) + })} + + + ) +} + +TableRow.propTypes = TableRowShape.isRequired diff --git a/src/components/TableSumCell/TableSumCell.jsx b/src/components/TableSumCell/TableSumCell.jsx new file mode 100644 index 0000000..c4abaab --- /dev/null +++ b/src/components/TableSumCell/TableSumCell.jsx @@ -0,0 +1,52 @@ +import React from 'react' +import { v4 as uuidv4 } from 'uuid' +import { connect } from 'react-redux' +import store from '../../store/reducers' +import { setTable } from '../../store/actions' +import { TableSumCellShape } from '../../helpers/shapes' + +const TableSumCell = (props) => { + const { table, rowSum, rowIndex } = props + + const onMouseOverHandler = (id) => { + const lightArray = table[id].map(cell => ({ + ...cell, + showPercent: true + })) + + const tableCopy = [...table] + + tableCopy.splice(id, 1, lightArray) + + store.dispatch(setTable(tableCopy)) + } + + const onMouseOutHandler = () => { + const newTable = table.map(row => ( + row.map(cell => ( + { ...cell, showPercent: false } + )) + )) + store.dispatch(setTable(newTable)) + } + + return ( + onMouseOverHandler(event.target.id)} + onMouseLeave={onMouseOutHandler} + > + Sum: {rowSum} + + + ) +} + +TableSumCell.propTypes = TableSumCellShape.isRequired + +const mapStateToProps = (state) => ({ + table: state.table +}) + +export default connect(mapStateToProps)(TableSumCell) diff --git a/src/helpers/helpers.js b/src/helpers/helpers.js index 892792e..3bd8a9e 100644 --- a/src/helpers/helpers.js +++ b/src/helpers/helpers.js @@ -1,8 +1,20 @@ import { v4 as uuidv4 } from 'uuid' export const randomGenerate = item => ({ + cellId: uuidv4(), amount: Math.floor(Math.random() * 999), - id: uuidv4(), isLight: false, showPercent: false }) + +export const generateMatrix = (rows, columns) => { + const matrix = [] + for (let i = 0; i < rows; i++) { + matrix[i] = [] + for (let j = 0; j < columns; j++) { + matrix[i][j] = randomGenerate() + } + } + + return matrix +} diff --git a/src/helpers/shapes.js b/src/helpers/shapes.js index 12cf94c..2644393 100644 --- a/src/helpers/shapes.js +++ b/src/helpers/shapes.js @@ -7,23 +7,21 @@ export const TableShape = PropTypes.shape({ showTable: PropTypes.bool }) -export const FormShape = PropTypes.shape({ - rows: PropTypes.number, - columns: PropTypes.number, - highlights: PropTypes.number +export const TableCellShape = PropTypes.shape({ + id: PropTypes.number, + amount: PropTypes.number, + isLight: PropTypes.bool, + showPercent: PropTypes.bool }) -export const AverageColumnsShape = PropTypes.shape({ - rows: PropTypes.number, - columns: PropTypes.number, - table: PropTypes.number +export const TableRowShape = PropTypes.shape({ + cells: PropTypes.arrayOf(TableCellShape) }) -export const RowSumItemShape = PropTypes.shape({ - table: PropTypes.number, +export const FormShape = PropTypes.shape({ + rows: PropTypes.number, columns: PropTypes.number, - cellValue: PropTypes.number, - rowSum: PropTypes.number + highlights: PropTypes.number }) export const TableItemShape = PropTypes.shape({ @@ -49,3 +47,14 @@ export const ButtonDeleteShape = PropTypes.shape({ export const ButtonAddShape = PropTypes.shape({ addRow: PropTypes.func }) + +export const AverageColumnsShape = PropTypes.shape({ + table: PropTypes.number +}) + +export const TableSumCellShape = PropTypes.shape({ + table: PropTypes.number, + columns: PropTypes.number, + cellValue: PropTypes.number, + rowSum: PropTypes.number +}) diff --git a/src/store/actions.js b/src/store/actions.js index 87b8661..03c1d9c 100644 --- a/src/store/actions.js +++ b/src/store/actions.js @@ -2,24 +2,26 @@ export const ACTION_TYPES = { SET_COLUMNS: 'SET::COLUMNS', SET_ROWS: 'SET::ROWS', SET_TABLE: 'SET::TABLE', - SET_HIGHLIGHT: 'SET::HIGHLIGHT', + SET_HIGHLIGHTS: 'SET::HIGHLIGHTS', SET_SHOW_TABLE: 'SET::SHOW::TABLE', - SET_SHOW_BUTTONS: 'SET::SHOW::BUTTONS' + SET_SHOW_BUTTONS: 'SET::SHOW::BUTTONS', + INCREMENT: 'INCREMENT', + SET_LIGHT_CELLS: 'SET_LIGHT_CELLS' } export const setColumns = (param) => ({ - payload: param === '' ? '' : Number(param), + payload: param, type: ACTION_TYPES.SET_COLUMNS }) export const setRows = (param) => ({ - payload: param === '' ? '' : Number(param), + payload: param, type: ACTION_TYPES.SET_ROWS }) export const setHighlights = (param) => ({ - payload: param === '' ? '' : Number(param), - type: ACTION_TYPES.SET_HIGHLIGHT + payload: param, + type: ACTION_TYPES.SET_HIGHLIGHTS }) export const setTable = (param) => ({ @@ -36,3 +38,13 @@ export const setShowButtons = (param) => ({ payload: param, type: ACTION_TYPES.SET_SHOW_BUTTONS }) + +export const increment = (id, cellIndex) => ({ + payload: { id, cellIndex }, + type: ACTION_TYPES.INCREMENT +}) + +export const setLightCells = (id, cellIndex, amount, highlights) => ({ + payload: { id, cellIndex, amount, highlights }, + type: ACTION_TYPES.SET_LIGHT_CELLS +}) diff --git a/src/store/reducers.js b/src/store/reducers.js index 1571b22..3ee31c9 100644 --- a/src/store/reducers.js +++ b/src/store/reducers.js @@ -5,10 +5,12 @@ function rootReducer (state, action) { const { SET_COLUMNS, SET_ROWS, - SET_HIGHLIGHT, + SET_HIGHLIGHTS, SET_TABLE, SET_SHOW_TABLE, - SET_SHOW_BUTTONS + SET_SHOW_BUTTONS, + INCREMENT, + SET_LIGHT_CELLS } = ACTION_TYPES switch (action.type) { @@ -22,21 +24,21 @@ function rootReducer (state, action) { case SET_COLUMNS: { return { ...state, - columns: action.payload + columns: action.payload === '' ? '' : Number(action.payload) } } case SET_ROWS: { return { ...state, - rows: action.payload + rows: action.payload === '' ? '' : Number(action.payload) } } - case SET_HIGHLIGHT: { + case SET_HIGHLIGHTS: { return { ...state, - highlights: action.payload + highlights: action.payload === '' ? '' : Number(action.payload) } } @@ -54,6 +56,49 @@ function rootReducer (state, action) { } } + case INCREMENT: { + state.table.splice(action.payload.id, 1, [...state.table[action.payload.id] + .map((item, index) => index !== action.payload.cellIndex + ? item + : { + ...state.table[action.payload.id][action.payload.cellIndex], + amount: state.table[action.payload.id][action.payload.cellIndex].amount + 1 + }) + ]) + const newTable = [...state.table] + return { + ...state, + table: newTable + } + } + + case SET_LIGHT_CELLS: { + // const amount = action.payload.amount + // const highlights = action.payload.highlights + const rowId = action.payload.id + const cellIndex = action.payload.cellIndex + // const col = state.table.flat().length / state.table.length + console.log(rowId, cellIndex) + break + + // const lightArray = [...state.table].flat().map((item, index) => ({ + // ...item, + // rowIndex: index, + // difference: Math.abs(item.amount - amount) + // })).sort((a, b) => a.difference - b.difference).slice(0, highlights + 1) + + // state.table.map(cell => ( + // lightArray.some(lightCell => lightCell.cellId === cell.cellId) + // ? { ...cell, isLight: true } + // : cell + // )) + + // return { + // ...state, + // table: newTable + // } + } + default: return state } From 6bed44e2952e569e40e4d80a07b897a399d6e9f0 Mon Sep 17 00:00:00 2001 From: denkondratiev Date: Mon, 27 Jul 2020 03:22:25 +0300 Subject: [PATCH 5/7] full refactoring, new matrix generator --- package-lock.json | 5 + package.json | 1 + .../AverageColumns/AverageColumns.jsx | 36 ---- src/components/AverageRow/AverageRow.jsx | 24 +++ src/components/ButtonAdd/ButtonAdd.jsx | 4 +- src/components/Buttons/Buttons.jsx | 48 ++--- src/components/Form/Form.jsx | 153 ++++++++-------- src/components/Table/Table.jsx | 48 +++-- src/components/TableCell/TableCell.jsx | 87 +++------ src/components/TableCellSum/TableCellSum.jsx | 24 +++ src/components/TableRow/TableRow.jsx | 51 ++++-- src/components/TableSumCell/TableSumCell.jsx | 52 ------ src/helpers/generate.js | 25 +++ src/helpers/getLightClosest.js | 15 ++ src/helpers/helpers.js | 20 --- src/helpers/selectors.js | 44 +++++ src/helpers/shapes.js | 56 +++--- src/index.jsx | 2 +- src/store/actions.js | 60 +++---- src/store/reducers.js | 166 +++++++----------- src/store/store.js | 9 + 21 files changed, 469 insertions(+), 461 deletions(-) delete mode 100644 src/components/AverageColumns/AverageColumns.jsx create mode 100644 src/components/AverageRow/AverageRow.jsx create mode 100644 src/components/TableCellSum/TableCellSum.jsx delete mode 100644 src/components/TableSumCell/TableSumCell.jsx create mode 100644 src/helpers/generate.js create mode 100644 src/helpers/getLightClosest.js delete mode 100644 src/helpers/helpers.js create mode 100644 src/helpers/selectors.js create mode 100644 src/store/store.js diff --git a/package-lock.json b/package-lock.json index a4939c7..16c364c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11322,6 +11322,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, + "reselect": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", + "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" + }, "resolve": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", diff --git a/package.json b/package.json index 9f10f0c..cb93c1e 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "react-scripts": "3.4.1", "redux": "^4.0.5", "redux-devtools-extension": "^2.13.8", + "reselect": "^4.0.0", "uuid": "^8.2.0" }, "scripts": { diff --git a/src/components/AverageColumns/AverageColumns.jsx b/src/components/AverageColumns/AverageColumns.jsx deleted file mode 100644 index ec3f3f8..0000000 --- a/src/components/AverageColumns/AverageColumns.jsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react' -import { v4 as uuidv4 } from 'uuid' -import { AverageColumnsShape } from '../../helpers/shapes' -import { connect } from 'react-redux' - -const AverageColumns = (props) => { - const { table } = props - - const onlyAmount = table.map(row => row.map(cell => cell.amount)) - - const res = [] - for (let i = 0; i < onlyAmount.length; i++) { - for (let j = 0; j < onlyAmount[i].length; j++) { - res[j] = (res[j] || 0) + Math.floor(onlyAmount[i][j] / onlyAmount.length) - } - } - - const averageColumnSum = res - - return ( - <> - {{averageColumnSum.map(item => ( - Average sum: {item} - ))} - } - - ) -} - -AverageColumns.propTypes = AverageColumnsShape.isRequired - -const mapStateToProps = (state) => ({ - table: state.table -}) - -export default connect(mapStateToProps)(AverageColumns) diff --git a/src/components/AverageRow/AverageRow.jsx b/src/components/AverageRow/AverageRow.jsx new file mode 100644 index 0000000..eca03cb --- /dev/null +++ b/src/components/AverageRow/AverageRow.jsx @@ -0,0 +1,24 @@ +import React from 'react' +import { v4 as uuidv4 } from 'uuid' +import { AverageRowShape } from '../../helpers/shapes' +import { connect } from 'react-redux' +import { getAverageRowSum } from '../../helpers/selectors' + +const AverageRow = ({ averageArray }) => { + return ( + <> + {{averageArray.map(item => ( + Average sum: {item} + ))} + } + + ) +} + +AverageRow.propTypes = AverageRowShape.isRequired + +const mapStateToProps = (state) => ({ + averageArray: getAverageRowSum(state) +}) + +export default connect(mapStateToProps)(AverageRow) diff --git a/src/components/ButtonAdd/ButtonAdd.jsx b/src/components/ButtonAdd/ButtonAdd.jsx index e58314b..4e01644 100644 --- a/src/components/ButtonAdd/ButtonAdd.jsx +++ b/src/components/ButtonAdd/ButtonAdd.jsx @@ -1,9 +1,7 @@ import React from 'react' import { ButtonAddShape } from '../../helpers/shapes' -export const ButtonAdd = (props) => { - const { addRow } = props - +export const ButtonAdd = ({ addRow }) => { return (