Artem 3 vuotta sitten
vanhempi
commit
8894591cdf

+ 376 - 0
package-lock.json

@@ -12,7 +12,12 @@
         "@testing-library/user-event": "^12.8.3",
         "react": "^17.0.2",
         "react-dom": "^17.0.2",
+        "react-redux": "^7.2.4",
         "react-scripts": "4.0.3",
+        "redux": "^4.1.1",
+        "redux-logger": "^3.0.6",
+        "redux-saga": "^1.1.3",
+        "redux-thunk": "^2.3.0",
         "web-vitals": "^1.1.2"
       }
     },
@@ -2719,6 +2724,53 @@
         "node": ">= 8"
       }
     },
+    "node_modules/@redux-saga/core": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.1.3.tgz",
+      "integrity": "sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg==",
+      "dependencies": {
+        "@babel/runtime": "^7.6.3",
+        "@redux-saga/deferred": "^1.1.2",
+        "@redux-saga/delay-p": "^1.1.2",
+        "@redux-saga/is": "^1.1.2",
+        "@redux-saga/symbols": "^1.1.2",
+        "@redux-saga/types": "^1.1.0",
+        "redux": "^4.0.4",
+        "typescript-tuple": "^2.2.1"
+      }
+    },
+    "node_modules/@redux-saga/deferred": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.1.2.tgz",
+      "integrity": "sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ=="
+    },
+    "node_modules/@redux-saga/delay-p": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.1.2.tgz",
+      "integrity": "sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g==",
+      "dependencies": {
+        "@redux-saga/symbols": "^1.1.2"
+      }
+    },
+    "node_modules/@redux-saga/is": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.2.tgz",
+      "integrity": "sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w==",
+      "dependencies": {
+        "@redux-saga/symbols": "^1.1.2",
+        "@redux-saga/types": "^1.1.0"
+      }
+    },
+    "node_modules/@redux-saga/symbols": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.2.tgz",
+      "integrity": "sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ=="
+    },
+    "node_modules/@redux-saga/types": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.1.0.tgz",
+      "integrity": "sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg=="
+    },
     "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",
@@ -3480,6 +3532,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",
@@ -3692,11 +3753,37 @@
       "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.2.tgz",
       "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog=="
     },
+    "node_modules/@types/prop-types": {
+      "version": "15.7.4",
+      "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
+      "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
+    },
     "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": "17.0.19",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.19.tgz",
+      "integrity": "sha512-sX1HisdB1/ZESixMTGnMxH9TDe8Sk709734fEQZzCV/4lSu9kJCPbo2PbTRoZM+53Pp0P10hYVyReUueGwUi4A==",
+      "dependencies": {
+        "@types/prop-types": "*",
+        "@types/scheduler": "*",
+        "csstype": "^3.0.2"
+      }
+    },
+    "node_modules/@types/react-redux": {
+      "version": "7.1.18",
+      "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz",
+      "integrity": "sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==",
+      "dependencies": {
+        "@types/hoist-non-react-statics": "^3.3.0",
+        "@types/react": "*",
+        "hoist-non-react-statics": "^3.3.0",
+        "redux": "^4.0.0"
+      }
+    },
     "node_modules/@types/resolve": {
       "version": "0.0.8",
       "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
@@ -3705,6 +3792,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",
@@ -6762,6 +6854,11 @@
       "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
       "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
     },
+    "node_modules/csstype": {
+      "version": "3.0.8",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
+      "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
+    },
     "node_modules/cyclist": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
@@ -6836,6 +6933,11 @@
       "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
       "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw="
     },
+    "node_modules/deep-diff": {
+      "version": "0.3.8",
+      "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz",
+      "integrity": "sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ="
+    },
     "node_modules/deep-equal": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
@@ -9812,6 +9914,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",
@@ -16512,6 +16627,35 @@
       "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": "7.2.4",
+      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz",
+      "integrity": "sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==",
+      "dependencies": {
+        "@babel/runtime": "^7.12.1",
+        "@types/react-redux": "^7.1.16",
+        "hoist-non-react-statics": "^3.3.2",
+        "loose-envify": "^1.4.0",
+        "prop-types": "^15.7.2",
+        "react-is": "^16.13.1"
+      },
+      "peerDependencies": {
+        "react": "^16.8.3 || ^17"
+      },
+      "peerDependenciesMeta": {
+        "react-dom": {
+          "optional": true
+        },
+        "react-native": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-redux/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/react-refresh": {
       "version": "0.8.3",
       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
@@ -16803,6 +16947,35 @@
         "node": ">=8"
       }
     },
