diff --git a/package-lock.json b/package-lock.json index 818d210..94c1a18 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,10 +8,13 @@ "name": "ctd-esp-fe1-final", "version": "0.1.0", "dependencies": { + "@reduxjs/toolkit": "^1.9.5", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-redux": "^8.1.2", "react-router-dom": "^6.8.1", "react-scripts": "^5.0.1", + "typescript": "^4.9.5", "web-vitals": "^3.1.1" } }, @@ -2843,6 +2846,29 @@ "node": ">= 8" } }, + "node_modules/@reduxjs/toolkit": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz", + "integrity": "sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==", + "dependencies": { + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@remix-run/router": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz", @@ -3303,6 +3329,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": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -3367,6 +3402,11 @@ "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==" }, + "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", @@ -3382,6 +3422,16 @@ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, + "node_modules/@types/react": { + "version": "18.2.21", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", + "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -3395,6 +3445,11 @@ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" }, + "node_modules/@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" + }, "node_modules/@types/semver": { "version": "7.3.13", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", @@ -3435,6 +3490,11 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==" }, + "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/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -5705,6 +5765,11 @@ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -7957,6 +8022,19 @@ "he": "bin/he" } }, + "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", @@ -8220,9 +8298,9 @@ } }, "node_modules/immer": { - "version": "9.0.19", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz", - "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==", + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -13286,6 +13364,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.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.2.tgz", + "integrity": "sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==", + "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 || ^5.0.0-beta.0" + }, + "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.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -13431,6 +13552,22 @@ "node": ">=6.0.0" } }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "peerDependencies": { + "redux": "^4" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -13573,6 +13710,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, + "node_modules/reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, "node_modules/resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", @@ -15044,7 +15186,6 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -15177,6 +15318,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -18158,6 +18307,17 @@ } } }, + "@reduxjs/toolkit": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz", + "integrity": "sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==", + "requires": { + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" + } + }, "@remix-run/router": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz", @@ -18485,6 +18645,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": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -18549,6 +18718,11 @@ "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==" }, + "@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", @@ -18564,6 +18738,16 @@ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, + "@types/react": { + "version": "18.2.21", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", + "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -18577,6 +18761,11 @@ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" }, + "@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" + }, "@types/semver": { "version": "7.3.13", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", @@ -18617,6 +18806,11 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==" }, + "@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/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -20280,6 +20474,11 @@ } } }, + "csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, "damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -21913,6 +22112,21 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, + "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", @@ -22109,9 +22323,9 @@ "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" }, "immer": { - "version": "9.0.19", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz", - "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==" + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==" }, "import-fresh": { "version": "3.3.0", @@ -25624,6 +25838,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.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.2.tgz", + "integrity": "sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==", + "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.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, "react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -25727,6 +25961,20 @@ "minimatch": "^3.0.5" } }, + "redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, + "redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "requires": {} + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -25838,6 +26086,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, + "reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, "resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", @@ -26917,8 +27170,7 @@ "typescript": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "peer": true + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" }, "unbox-primitive": { "version": "1.0.2", @@ -27000,6 +27252,12 @@ "punycode": "^2.1.0" } }, + "use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 1db476a..1404fce 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,13 @@ "version": "0.1.0", "private": true, "dependencies": { + "@reduxjs/toolkit": "^1.9.5", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-redux": "^8.1.2", "react-router-dom": "^6.8.1", "react-scripts": "^5.0.1", + "typescript": "^4.9.5", "web-vitals": "^3.1.1" }, "scripts": { diff --git a/src/componentes/botones/boton-favorito.componente.jsx b/src/componentes/botones/boton-favorito.componente.tsx similarity index 75% rename from src/componentes/botones/boton-favorito.componente.jsx rename to src/componentes/botones/boton-favorito.componente.tsx index 81c56e5..a8239dc 100644 --- a/src/componentes/botones/boton-favorito.componente.jsx +++ b/src/componentes/botones/boton-favorito.componente.tsx @@ -1,13 +1,16 @@ import './boton-favorito.css'; +import { BotonFavoritoProps } from '../../interfaces/interfaces'; /** * Boton que indica si un elemento es favorito o no, y da la posibilidad de marcarlo/desmarcarlo * * Deberás tipar las propiedades si usas este componente - * + * * @returns un JSX element */ -const BotonFavorito = ({esFavorito, onClick}) => { + + +const BotonFavorito = ({esFavorito, onClick}: BotonFavoritoProps) => { const src = esFavorito ? "/imagenes/star-filled.png" : "/imagenes/star.png" return
diff --git a/src/componentes/paginacion/paginacion.componente.jsx b/src/componentes/paginacion/paginacion.componente.jsx deleted file mode 100644 index 53804a3..0000000 --- a/src/componentes/paginacion/paginacion.componente.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import './paginacion.css'; - -/** - * Componente que contiene los botones para paginar - * - * Deberás agregar las propiedades necesarias para que funcione correctamente - * - * - * @returns un JSX element - */ -const Paginacion = () => { - - return
- - -
-} - -export default Paginacion; \ No newline at end of file diff --git a/src/componentes/paginacion/paginacion.componente.tsx b/src/componentes/paginacion/paginacion.componente.tsx new file mode 100644 index 0000000..cfea7b3 --- /dev/null +++ b/src/componentes/paginacion/paginacion.componente.tsx @@ -0,0 +1,24 @@ + +import { IPagination } from '../../interfaces/interfaces'; +import { DECREMENT_PAGE, INCREMENT_PAGE } from '../../store/slice/pagination/paginationSlice'; +import { useAppDispatch } from '../../store/store'; +import './paginacion.css'; + +/** + * Componente que contiene los botones para paginar + * + * Deberás agregar las propiedades necesarias para que funcione correctamente + * + * + * @returns un JSX element + */ +const Paginacion = ({page}:IPagination) => { + const dispatch = useAppDispatch(); + + return
+ + +
+} + +export default Paginacion; \ No newline at end of file diff --git a/src/componentes/personajes/filtros.componente.jsx b/src/componentes/personajes/filtros.componente.jsx index b82f7c3..90e3e6f 100644 --- a/src/componentes/personajes/filtros.componente.jsx +++ b/src/componentes/personajes/filtros.componente.jsx @@ -3,9 +3,9 @@ import './filtros.css'; const Filtros = () => { return
- +
} -export default Filtros; \ No newline at end of file +export default Filtros; diff --git a/src/componentes/personajes/tarjeta-personaje.componente.jsx b/src/componentes/personajes/tarjeta-personaje.componente.tsx similarity index 92% rename from src/componentes/personajes/tarjeta-personaje.componente.jsx rename to src/componentes/personajes/tarjeta-personaje.componente.tsx index 332edfe..508c46b 100644 --- a/src/componentes/personajes/tarjeta-personaje.componente.jsx +++ b/src/componentes/personajes/tarjeta-personaje.componente.tsx @@ -15,7 +15,7 @@ const TarjetaPersonaje = () => { Rick Sanchez
Rick Sanchez - +
} diff --git a/src/index.jsx b/src/index.jsx index 44f96ac..17ef78e 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -1,17 +1,21 @@ import * as React from "react"; import * as ReactDOM from "react-dom"; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; -import {BrowserRouter} from "react-router-dom"; +import "./index.css"; +import App from "./App"; +import reportWebVitals from "./reportWebVitals"; +import { BrowserRouter } from "react-router-dom"; +import { Provider } from "react-redux"; +import { store } from "./store/store"; ReactDOM.render( - + + - + + , - document.getElementById('root') + document.getElementById("root") ); // If you want to start measuring performance in your app, pass a function diff --git a/src/interfaces/interfaces.ts b/src/interfaces/interfaces.ts new file mode 100644 index 0000000..32ea953 --- /dev/null +++ b/src/interfaces/interfaces.ts @@ -0,0 +1,63 @@ +export interface BotonFavoritoProps +{ + esFavorito: boolean, + onClick?: () => void + +} + +export interface Welcome { + info: infoApi; + results: Icharacter[]; +} + +export interface infoApi { + count: number; + pages: number; + next: string; + prev: string; +} + +export interface Icharacter { + id: number; + name: string; + status: Status; + species: string; + type: string; + gender: Gender; + origin: Location; + location: Location; + image: string; + episode: string[]; + url: string; + created: Date; +} + +export enum Gender { + Female = "Female", + Male = "Male", + Unknown = "unknown", +} + +export interface Location { + name: string; + url: string; +} + +export enum Status { + Alive = "Alive", + Dead = "Dead", + Unknown = "unknown", +} + +export interface characterState +{ + dataCharacter: Icharacter[], + loading: boolean, + Error:string | null +} + + +export interface IPagination { + page: number + } + \ No newline at end of file diff --git a/src/paginas/Detalle.pagina.jsx b/src/paginas/Detalle.pagina.tsx similarity index 91% rename from src/paginas/Detalle.pagina.jsx rename to src/paginas/Detalle.pagina.tsx index b0db4c7..47efb49 100644 --- a/src/paginas/Detalle.pagina.jsx +++ b/src/paginas/Detalle.pagina.tsx @@ -1,6 +1,7 @@ import "./Detalle.css"; import BotonFavorito from "../componentes/botones/boton-favorito.componente"; import TarjetaEpisodio from "../componentes/episodios/tarjeta-episodio.componente"; +import { BotonFavoritoProps } from '../interfaces/interfaces'; /** * Esta es la pagina de detalle. Aqui se puede mostrar la vista sobre el personaje seleccionado junto con la lista de episodios en los que aparece @@ -26,7 +27,7 @@ const PaginaDetalle = () => {

Planeta: Earth

Genero: Male

- +

Lista de episodios donde apareció el personaje

diff --git a/src/paginas/Inicio.pagina.jsx b/src/paginas/Inicio.pagina.tsx similarity index 57% rename from src/paginas/Inicio.pagina.jsx rename to src/paginas/Inicio.pagina.tsx index bb2b011..8a965cc 100644 --- a/src/paginas/Inicio.pagina.jsx +++ b/src/paginas/Inicio.pagina.tsx @@ -1,6 +1,9 @@ import Filtros from "../componentes/personajes/filtros.componente" import GrillaPersonajes from "../componentes/personajes/grilla-personajes.componente" import Paginacion from "../componentes/paginacion/paginacion.componente"; +import { useAppDispatch, useAppSelector } from "../store/store"; +import { GET_CHARACTERS } from "../store/slice/character/thunksCharacter"; +import { useEffect } from "react"; /** * Esta es la pagina principal. Aquí se debera ver el panel de filtros junto con la grilla de personajes. @@ -11,15 +14,23 @@ import Paginacion from "../componentes/paginacion/paginacion.componente"; * @returns la pagina de inicio */ const PaginaInicio = () => { + const dispatch = useAppDispatch() + const{value:pageValue} = useAppSelector((state) => state.pages) + const{dataCharacter} = useAppSelector((state) => state.characters) + + useEffect(() => { + dispatch(GET_CHARACTERS({data:pageValue, parameter: 'page'})) + },[pageValue]) + return

Catálogo de Personajes

- + - +
} diff --git a/src/store/slice/character/characterSlice.ts b/src/store/slice/character/characterSlice.ts new file mode 100644 index 0000000..287212f --- /dev/null +++ b/src/store/slice/character/characterSlice.ts @@ -0,0 +1,36 @@ +import { PayloadAction, createSlice } from "@reduxjs/toolkit"; +import { Icharacter, characterState } from "../../../interfaces/interfaces"; +import { GET_CHARACTERS } from "./thunksCharacter"; + +const inicialState: characterState = { + dataCharacter: [], + loading: true, + Error: null, +}; + +export const characterSlice = createSlice({ + name: "character", + initialState: inicialState, + + reducers: {}, + + extraReducers: (builder) => { + builder.addCase(GET_CHARACTERS.pending, (state) => { + state.loading = true; + }) + + builder.addCase(GET_CHARACTERS.fulfilled, (state, action) => { + state.dataCharacter = action.payload; + state.loading = false; + }) + + builder.addCase(GET_CHARACTERS.rejected, (state, action) => { + state.loading = false; + state.Error = action.error.message ?? 'Se ha presentado un error en la petición' + }) + }, + +}); + +const charactersReducer = characterSlice.reducer; +export default charactersReducer; diff --git a/src/store/slice/character/thunksCharacter.ts b/src/store/slice/character/thunksCharacter.ts new file mode 100644 index 0000000..de282bb --- /dev/null +++ b/src/store/slice/character/thunksCharacter.ts @@ -0,0 +1,34 @@ +import { createAsyncThunk } from "@reduxjs/toolkit"; +import { Icharacter } from "../../../interfaces/interfaces"; + +export const GET_CHARACTERS = createAsyncThunk +( + 'character/GET_CHARACTERS', + async ({data, parameter}: {data:number | string; parameter:string})=> + { + try + { + const dataCharacter = await fetch(`https://rickandmortyapi.com/api/character/?${parameter}=${data}`); + const dataResponseCharacter = await dataCharacter.json(); + const dataResulsCharacter = dataResponseCharacter.results; + return dataResulsCharacter; + } + + + catch(error) + { + console.error("Error en la petición:", error); + + + } + + + } +); + +export const GET_CHARACTER_BY_ID = createAsyncThunk('character/GET_CHARACTERS',async (id:number): Promise => { + const dataResulsCharacter = await fetch(`https://rickandmortyapi.com/api/character/${id}`) + const dataResponseCharacter = await dataResulsCharacter.json(); + return dataResponseCharacter; + +}) diff --git a/src/store/slice/pagination/paginationSlice.ts b/src/store/slice/pagination/paginationSlice.ts new file mode 100644 index 0000000..746042e --- /dev/null +++ b/src/store/slice/pagination/paginationSlice.ts @@ -0,0 +1,31 @@ + +import { createSlice } from '@reduxjs/toolkit'; +import React from 'react' + +export type paginationSlice = { + value : number, +} + +const initialState : paginationSlice ={ + value:0 +} + +export const paginationSlice = createSlice({ + name : 'page', + initialState: initialState, + reducers : { + INCREMENT_PAGE : (state) => { + state.value += 1; + }, + DECREMENT_PAGE : (state) => { + state.value -= 1; + }, + + } +}); + +const paginationReducer = paginationSlice.reducer; + +export const {INCREMENT_PAGE, DECREMENT_PAGE} = paginationSlice.actions; + +export default paginationReducer; \ No newline at end of file diff --git a/src/store/store.ts b/src/store/store.ts new file mode 100644 index 0000000..36b734f --- /dev/null +++ b/src/store/store.ts @@ -0,0 +1,24 @@ +import { configureStore } from "@reduxjs/toolkit"; +import charactersReducer from "./slice/character/characterSlice"; +import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"; +import paginationReducer from "./slice/pagination/paginationSlice"; + + +export const store = configureStore +({ + reducer: + { + pages:paginationReducer, + characters:charactersReducer, + }, +}); + +type RootState = ReturnType; +type AppDispatch = typeof store.dispatch; + +type DispatchFunc=()=>AppDispatch + +export const useAppDispatch:DispatchFunc = useDispatch +export const useAppSelector:TypedUseSelectorHook = useSelector; + +export default store;