From 97c31b45414cf802dd4ed4379ebefc1368abf39b Mon Sep 17 00:00:00 2001 From: Raphael Martins Date: Mon, 25 Apr 2022 15:43:22 -0300 Subject: [PATCH 1/5] defined components architecture. --- src/App.js | 25 +++++++++++-------------- src/components/GeneratePasswordBtn.js | 9 +++++++++ src/components/Length.js | 12 ++++++++++++ src/components/Option.js | 17 +++++++++++++++++ src/components/Password.js | 9 +++++++++ src/components/Settings.js | 16 ++++++++++++++++ 6 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 src/components/GeneratePasswordBtn.js create mode 100644 src/components/Length.js create mode 100644 src/components/Option.js create mode 100644 src/components/Password.js create mode 100644 src/components/Settings.js diff --git a/src/App.js b/src/App.js index 3784575..022987c 100644 --- a/src/App.js +++ b/src/App.js @@ -1,23 +1,20 @@ import logo from './logo.svg'; import './App.css'; +import Password from './components/Password'; +import Length from './components/Length'; +import Settings from './components/Settings'; +import GeneratePasswordBtn from './components/GeneratePasswordBtn'; function App() { return (
-
- logo -

- Edit src/App.js and save to reload. -

- - Learn React - -
+
+

password generator

+ + + + +
); } diff --git a/src/components/GeneratePasswordBtn.js b/src/components/GeneratePasswordBtn.js new file mode 100644 index 0000000..7f0973d --- /dev/null +++ b/src/components/GeneratePasswordBtn.js @@ -0,0 +1,9 @@ +import React from 'react'; + +function GeneratePasswordBtn() { + return ( + + ); +} + +export default GeneratePasswordBtn; diff --git a/src/components/Length.js b/src/components/Length.js new file mode 100644 index 0000000..961a06f --- /dev/null +++ b/src/components/Length.js @@ -0,0 +1,12 @@ +import React from 'react'; + +function Length() { + return ( +
+ length: + +
+ ); +} + +export default Length; diff --git a/src/components/Option.js b/src/components/Option.js new file mode 100644 index 0000000..78d256d --- /dev/null +++ b/src/components/Option.js @@ -0,0 +1,17 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +function Option(props) { + return ( + + ); +} + +Option.propTypes = { + label: PropTypes.string.isRequired, +}; + +export default Option; diff --git a/src/components/Password.js b/src/components/Password.js new file mode 100644 index 0000000..59412d1 --- /dev/null +++ b/src/components/Password.js @@ -0,0 +1,9 @@ +import React from 'react'; + +function Password() { + return ( +

click generate

+ ); +} + +export default Password; diff --git a/src/components/Settings.js b/src/components/Settings.js new file mode 100644 index 0000000..14c30d7 --- /dev/null +++ b/src/components/Settings.js @@ -0,0 +1,16 @@ +import React from 'react'; +import Option from './Option'; + +function Settings() { + return ( +
+ settings +
+ ); +} + +export default Settings; From dc39af50d961250508984a5d7eca4865d271f578 Mon Sep 17 00:00:00 2001 From: Raphael Martins Date: Mon, 25 Apr 2022 15:59:12 -0300 Subject: [PATCH 2/5] configure redux. --- package-lock.json | 276 +++++++++++++++++++++++++++++++++ package.json | 3 + src/index.js | 12 +- src/redux/reducers/index.js | 6 + src/redux/reducers/settings.js | 16 ++ src/redux/store/index.js | 8 + 6 files changed, 317 insertions(+), 4 deletions(-) create mode 100644 src/redux/reducers/index.js create mode 100644 src/redux/reducers/settings.js create mode 100644 src/redux/store/index.js diff --git a/package-lock.json b/package-lock.json index 6c5205a..9caaec6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,12 +8,15 @@ "name": "exercise-password-generator", "version": "0.1.0", "dependencies": { + "@reduxjs/toolkit": "^1.8.1", "@testing-library/jest-dom": "^5.16.1", "@testing-library/react": "^12.1.2", "@testing-library/user-event": "^13.5.0", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-redux": "^8.0.1", "react-scripts": "4.0.3", + "redux": "^4.2.0", "web-vitals": "^2.1.4" }, "devDependencies": { @@ -2667,6 +2670,38 @@ "node": ">=10" } }, + "node_modules/@reduxjs/toolkit": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.1.tgz", + "integrity": "sha512-Q6mzbTpO9nOYRnkwpDlFOAbQnd3g7zj7CtHAZWz5SzE5lcV97Tf8f3SzOO8BoPOMYBFgfZaqTUZqgGu+a0+Fng==", + "dependencies": { + "immer": "^9.0.7", + "redux": "^4.1.2", + "redux-thunk": "^2.4.1", + "reselect": "^4.1.5" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.0-beta" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "9.0.12", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", + "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/@rollup/plugin-node-resolve": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", @@ -3242,6 +3277,15 @@ "@types/node": "*" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/html-minifier-terser": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", @@ -3318,11 +3362,26 @@ "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.3.tgz", "integrity": "sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w==" }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, "node_modules/@types/q": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" }, + "node_modules/@types/react": { + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.6.tgz", + "integrity": "sha512-bPqwzJRzKtfI0mVYr5R+1o9BOE8UEXefwc1LwcBtfnaAn6OoqMhLa/91VA8aeWfDPJt1kHvYKI8RHcQybZLHHA==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/resolve": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", @@ -3331,6 +3390,11 @@ "@types/node": "*" } }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, "node_modules/@types/source-list-map": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", @@ -3370,6 +3434,11 @@ "node": ">=0.10.0" } }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "node_modules/@types/webpack": { "version": "4.41.32", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.32.tgz", @@ -6484,6 +6553,11 @@ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" }, + "node_modules/csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + }, "node_modules/cyclist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", @@ -9979,6 +10053,19 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "node_modules/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==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -18757,6 +18844,49 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "node_modules/react-redux": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.1.tgz", + "integrity": "sha512-LMZMsPY4DYdZfLJgd7i79n5Kps5N9XVLCJJeWAaPYTV+Eah2zTuBjTxKtNEbjiyitbq80/eIkm55CYSLqAub3w==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^16.8 || ^17.0 || ^18.0", + "@types/react-dom": "^16.8 || ^17.0 || ^18.0", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0", + "react-native": ">=0.59", + "redux": "^4" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-redux/node_modules/react-is": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.0.0.tgz", + "integrity": "sha512-yUcBYdBBbo3QiPsgYDcfQcIkGZHfxOaoE6HLSnr1sPzMhdyxusbfKOSUbSd/ocGi32dxcj366PsTj+5oggeKKw==" + }, "node_modules/react-refresh": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", @@ -19385,6 +19515,22 @@ "node": ">=8" } }, + "node_modules/redux": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", + "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-thunk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "peerDependencies": { + "redux": "^4" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -19583,6 +19729,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, + "node_modules/reselect": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz", + "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==" + }, "node_modules/resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", @@ -22776,6 +22927,14 @@ "node": ">=0.10.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.0.0.tgz", + "integrity": "sha512-AFVsxg5GkFg8GDcxnl+Z0lMAz9rE8DGJCc28qnBuQF7lac57B5smLcT37aXpXIIPz75rW4g3eXHPjhHwdGskOw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0-rc" + } + }, "node_modules/util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", @@ -26592,6 +26751,24 @@ } } }, + "@reduxjs/toolkit": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.1.tgz", + "integrity": "sha512-Q6mzbTpO9nOYRnkwpDlFOAbQnd3g7zj7CtHAZWz5SzE5lcV97Tf8f3SzOO8BoPOMYBFgfZaqTUZqgGu+a0+Fng==", + "requires": { + "immer": "^9.0.7", + "redux": "^4.1.2", + "redux-thunk": "^2.4.1", + "reselect": "^4.1.5" + }, + "dependencies": { + "immer": { + "version": "9.0.12", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", + "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==" + } + } + }, "@rollup/plugin-node-resolve": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", @@ -26990,6 +27167,15 @@ "@types/node": "*" } }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/html-minifier-terser": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", @@ -27066,11 +27252,26 @@ "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.3.tgz", "integrity": "sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w==" }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, "@types/q": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" }, + "@types/react": { + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.6.tgz", + "integrity": "sha512-bPqwzJRzKtfI0mVYr5R+1o9BOE8UEXefwc1LwcBtfnaAn6OoqMhLa/91VA8aeWfDPJt1kHvYKI8RHcQybZLHHA==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "@types/resolve": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", @@ -27079,6 +27280,11 @@ "@types/node": "*" } }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, "@types/source-list-map": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", @@ -27117,6 +27323,11 @@ } } }, + "@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "@types/webpack": { "version": "4.41.32", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.32.tgz", @@ -29553,6 +29764,11 @@ } } }, + "csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + }, "cyclist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", @@ -32218,6 +32434,21 @@ "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" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, "hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -38817,6 +39048,26 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "react-redux": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.1.tgz", + "integrity": "sha512-LMZMsPY4DYdZfLJgd7i79n5Kps5N9XVLCJJeWAaPYTV+Eah2zTuBjTxKtNEbjiyitbq80/eIkm55CYSLqAub3w==", + "requires": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "dependencies": { + "react-is": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.0.0.tgz", + "integrity": "sha512-yUcBYdBBbo3QiPsgYDcfQcIkGZHfxOaoE6HLSnr1sPzMhdyxusbfKOSUbSd/ocGi32dxcj366PsTj+5oggeKKw==" + } + } + }, "react-refresh": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", @@ -39216,6 +39467,20 @@ "strip-indent": "^3.0.0" } }, + "redux": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", + "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, + "redux-thunk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "requires": {} + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -39370,6 +39635,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, + "reselect": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz", + "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==" + }, "resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", @@ -41864,6 +42134,12 @@ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, + "use-sync-external-store": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.0.0.tgz", + "integrity": "sha512-AFVsxg5GkFg8GDcxnl+Z0lMAz9rE8DGJCc28qnBuQF7lac57B5smLcT37aXpXIIPz75rW4g3eXHPjhHwdGskOw==", + "requires": {} + }, "util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", diff --git a/package.json b/package.json index 4593872..23e8825 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,15 @@ "node": "16" }, "dependencies": { + "@reduxjs/toolkit": "^1.8.1", "@testing-library/jest-dom": "^5.16.1", "@testing-library/react": "^12.1.2", "@testing-library/user-event": "^13.5.0", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-redux": "^8.0.1", "react-scripts": "4.0.3", + "redux": "^4.2.0", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/src/index.js b/src/index.js index ef2edf8..bd15611 100644 --- a/src/index.js +++ b/src/index.js @@ -1,13 +1,17 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import './index.css'; +import { Provider } from 'react-redux'; import App from './App'; +import './index.css'; +import store from './redux/store'; import reportWebVitals from './reportWebVitals'; ReactDOM.render( - - - , + + + + + , document.getElementById('root') ); diff --git a/src/redux/reducers/index.js b/src/redux/reducers/index.js new file mode 100644 index 0000000..69b6452 --- /dev/null +++ b/src/redux/reducers/index.js @@ -0,0 +1,6 @@ +import { combineReducers } from 'redux'; +import settings from './settings'; + +const rootReducer = combineReducers({ settings }); + +export default rootReducer; diff --git a/src/redux/reducers/settings.js b/src/redux/reducers/settings.js new file mode 100644 index 0000000..7dbaa2c --- /dev/null +++ b/src/redux/reducers/settings.js @@ -0,0 +1,16 @@ +const INITIAL_STATE = { + length: 4, + includeUppercase: false, + includeLowercase: false, + includeNumbers: false, + includeSymbols: false, +}; + +const settings = (state = INITIAL_STATE, action) => { + switch (action.type) { + default: + return state; + } +}; + +export default settings; diff --git a/src/redux/store/index.js b/src/redux/store/index.js new file mode 100644 index 0000000..d5151c6 --- /dev/null +++ b/src/redux/store/index.js @@ -0,0 +1,8 @@ +import { configureStore } from '@reduxjs/toolkit'; +import rootReducer from '../reducers'; + +const store = configureStore({ + reducer: rootReducer, +}); + +export default store; From 76e416cd32402442b3024b9086a1bebba358e207 Mon Sep 17 00:00:00 2001 From: Raphael Martins Date: Mon, 25 Apr 2022 16:13:32 -0300 Subject: [PATCH 3/5] the inputs are now controlled by the state. --- src/components/Length.js | 22 +++++++++++++++++++--- src/components/Option.js | 23 ++++++++++++++++++----- src/components/Settings.js | 8 ++++---- src/redux/actions/index.js | 12 ++++++++++++ src/redux/reducers/settings.js | 7 +++++++ 5 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 src/redux/actions/index.js diff --git a/src/components/Length.js b/src/components/Length.js index 961a06f..98b7bb8 100644 --- a/src/components/Length.js +++ b/src/components/Length.js @@ -1,10 +1,26 @@ -import React from 'react'; +import React from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { actionChangeSettings } from "../redux/actions"; function Length() { + const { length } = useSelector((state) => state.settings); + const dispatch = useDispatch(); + return (
- length: - + + length: {length} + + + dispatch(actionChangeSettings(target.name, target.value)) + } + />
); } diff --git a/src/components/Option.js b/src/components/Option.js index 78d256d..0001af3 100644 --- a/src/components/Option.js +++ b/src/components/Option.js @@ -1,17 +1,30 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import PropTypes from "prop-types"; +import React from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { actionChangeSettings } from "../redux/actions"; + +function Option({ label, name }) { + const settings = useSelector((state) => state.settings); + const dispatch = useDispatch(); -function Option(props) { return ( ); } Option.propTypes = { label: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, }; export default Option; diff --git a/src/components/Settings.js b/src/components/Settings.js index 14c30d7..6991b40 100644 --- a/src/components/Settings.js +++ b/src/components/Settings.js @@ -5,10 +5,10 @@ function Settings() { return (
settings -
); } diff --git a/src/redux/actions/index.js b/src/redux/actions/index.js new file mode 100644 index 0000000..40e65bd --- /dev/null +++ b/src/redux/actions/index.js @@ -0,0 +1,12 @@ +const CHANGE_SETTINGS = 'CHANGE_SETTINGS'; + +const actionChangeSettings = (name, value) => ({ + type: CHANGE_SETTINGS, + name, + value, +}); + +export { + CHANGE_SETTINGS, + actionChangeSettings, +}; diff --git a/src/redux/reducers/settings.js b/src/redux/reducers/settings.js index 7dbaa2c..14c08c2 100644 --- a/src/redux/reducers/settings.js +++ b/src/redux/reducers/settings.js @@ -1,3 +1,5 @@ +import { CHANGE_SETTINGS } from '../actions'; + const INITIAL_STATE = { length: 4, includeUppercase: false, @@ -8,6 +10,11 @@ const INITIAL_STATE = { const settings = (state = INITIAL_STATE, action) => { switch (action.type) { + case CHANGE_SETTINGS: + return { + ...state, + [action.name]: action.value, + }; default: return state; } From 856fb82071d9e8ed76e98a471d2be4229b372775 Mon Sep 17 00:00:00 2001 From: Raphael Martins Date: Mon, 25 Apr 2022 16:57:10 -0300 Subject: [PATCH 4/5] the password is not being generated. --- src/components/GeneratePasswordBtn.js | 10 ++++- src/components/Password.js | 9 ++-- src/redux/actions/index.js | 7 +++ src/redux/reducers/characters.js | 65 +++++++++++++++++++++++++++ src/redux/reducers/settings.js | 24 +++++++++- 5 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 src/redux/reducers/characters.js diff --git a/src/components/GeneratePasswordBtn.js b/src/components/GeneratePasswordBtn.js index 7f0973d..b0b048e 100644 --- a/src/components/GeneratePasswordBtn.js +++ b/src/components/GeneratePasswordBtn.js @@ -1,8 +1,14 @@ -import React from 'react'; +import React from "react"; +import { useDispatch } from "react-redux"; +import { actionGeneratePassword } from "../redux/actions"; function GeneratePasswordBtn() { + const dispatch = useDispatch(); + return ( - + ); } diff --git a/src/components/Password.js b/src/components/Password.js index 59412d1..9caeb97 100644 --- a/src/components/Password.js +++ b/src/components/Password.js @@ -1,9 +1,10 @@ -import React from 'react'; +import React from "react"; +import { useSelector } from "react-redux"; function Password() { - return ( -

click generate

- ); + const { password } = useSelector((state) => state.settings); + + return

{password}

; } export default Password; diff --git a/src/redux/actions/index.js b/src/redux/actions/index.js index 40e65bd..044a760 100644 --- a/src/redux/actions/index.js +++ b/src/redux/actions/index.js @@ -1,4 +1,5 @@ const CHANGE_SETTINGS = 'CHANGE_SETTINGS'; +const GENERATE_PASSWORD = 'GENERATE_PASSWORD'; const actionChangeSettings = (name, value) => ({ type: CHANGE_SETTINGS, @@ -6,7 +7,13 @@ const actionChangeSettings = (name, value) => ({ value, }); +const actionGeneratePassword = () => ({ + type: GENERATE_PASSWORD, +}); + export { CHANGE_SETTINGS, actionChangeSettings, + GENERATE_PASSWORD, + actionGeneratePassword, }; diff --git a/src/redux/reducers/characters.js b/src/redux/reducers/characters.js new file mode 100644 index 0000000..5a2555a --- /dev/null +++ b/src/redux/reducers/characters.js @@ -0,0 +1,65 @@ +const numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; +const lowerCaseLetters = [ + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', +]; +const upperCaseLetters = lowerCaseLetters.map((letter) => letter.toUpperCase()); +const symbols = [ + '!', + '#', + '$', + '%', + '&', + '\'', + '(', + ')', + '*', + '+', + ',', + '-', + '.', + '/', + ':', + ';', + '<', + '=', + '>', + '?', + '@', + '[', + '\\', + ']', + '^', + '_', + '`', + '{', + '|', + '}', + '~', +]; + +export { numbers, lowerCaseLetters, upperCaseLetters, symbols }; diff --git a/src/redux/reducers/settings.js b/src/redux/reducers/settings.js index 14c08c2..2698254 100644 --- a/src/redux/reducers/settings.js +++ b/src/redux/reducers/settings.js @@ -1,6 +1,8 @@ -import { CHANGE_SETTINGS } from '../actions'; +import { CHANGE_SETTINGS, GENERATE_PASSWORD } from '../actions'; +import { lowerCaseLetters, numbers, symbols, upperCaseLetters } from './characters'; const INITIAL_STATE = { + password: 'CLICK GENERATE', length: 4, includeUppercase: false, includeLowercase: false, @@ -8,6 +10,21 @@ const INITIAL_STATE = { includeSymbols: false, }; +const generatePassword = (settings) => { + let password = []; + + if (settings.includeUppercase) password = [...password, ...lowerCaseLetters]; + if (settings.includeLowercase) password = [...password, ...upperCaseLetters]; + if (settings.includeNumbers) password = [...password, ...numbers]; + if (settings.includeSymbols) password = [...password, ...symbols]; + + const shuffle = 0.5; + password.sort(() => Math.random() - shuffle); + password = password.join('').slice(0, settings.length); + + return password; +}; + const settings = (state = INITIAL_STATE, action) => { switch (action.type) { case CHANGE_SETTINGS: @@ -15,6 +32,11 @@ const settings = (state = INITIAL_STATE, action) => { ...state, [action.name]: action.value, }; + case GENERATE_PASSWORD: + return { + ...state, + password: generatePassword(state), + }; default: return state; } From 9158466b3f26aa09ed1d796c2372c2eba0e36b6d Mon Sep 17 00:00:00 2001 From: Raphael Martins Date: Mon, 25 Apr 2022 17:02:47 -0300 Subject: [PATCH 5/5] fix: now the button is disabled if none of the options are checked. --- src/components/GeneratePasswordBtn.js | 16 ++++++++++++++-- src/redux/reducers/settings.js | 4 ++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/components/GeneratePasswordBtn.js b/src/components/GeneratePasswordBtn.js index b0b048e..bc57526 100644 --- a/src/components/GeneratePasswordBtn.js +++ b/src/components/GeneratePasswordBtn.js @@ -1,12 +1,24 @@ import React from "react"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { actionGeneratePassword } from "../redux/actions"; function GeneratePasswordBtn() { const dispatch = useDispatch(); + const { includeUppercase, includeLowercase, includeNumbers, includeSymbols } = + useSelector((state) => state.settings); + const settings = [ + includeUppercase, + includeLowercase, + includeNumbers, + includeSymbols, + ]; return ( - ); diff --git a/src/redux/reducers/settings.js b/src/redux/reducers/settings.js index 2698254..bf37eee 100644 --- a/src/redux/reducers/settings.js +++ b/src/redux/reducers/settings.js @@ -13,8 +13,8 @@ const INITIAL_STATE = { const generatePassword = (settings) => { let password = []; - if (settings.includeUppercase) password = [...password, ...lowerCaseLetters]; - if (settings.includeLowercase) password = [...password, ...upperCaseLetters]; + if (settings.includeLowercase) password = [...password, ...lowerCaseLetters]; + if (settings.includeUppercase) password = [...password, ...upperCaseLetters]; if (settings.includeNumbers) password = [...password, ...numbers]; if (settings.includeSymbols) password = [...password, ...symbols];