+    "node_modules/redux": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.1.tgz",
+      "integrity": "sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw==",
+      "dependencies": {
+        "@babel/runtime": "^7.9.2"
+      }
+    },
+    "node_modules/redux-logger": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz",
+      "integrity": "sha1-91VZZvMJjzyIYExEnPC69XeCdL8=",
+      "dependencies": {
+        "deep-diff": "^0.3.5"
+      }
+    },
+    "node_modules/redux-saga": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.1.3.tgz",
+      "integrity": "sha512-RkSn/z0mwaSa5/xH/hQLo8gNf4tlvT18qXDNvedihLcfzh+jMchDgaariQoehCpgRltEm4zHKJyINEz6aqswTw==",
+      "dependencies": {
+        "@redux-saga/core": "^1.1.3"
+      }
+    },
+    "node_modules/redux-thunk": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
+      "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
+    },
     "node_modules/regenerate": {
       "version": "1.4.2",
       "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -19530,6 +19703,27 @@
         "node": ">=4.2.0"
       }
     },
+    "node_modules/typescript-compare": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz",
+      "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==",
+      "dependencies": {
+        "typescript-logic": "^0.0.0"
+      }
+    },
+    "node_modules/typescript-logic": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz",
+      "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q=="
+    },
+    "node_modules/typescript-tuple": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz",
+      "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==",
+      "dependencies": {
+        "typescript-compare": "^0.0.2"
+      }
+    },
     "node_modules/unbox-primitive": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
@@ -23644,6 +23838,53 @@
         }
       }
     },
+    "@redux-saga/core": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.1.3.tgz",
+      "integrity": "sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg==",
+      "requires": {
+        "@babel/runtime": "^7.6.3",
+        "@redux-saga/deferred": "^1.1.2",
+        "@redux-saga/delay-p": "^1.1.2",
+        "@redux-saga/is": "^1.1.2",
+        "@redux-saga/symbols": "^1.1.2",
+        "@redux-saga/types": "^1.1.0",
+        "redux": "^4.0.4",
+        "typescript-tuple": "^2.2.1"
+      }
+    },
+    "@redux-saga/deferred": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.1.2.tgz",
+      "integrity": "sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ=="
+    },
+    "@redux-saga/delay-p": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.1.2.tgz",
+      "integrity": "sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g==",
+      "requires": {
+        "@redux-saga/symbols": "^1.1.2"
+      }
+    },
+    "@redux-saga/is": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.2.tgz",
+      "integrity": "sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w==",
+      "requires": {
+        "@redux-saga/symbols": "^1.1.2",
+        "@redux-saga/types": "^1.1.0"
+      }
+    },
+    "@redux-saga/symbols": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.2.tgz",
+      "integrity": "sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ=="
+    },
+    "@redux-saga/types": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.1.0.tgz",
+      "integrity": "sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg=="
+    },
     "@rollup/plugin-node-resolve": {
       "version": "7.1.3",
       "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz",
@@ -24192,6 +24433,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",
@@ -24366,11 +24616,37 @@
       "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.3.2.tgz",
       "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog=="
     },
+    "@types/prop-types": {
+      "version": "15.7.4",
+      "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
+      "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
+    },
     "@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": "17.0.19",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.19.tgz",
+      "integrity": "sha512-sX1HisdB1/ZESixMTGnMxH9TDe8Sk709734fEQZzCV/4lSu9kJCPbo2PbTRoZM+53Pp0P10hYVyReUueGwUi4A==",
+      "requires": {
+        "@types/prop-types": "*",
+        "@types/scheduler": "*",
+        "csstype": "^3.0.2"
+      }
+    },
+    "@types/react-redux": {
+      "version": "7.1.18",
+      "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz",
+      "integrity": "sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==",
+      "requires": {
+        "@types/hoist-non-react-statics": "^3.3.0",
+        "@types/react": "*",
+        "hoist-non-react-statics": "^3.3.0",
+        "redux": "^4.0.0"
+      }
+    },
     "@types/resolve": {
       "version": "0.0.8",
       "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
@@ -24379,6 +24655,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",
@@ -26810,6 +27091,11 @@
         }
       }
     },
+    "csstype": {
+      "version": "3.0.8",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
+      "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
+    },
     "cyclist": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
@@ -26867,6 +27153,11 @@
       "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
       "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw="
     },
+    "deep-diff": {
+      "version": "0.3.8",
+      "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz",
+      "integrity": "sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ="
+    },
     "deep-equal": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
@@ -29121,6 +29412,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",
@@ -34258,6 +34564,26 @@
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
       "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
     },
+    "react-redux": {
+      "version": "7.2.4",
+      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz",
+      "integrity": "sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==",
+      "requires": {
+        "@babel/runtime": "^7.12.1",
+        "@types/react-redux": "^7.1.16",
+        "hoist-non-react-statics": "^3.3.2",
+        "loose-envify": "^1.4.0",
+        "prop-types": "^15.7.2",
+        "react-is": "^16.13.1"
+      },
+      "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=="
+        }
+      }
+    },
     "react-refresh": {
       "version": "0.8.3",
       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
@@ -34490,6 +34816,35 @@
         "strip-indent": "^3.0.0"
       }
     },
+    "redux": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.1.tgz",
+      "integrity": "sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw==",
+      "requires": {
+        "@babel/runtime": "^7.9.2"
+      }
+    },
+    "redux-logger": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz",
+      "integrity": "sha1-91VZZvMJjzyIYExEnPC69XeCdL8=",
+      "requires": {
+        "deep-diff": "^0.3.5"
+      }
+    },
+    "redux-saga": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.1.3.tgz",
+      "integrity": "sha512-RkSn/z0mwaSa5/xH/hQLo8gNf4tlvT18qXDNvedihLcfzh+jMchDgaariQoehCpgRltEm4zHKJyINEz6aqswTw==",
+      "requires": {
+        "@redux-saga/core": "^1.1.3"
+      }
+    },
+    "redux-thunk": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
+      "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
+    },
     "regenerate": {
       "version": "1.4.2",
       "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -36645,6 +37000,27 @@
       "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
       "peer": true
     },
+    "typescript-compare": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz",
+      "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==",
+      "requires": {
+        "typescript-logic": "^0.0.0"
+      }
+    },
+    "typescript-logic": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz",
+      "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q=="
+    },
+    "typescript-tuple": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz",
+      "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==",
+      "requires": {
+        "typescript-compare": "^0.0.2"
+      }
+    },
     "unbox-primitive": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",

+ 5 - 0
package.json

@@ -8,7 +8,12 @@
     "@testing-library/user-event": "^12.8.3",
     "react": "^17.0.2",
     "react-dom": "^17.0.2",
+    "react-redux": "^7.2.4",
     "react-scripts": "4.0.3",
+    "redux": "^4.1.1",
+    "redux-logger": "^3.0.6",
+    "redux-saga": "^1.1.3",
+    "redux-thunk": "^2.3.0",
     "web-vitals": "^1.1.2"
   },
   "scripts": {

+ 92 - 15
src/App.js

@@ -1,25 +1,102 @@
-import logo from './logo.svg';
+import React, { useState } from 'react';
+
+import { useDispatch, useSelector } from 'react-redux';
+
+import { decrease, increase } from './store/counter/actions';
+import { getFakeData, updateValue } from './store/fake/actions';
+
 import './App.css';
 
 function App() {
+
+
+  const dispatch = useDispatch();
+
+  const count = useSelector((state) => {
+    return state.counter.count;
+  });
+
+  const data = useSelector(s => s.fake.data);
+  const value = useSelector(s => s.fake.value);
+  // const isFetching = useSelector(s => s.fake.isFetching)
+
+  const onIncreaseHandler = () => {
+    dispatch(increase({ bool: 'sss'}))
+  }
+
+  const onDecreaseHandler = () => {
+    dispatch(decrease())
+  }
+
+  const onChange = (e) => {
+    dispatch(updateValue(e.target.value))
+  }
+
+  // const getVideos = () => {
+  //   // dispatch(getFakeData({ value: value }))
+  //   // requestFilms(value).then(r => r.json()).then(response => setData(response))
+  // }
+  console.log('data', data);
   return (
     <div className="App">
-      <header className="App-header">
-        <img src={logo} className="App-logo" alt="logo" />
-        <p>
-          Edit <code>src/App.js</code> and save to reload.
-        </p>
-        <a
-          className="App-link"
-          href="https://reactjs.org"
-          target="_blank"
-          rel="noopener noreferrer"
-        >
-          Learn React
-        </a>
-      </header>
+      {/* {isFetching && <span>Loading....</span>} */}
+
+      <h2>our count is: <span>{count}</span></h2>
+
+      <input type="text" value={value} onChange={onChange} />
+      {/* <button onClick={getVideos}>GET VIDEOS</button> */}
+
+      <button onClick={onIncreaseHandler}>increase</button>
+      <button onClick={onDecreaseHandler}>decrease</button>
+
+      <ul>
+        {data.length !== 0 && data.map(el => (
+          <li key={el.show.id}>{el.show.name}</li>
+        ))}
+      </ul>
+
+      {/* <ul>
+       {data.map(el => <li key={el.id}>{el.title}</li>)}
+      </ul> */}
     </div>
   );
 }
 
 export default App;
+
+// class App extends React.Component {
+//   onIncreaseHandler = () => this.props.increase()
+//   onDecreaseHandler = () => this.props.decrease()
+
+//   render() {
+//     console.log('this ', this.props)
+//     return (
+//     <div className="App">
+//       <h2>our count is: <span>{this.props.count}</span></h2>
+
+//       <button onClick={this.onIncreaseHandler}>increase</button>
+//       <button onClick={this.onDecreaseHandler}>decrease</button>
+//     </div>
+//   );
+//   }
+// }
+
+// const mapStateToProps = (state) => ({
+//   count: state.counter.count,
+// });
+
+// // const mapStateToProps = (state) => ({
+// //   count: state.counter.count,
+// // });
+
+// const dispatchActions = { decrease, increase }
+
+// // const mapDispatchToProps = (dispatch) => bindActionCreators(dispatchActions, dispatch)
+// // const mapDispatchToProps = (dispatch) => {
+// //   return {
+// //     increase: () => dispatch(increase()),
+// //     decrease: () => dispatch(decrease()),
+// //   }
+// // }
+
+// export default connect(mapStateToProps, dispatchActions)(App);

+ 5 - 0
src/index.js

@@ -1,12 +1,17 @@
 import React from 'react';
 import ReactDOM from 'react-dom';
+import { Provider } from 'react-redux';
 import './index.css';
 import App from './App';
 import reportWebVitals from './reportWebVitals';
 
+import store from './store'
+
 ReactDOM.render(
   <React.StrictMode>
+    <Provider store={store}>
     <App />
+    </Provider>
   </React.StrictMode>,
   document.getElementById('root')
 );

+ 11 - 0
src/store/counter/actions.js

@@ -0,0 +1,11 @@
+import * as types from './types';
+
+export const increase = (payload) => ({
+  type: types.INCREASE,
+  payload
+})
+
+export const decrease = (payload) => ({
+  type: types.DECREASE,
+  payload
+})

+ 20 - 0
src/store/counter/reducer.js

@@ -0,0 +1,20 @@
+import * as types from './types';
+
+const initialState = {
+  count: 0
+}
+
+export const countReducer = (state = initialState, action) => {
+  switch(action.type) {
+    case types.INCREASE: {
+      return { ...state, count: state.count + 1 }
+    }
+    case types.DECREASE: {
+      return { ...state, count: state.count - 1 }
+    }
+
+    default: {
+      return state;
+    }
+  }
+}

+ 2 - 0
src/store/counter/types.js

@@ -0,0 +1,2 @@
+export const INCREASE = 'INCREASE';
+export const DECREASE = 'DECREASE';

+ 63 - 0
src/store/fake/actions.js

@@ -0,0 +1,63 @@
+import * as types from './types';
+
+export const fakeCall = async () => {
+  const json = await fetch('https://first-fly.firebaseio.com/language.json');
+
+  const result = await json.json();
+  return result;
+}
+
+export const requestFilms = async (v) => {
+  const r = await fetch(`https://api.tvmaze.com/search/shows?q=${v}`)
+  const result = await r.json()
+
+  return result;
+}
+
+export const requestFilmsV2 = (v) => new Promise((res) => setTimeout(async() => {
+  const data = requestFilms(v);
+  res(data)
+}, 3000))
+
+export const getFakeData = (payload) => ({
+  type: types.GET_FAKE_DATA,
+  payload
+})
+
+export const getFakeDataSuccess = (payload) => ({
+  type: types.GET_FAKE_DATA_SUCCESS,
+  payload
+})
+
+export const getFakeDataFail = (payload) => ({
+  type: types.GET_FAKE_DATA_FAIL,
+  payload
+})
+
+export const fetchFakeData = (payload) => async (dispatch) => {
+  dispatch(getFakeData())
+  try {
+    const data = await fakeCall();
+
+    dispatch(getFakeDataSuccess(data))
+  } catch (error) {
+    dispatch(getFakeDataFail())
+  }
+}
+
+export const fetchFilms = ({ value }) => async (dispatch) => {
+  dispatch(getFakeData())
+  try {
+    const data = await requestFilms(value);
+
+    dispatch(getFakeDataSuccess(data))
+  } catch (error) {
+    dispatch(getFakeDataFail())
+  }
+}
+
+
+export const updateValue = (payload) => ({
+  type: types.UPDATE_VALUE,
+  payload
+})

+ 28 - 0
src/store/fake/reducer.js

@@ -0,0 +1,28 @@
+import * as types from './types';
+
+const initialState = {
+  data: [],
+  isFetching: false,
+  value: ''
+}
+
+export const fakeReducer = (state = initialState, action) => {
+  switch(action.type) {
+    case types.GET_FAKE_DATA: {
+      return { ...state, isFetching: true }
+    }
+    case types.GET_FAKE_DATA_SUCCESS: {
+      return { ...state, isFetching: false, data: action.payload }
+    }
+    case types.GET_FAKE_DATA_FAIL: {
+      return { ...state, isFetching: false }
+    }
+    case types.UPDATE_VALUE: {
+      return { ...state, value: action.payload }
+    }
+
+    default: {
+      return state;
+    }
+  }
+}

+ 34 - 0
src/store/fake/saga.js

@@ -0,0 +1,34 @@
+import { call, put, takeLatest, all, debounce, select } from 'redux-saga/effects';
+
+import * as types from './types';
+import * as actions from './actions'
+
+function* getFilms({ payload }) {
+  try {
+    const [data] = yield all([
+      call(actions.requestFilmsV2, payload.value),
+      call(actions.fakeCall, payload.value),
+    ])
+
+    yield put(actions.getFakeDataSuccess(data));
+  } catch (error) {
+    yield put(actions.getFakeDataFail());
+  }
+}
+
+function* getFilmsV2() {
+  const value = yield select(s => s.fake.value);
+  try {
+    const data = yield call(actions.requestFilms, value)
+
+    yield put(actions.getFakeDataSuccess(data));
+  } catch (error) {
+    yield put(actions.getFakeDataFail());
+  }
+}
+
+export default function* films() {
+  // yield takeEvery(types.GET_FAKE_DATA, getFilms);
+  yield takeLatest(types.GET_FAKE_DATA, getFilms);
+  yield debounce(null, types.UPDATE_VALUE, getFilmsV2);
+}

+ 5 - 0
src/store/fake/types.js

@@ -0,0 +1,5 @@
+export const GET_FAKE_DATA = 'GET_FAKE_DATA';
+export const GET_FAKE_DATA_SUCCESS = 'GET_FAKE_DATA_SUCCESS';
+export const GET_FAKE_DATA_FAIL = 'GET_FAKE_DATA_FAIL';
+
+export const UPDATE_VALUE = 'UPDATE_VALUE';

+ 29 - 0
src/store/index.js

@@ -0,0 +1,29 @@
+import { createStore, applyMiddleware } from 'redux';
+import createSagaMiddleware from 'redux-saga';
+import logger from 'redux-logger';
+import thunk from 'redux-thunk';
+
+import rootSaga from './saga';
+import { rootReducer } from './root-reducer';
+
+const sagaMiddleware = createSagaMiddleware();
+
+const middlewares = [thunk, sagaMiddleware];
+
+if (process.env.NODE_ENV === 'development') {
+  middlewares.push(logger);
+}
+
+const store = createStore(rootReducer,  applyMiddleware(...middlewares));
+
+export default store;
+
+sagaMiddleware.run(rootSaga);
+
+// const mm = (state) => (next) => (action) => {
+//   if (typeof action === 'function') {
+//     return next(state.dispatch, state.getState);
+//   }
+
+//   return next(action);
+// }

+ 13 - 0
src/store/root-reducer.js

@@ -0,0 +1,13 @@
+import { combineReducers } from 'redux';
+
+import { fakeReducer } from './fake/reducer';
+import { countReducer } from './counter/reducer';
+
+const reducers = combineReducers({
+  fake: fakeReducer,
+  counter: countReducer,
+});
+
+export const rootReducer = (state, action) => {
+  return reducers(state, action)
+}

+ 7 - 0
src/store/saga.js

@@ -0,0 +1,7 @@
+import { fork } from 'redux-saga/effects';
+
+import films from './fake/saga';
+
+export default function* rootSaga() {
+  yield fork(films)
+}