diff --git a/package-lock.json b/package-lock.json index 815af29..b7bd464 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", "@mui/icons-material": "^5.11.11", + "@mui/lab": "^5.0.0-alpha.163", "@mui/material": "^5.11.13", "@reduxjs/toolkit": "^1.9.3", "compressorjs": "^1.2.1", @@ -27,6 +28,7 @@ "react-rnd": "^10.4.1", "react-router-dom": "^6.9.0", "react-toastify": "^9.1.2", + "redux-persist": "^6.0.0", "short-unique-id": "^4.4.4", "ts-key-enum": "^2.0.12" }, @@ -355,11 +357,11 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz", - "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dependencies": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" @@ -985,6 +987,40 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "dependencies": { + "@floating-ui/utils": "^0.2.1" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.1.tgz", + "integrity": "sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.1" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", + "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "dependencies": { + "@floating-ui/dom": "^1.6.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", @@ -1067,25 +1103,24 @@ } }, "node_modules/@mui/base": { - "version": "5.0.0-beta.4", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.4.tgz", - "integrity": "sha512-ejhtqYJpjDgHGEljjMBQWZ22yEK0OzIXNa7toJmmXsP4TT3W7xVy8bTJ0TniPDf+JNjrsgfgiFTDGdlEhV1E+g==", - "dependencies": { - "@babel/runtime": "^7.21.0", - "@emotion/is-prop-valid": "^1.2.1", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.13.1", + "version": "5.0.0-beta.34", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.34.tgz", + "integrity": "sha512-e2mbTGTtReD/y5RFwnhkl1Tgl3XwgJhY040IlfkTVaU9f5LWrVhEnpRsYXu3B1CtLrwiWs4cu7aMHV9yRd4jpw==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@floating-ui/react-dom": "^2.0.8", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.7", "@popperjs/core": "^2.11.8", - "clsx": "^1.2.1", - "prop-types": "^15.8.1", - "react-is": "^18.2.0" + "clsx": "^2.1.0", + "prop-types": "^15.8.1" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", @@ -1098,13 +1133,21 @@ } } }, + "node_modules/@mui/base/node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.13.4", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.13.4.tgz", - "integrity": "sha512-yFrMWcrlI0TqRN5jpb6Ma9iI7sGTHpytdzzL33oskFHNQ8UgrtPas33Y1K7sWAMwCrr1qbWDrOHLAQG4tAzuSw==", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.7.tgz", + "integrity": "sha512-AuF+Wo2Mp/edaO6vJnWjg+gj4tzEz5ChMZnAQpc22DXpSvM8ddgGcZvM7D7F99pIBoSv8ub+Iz0viL+yuGVmhg==", "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { @@ -1132,19 +1175,67 @@ } } }, + "node_modules/@mui/lab": { + "version": "5.0.0-alpha.163", + "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.163.tgz", + "integrity": "sha512-ieOX3LFBln78jgNsBca0JUX+zAC2p6/u2P9b7rU9eZIr0AK44b5Qr8gDOWI1JfJtib4kxLGd1Msasrbxy5cMSQ==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.34", + "@mui/system": "^5.15.7", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.7", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material": ">=5.15.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/lab/node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, "node_modules/@mui/material": { - "version": "5.13.5", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.13.5.tgz", - "integrity": "sha512-eMay+Ue1OYXOFMQA5Aau7qbAa/kWHLAyi0McsbPTWssCbGehqkF6CIdPsfVGw6tlO+xPee1hUitphHJNL3xpOQ==", - "dependencies": { - "@babel/runtime": "^7.21.0", - "@mui/base": "5.0.0-beta.4", - "@mui/core-downloads-tracker": "^5.13.4", - "@mui/system": "^5.13.5", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.13.1", - "@types/react-transition-group": "^4.4.6", - "clsx": "^1.2.1", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.7.tgz", + "integrity": "sha512-l6+AiKZH3iOJmZCnlpel8ghYQe9Lq0BEuKP8fGj3g5xz4arO9GydqYAtLPMvuHKtArj8lJGNuT2yHYxmejincA==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.34", + "@mui/core-downloads-tracker": "^5.15.7", + "@mui/system": "^5.15.7", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.7", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.1.0", "csstype": "^3.1.2", "prop-types": "^15.8.1", "react-is": "^18.2.0", @@ -1155,7 +1246,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.5.0", @@ -1176,13 +1267,21 @@ } } }, + "node_modules/@mui/material/node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, "node_modules/@mui/private-theming": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.13.1.tgz", - "integrity": "sha512-HW4npLUD9BAkVppOUZHeO1FOKUJWAwbpy0VQoGe3McUYTlck1HezGHQCfBQ5S/Nszi7EViqiimECVl9xi+/WjQ==", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.7.tgz", + "integrity": "sha512-bcEeeXm7GyQCQvN9dwo8htGv8/6tP05p0i02Z7GXm5EoDPlBcqTNGugsjNLoGq6B0SsdyanjJGw0Jw00o1yAOA==", "dependencies": { - "@babel/runtime": "^7.21.0", - "@mui/utils": "^5.13.1", + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.15.7", "prop-types": "^15.8.1" }, "engines": { @@ -1190,7 +1289,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", @@ -1203,11 +1302,11 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.13.2", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.13.2.tgz", - "integrity": "sha512-VCYCU6xVtXOrIN8lcbuPmoG+u7FYuOERG++fpY74hPpEWkyFQG97F+/XfTQVYzlR2m7nPjnwVUgATcTCMEaMvw==", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.7.tgz", + "integrity": "sha512-ixSdslOjK1kzdGcxqj7O3d14By/LPQ7EWknsViQ8RaeT863EAQemS+zvUJDTcOpkfJh6q6gPnYMIb2TJCs9eWA==", "dependencies": { - "@babel/runtime": "^7.21.0", + "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.11.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -1217,7 +1316,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.4.1", @@ -1234,16 +1333,16 @@ } }, "node_modules/@mui/system": { - "version": "5.13.5", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.13.5.tgz", - "integrity": "sha512-n0gzUxoZ2ZHZgnExkh2Htvo9uW2oakofgPRQrDoa/GQOWyRD0NH9MDszBwOb6AAoXZb+OV5TE7I4LeZ/dzgHYA==", - "dependencies": { - "@babel/runtime": "^7.21.0", - "@mui/private-theming": "^5.13.1", - "@mui/styled-engine": "^5.13.2", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.13.1", - "clsx": "^1.2.1", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.7.tgz", + "integrity": "sha512-9alZ4/dLxsTwUOdqakgzxiL5YW6ntqj0CfzWImgWnBMTZhgGcPsbYpBLniNkkk7/jptma4/bykWXHwju/ls/pg==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.15.7", + "@mui/styled-engine": "^5.15.7", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.7", + "clsx": "^2.1.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" }, @@ -1252,7 +1351,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.5.0", @@ -1272,12 +1371,20 @@ } } }, + "node_modules/@mui/system/node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, "node_modules/@mui/types": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz", - "integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==", + "version": "7.2.13", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.13.tgz", + "integrity": "sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==", "peerDependencies": { - "@types/react": "*" + "@types/react": "^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -1286,13 +1393,12 @@ } }, "node_modules/@mui/utils": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.13.1.tgz", - "integrity": "sha512-6lXdWwmlUbEU2jUI8blw38Kt+3ly7xkmV9ljzY4Q20WhsJMWiNry9CX8M+TaP/HbtuyR8XKsdMgQW7h7MM3n3A==", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.7.tgz", + "integrity": "sha512-8qhsxQRNV6aEOjjSk6YQIYJxkF5klhj8oG1FEEU4z6HV78TjNqRxMP08QGcdsibEbez+nihAaz6vu83b4XqbAg==", "dependencies": { - "@babel/runtime": "^7.21.0", - "@types/prop-types": "^15.7.5", - "@types/react-is": "^18.2.0", + "@babel/runtime": "^7.23.9", + "@types/prop-types": "^15.7.11", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -1301,10 +1407,16 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/@nodelib/fs.scandir": { @@ -1619,9 +1731,9 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "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==" + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/quill": { "version": "1.3.10", @@ -1650,18 +1762,10 @@ "@types/react": "*" } }, - "node_modules/@types/react-is": { - "version": "18.2.1", - "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.1.tgz", - "integrity": "sha512-wyUkmaaSZEzFZivD8F2ftSyAfk6L+DfFliVj/mYdOXbVjRcS87fQJLTnhk6dRZPuJjI+9g6RZJO4PNCngUrmyw==", - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/react-transition-group": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz", - "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==", + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", "dependencies": { "@types/react": "*" } @@ -3988,6 +4092,14 @@ "@babel/runtime": "^7.9.2" } }, + "node_modules/redux-persist": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz", + "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==", + "peerDependencies": { + "redux": ">4.0.0" + } + }, "node_modules/redux-thunk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", @@ -3997,9 +4109,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/regexp.prototype.flags": { "version": "1.5.1", @@ -4782,11 +4894,11 @@ } }, "@babel/runtime": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz", - "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "requires": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" } }, "@babel/template": { @@ -5152,6 +5264,36 @@ "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", "dev": true }, + "@floating-ui/core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "requires": { + "@floating-ui/utils": "^0.2.1" + } + }, + "@floating-ui/dom": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.1.tgz", + "integrity": "sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ==", + "requires": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.1" + } + }, + "@floating-ui/react-dom": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", + "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "requires": { + "@floating-ui/dom": "^1.6.1" + } + }, + "@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, "@humanwhocodes/config-array": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", @@ -5215,24 +5357,30 @@ } }, "@mui/base": { - "version": "5.0.0-beta.4", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.4.tgz", - "integrity": "sha512-ejhtqYJpjDgHGEljjMBQWZ22yEK0OzIXNa7toJmmXsP4TT3W7xVy8bTJ0TniPDf+JNjrsgfgiFTDGdlEhV1E+g==", - "requires": { - "@babel/runtime": "^7.21.0", - "@emotion/is-prop-valid": "^1.2.1", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.13.1", + "version": "5.0.0-beta.34", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.34.tgz", + "integrity": "sha512-e2mbTGTtReD/y5RFwnhkl1Tgl3XwgJhY040IlfkTVaU9f5LWrVhEnpRsYXu3B1CtLrwiWs4cu7aMHV9yRd4jpw==", + "requires": { + "@babel/runtime": "^7.23.9", + "@floating-ui/react-dom": "^2.0.8", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.7", "@popperjs/core": "^2.11.8", - "clsx": "^1.2.1", - "prop-types": "^15.8.1", - "react-is": "^18.2.0" + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "dependencies": { + "clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==" + } } }, "@mui/core-downloads-tracker": { - "version": "5.13.4", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.13.4.tgz", - "integrity": "sha512-yFrMWcrlI0TqRN5jpb6Ma9iI7sGTHpytdzzL33oskFHNQ8UgrtPas33Y1K7sWAMwCrr1qbWDrOHLAQG4tAzuSw==" + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.7.tgz", + "integrity": "sha512-AuF+Wo2Mp/edaO6vJnWjg+gj4tzEz5ChMZnAQpc22DXpSvM8ddgGcZvM7D7F99pIBoSv8ub+Iz0viL+yuGVmhg==" }, "@mui/icons-material": { "version": "5.11.16", @@ -5242,75 +5390,109 @@ "@babel/runtime": "^7.21.0" } }, + "@mui/lab": { + "version": "5.0.0-alpha.163", + "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.163.tgz", + "integrity": "sha512-ieOX3LFBln78jgNsBca0JUX+zAC2p6/u2P9b7rU9eZIr0AK44b5Qr8gDOWI1JfJtib4kxLGd1Msasrbxy5cMSQ==", + "requires": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.34", + "@mui/system": "^5.15.7", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.7", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "dependencies": { + "clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==" + } + } + }, "@mui/material": { - "version": "5.13.5", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.13.5.tgz", - "integrity": "sha512-eMay+Ue1OYXOFMQA5Aau7qbAa/kWHLAyi0McsbPTWssCbGehqkF6CIdPsfVGw6tlO+xPee1hUitphHJNL3xpOQ==", - "requires": { - "@babel/runtime": "^7.21.0", - "@mui/base": "5.0.0-beta.4", - "@mui/core-downloads-tracker": "^5.13.4", - "@mui/system": "^5.13.5", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.13.1", - "@types/react-transition-group": "^4.4.6", - "clsx": "^1.2.1", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.7.tgz", + "integrity": "sha512-l6+AiKZH3iOJmZCnlpel8ghYQe9Lq0BEuKP8fGj3g5xz4arO9GydqYAtLPMvuHKtArj8lJGNuT2yHYxmejincA==", + "requires": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.34", + "@mui/core-downloads-tracker": "^5.15.7", + "@mui/system": "^5.15.7", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.7", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.1.0", "csstype": "^3.1.2", "prop-types": "^15.8.1", "react-is": "^18.2.0", "react-transition-group": "^4.4.5" + }, + "dependencies": { + "clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==" + } } }, "@mui/private-theming": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.13.1.tgz", - "integrity": "sha512-HW4npLUD9BAkVppOUZHeO1FOKUJWAwbpy0VQoGe3McUYTlck1HezGHQCfBQ5S/Nszi7EViqiimECVl9xi+/WjQ==", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.7.tgz", + "integrity": "sha512-bcEeeXm7GyQCQvN9dwo8htGv8/6tP05p0i02Z7GXm5EoDPlBcqTNGugsjNLoGq6B0SsdyanjJGw0Jw00o1yAOA==", "requires": { - "@babel/runtime": "^7.21.0", - "@mui/utils": "^5.13.1", + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.15.7", "prop-types": "^15.8.1" } }, "@mui/styled-engine": { - "version": "5.13.2", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.13.2.tgz", - "integrity": "sha512-VCYCU6xVtXOrIN8lcbuPmoG+u7FYuOERG++fpY74hPpEWkyFQG97F+/XfTQVYzlR2m7nPjnwVUgATcTCMEaMvw==", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.7.tgz", + "integrity": "sha512-ixSdslOjK1kzdGcxqj7O3d14By/LPQ7EWknsViQ8RaeT863EAQemS+zvUJDTcOpkfJh6q6gPnYMIb2TJCs9eWA==", "requires": { - "@babel/runtime": "^7.21.0", + "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.11.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" } }, "@mui/system": { - "version": "5.13.5", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.13.5.tgz", - "integrity": "sha512-n0gzUxoZ2ZHZgnExkh2Htvo9uW2oakofgPRQrDoa/GQOWyRD0NH9MDszBwOb6AAoXZb+OV5TE7I4LeZ/dzgHYA==", - "requires": { - "@babel/runtime": "^7.21.0", - "@mui/private-theming": "^5.13.1", - "@mui/styled-engine": "^5.13.2", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.13.1", - "clsx": "^1.2.1", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.15.7.tgz", + "integrity": "sha512-9alZ4/dLxsTwUOdqakgzxiL5YW6ntqj0CfzWImgWnBMTZhgGcPsbYpBLniNkkk7/jptma4/bykWXHwju/ls/pg==", + "requires": { + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.15.7", + "@mui/styled-engine": "^5.15.7", + "@mui/types": "^7.2.13", + "@mui/utils": "^5.15.7", + "clsx": "^2.1.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" + }, + "dependencies": { + "clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==" + } } }, "@mui/types": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz", - "integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==", + "version": "7.2.13", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.13.tgz", + "integrity": "sha512-qP9OgacN62s+l8rdDhSFRe05HWtLLJ5TGclC9I1+tQngbssu0m2dmFZs+Px53AcOs9fD7TbYd4gc9AXzVqO/+g==", "requires": {} }, "@mui/utils": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.13.1.tgz", - "integrity": "sha512-6lXdWwmlUbEU2jUI8blw38Kt+3ly7xkmV9ljzY4Q20WhsJMWiNry9CX8M+TaP/HbtuyR8XKsdMgQW7h7MM3n3A==", + "version": "5.15.7", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.15.7.tgz", + "integrity": "sha512-8qhsxQRNV6aEOjjSk6YQIYJxkF5klhj8oG1FEEU4z6HV78TjNqRxMP08QGcdsibEbez+nihAaz6vu83b4XqbAg==", "requires": { - "@babel/runtime": "^7.21.0", - "@types/prop-types": "^15.7.5", - "@types/react-is": "^18.2.0", + "@babel/runtime": "^7.23.9", + "@types/prop-types": "^15.7.11", "prop-types": "^15.8.1", "react-is": "^18.2.0" } @@ -5521,9 +5703,9 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "@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==" + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "@types/quill": { "version": "1.3.10", @@ -5552,18 +5734,10 @@ "@types/react": "*" } }, - "@types/react-is": { - "version": "18.2.1", - "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.1.tgz", - "integrity": "sha512-wyUkmaaSZEzFZivD8F2ftSyAfk6L+DfFliVj/mYdOXbVjRcS87fQJLTnhk6dRZPuJjI+9g6RZJO4PNCngUrmyw==", - "requires": { - "@types/react": "*" - } - }, "@types/react-transition-group": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz", - "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==", + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", "requires": { "@types/react": "*" } @@ -7206,6 +7380,12 @@ "@babel/runtime": "^7.9.2" } }, + "redux-persist": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz", + "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==", + "requires": {} + }, "redux-thunk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", @@ -7213,9 +7393,9 @@ "requires": {} }, "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "regexp.prototype.flags": { "version": "1.5.1", diff --git a/package.json b/package.json index a5554aa..ba7d281 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", "@mui/icons-material": "^5.11.11", + "@mui/lab": "^5.0.0-alpha.163", "@mui/material": "^5.11.13", "@reduxjs/toolkit": "^1.9.3", "compressorjs": "^1.2.1", @@ -29,6 +30,7 @@ "react-rnd": "^10.4.1", "react-router-dom": "^6.9.0", "react-toastify": "^9.1.2", + "redux-persist": "^6.0.0", "short-unique-id": "^4.4.4", "ts-key-enum": "^2.0.12" }, diff --git a/src/App.tsx b/src/App.tsx index ae2cbe0..1c7c968 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,28 +12,36 @@ import { VideoContent } from "./pages/VideoContent/VideoContent"; import DownloadWrapper from "./wrappers/DownloadWrapper"; import { IndividualProfile } from "./pages/IndividualProfile/IndividualProfile"; import { PlaylistContent } from "./pages/PlaylistContent/PlaylistContent"; +import { PersistGate } from "redux-persist/integration/react"; +import { persistStore } from "redux-persist"; function App() { // const themeColor = window._qdnTheme const [theme, setTheme] = useState("dark"); + let persistor = persistStore(store); return ( - - - - setTheme(val)}> - - - } /> - } /> - } /> - } /> - - - - + + + + + setTheme(val)}> + + + } /> + } /> + } + /> + } /> + + + + + ); } diff --git a/src/components/common/SubscribeButton.tsx b/src/components/common/SubscribeButton.tsx index 20119a2..273ce8d 100644 --- a/src/components/common/SubscribeButton.tsx +++ b/src/components/common/SubscribeButton.tsx @@ -1,21 +1,42 @@ import { Button, ButtonProps } from "@mui/material"; -import { MouseEvent } from "react"; +import { MouseEvent, useEffect, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "../../state/store.ts"; +import { subscribe, unSubscribe } from "../../state/features/persistSlice.ts"; interface SubscribeButtonProps extends ButtonProps { name: string; } -const isSubscribed = false; export const SubscribeButton = ({ name, ...props }: SubscribeButtonProps) => { + const dispatch = useDispatch(); + const persistSelector = useSelector((state: RootState) => { + return state.persist; + }); + const [isSubscribed, setIsSubscribed] = useState(false); + + useEffect(() => { + setIsSubscribed(persistSelector.subscriptionList.includes(name)); + }, []); + + const subscribeToRedux = () => { + dispatch(subscribe(name)); + setIsSubscribed(true); + }; + const unSubscribeFromRedux = () => { + dispatch(unSubscribe(name)); + setIsSubscribed(false); + }; + const manageSubscription = (e: MouseEvent) => { e.preventDefault(); e.stopPropagation(); - console.log("subscribed to: ", name); + isSubscribed ? unSubscribeFromRedux() : subscribeToRedux(); }; + const verticalPadding = "3px"; const horizontalPadding = "8px"; const buttonStyle = { - ...props.sx, fontSize: "15px", fontWeight: "700", paddingTop: verticalPadding, @@ -23,7 +44,8 @@ export const SubscribeButton = ({ name, ...props }: SubscribeButtonProps) => { paddingLeft: horizontalPadding, paddingRight: horizontalPadding, borderRadius: 28, - display: "none", + height: "45px", + ...props.sx, }; return ( + + + + + + + + + + + + + + + + + + {persistSelector.subscriptionList.length > 0 ? ( + <> + + + + ) : ( +
+ You have no subscriptions +
+ )} +
+
+
+
+
+ + + + + ); +}; diff --git a/src/pages/Home/VideoList-styles.tsx b/src/pages/Home/VideoList-styles.tsx index 52fb11f..1b86aa0 100644 --- a/src/pages/Home/VideoList-styles.tsx +++ b/src/pages/Home/VideoList-styles.tsx @@ -7,6 +7,7 @@ import { TextField, InputLabel, Autocomplete, + Radio, } from "@mui/material"; export const VideoContainer = styled(Grid)(({ theme }) => ({ @@ -131,7 +132,7 @@ export const VideoCardTitle = styled(DoubleLine)(({ theme }) => ({ })); export const VideoCardName = styled(Typography)(({ theme }) => ({ fontFamily: "Cairo", - fontSize: "18px", + fontSize: "16px", letterSpacing: "0.4px", color: theme.palette.text.primary, userSelect: "none", @@ -195,7 +196,7 @@ export const NameContainer = styled(Box)(({ theme }) => ({ justifyContent: "flex-start", alignItems: "center", gap: "10px", - marginBottom: "10px", + marginBottom: "2px", })); export const MyStoresCard = styled(Box)(({ theme }) => ({ @@ -270,6 +271,13 @@ export const FiltersCheckbox = styled(Checkbox)(({ theme }) => ({ }, })); +export const FiltersRadioButton = styled(Radio)(({ theme }) => ({ + color: "#c0d4ff", + "&.Mui-checked": { + color: "#6596ff", + }, +})); + export const FilterSelect = styled(Autocomplete)(({ theme }) => ({ "& #categories-select": { padding: "7px", diff --git a/src/pages/Home/VideoList.tsx b/src/pages/Home/VideoList.tsx index 146c7f6..6ce0729 100644 --- a/src/pages/Home/VideoList.tsx +++ b/src/pages/Home/VideoList.tsx @@ -1,276 +1,50 @@ -import React, { useCallback, useEffect, useRef, useState } from "react"; -import { useNavigate } from "react-router-dom"; -import ReactDOM from "react-dom"; -import { useSelector, useDispatch } from "react-redux"; -import { RootState } from "../../state/store"; -import { - Avatar, - Box, - Button, - FormControl, - Grid, - Input, - InputLabel, - MenuItem, - OutlinedInput, - Select, - SelectChangeEvent, - Tooltip, - Typography, - useTheme, -} from "@mui/material"; -import { useFetchVideos } from "../../hooks/useFetchVideos"; -import LazyLoad from "../../components/common/LazyLoad"; import { BlockIconContainer, BottomParent, - FilterSelect, - FiltersCheckbox, - FiltersCol, - FiltersContainer, - FiltersRow, - FiltersSubContainer, - FiltersTitle, IconsBox, NameContainer, + VideoCard, VideoCardCol, - ProductManagerRow, VideoCardContainer, - VideoCard, VideoCardName, VideoCardTitle, - VideoContainer, VideoUploadDate, -} from "./VideoList-styles"; -import ResponsiveImage from "../../components/ResponsiveImage"; -import { formatDate, formatTimestampSeconds } from "../../utils/time"; -import { Subtitle, SubtitleContainer } from "./Home-styles"; -import { ExpandMoreSVG } from "../../assets/svgs/ExpandMoreSVG"; +} from "./VideoList-styles.tsx"; +import { Avatar, Box, Tooltip, useTheme } from "@mui/material"; +import EditIcon from "@mui/icons-material/Edit"; import { - addVideos, blockUser, - changeFilterType, - changeSelectedCategoryVideos, - changeSelectedSubCategoryVideos, - changefilterName, - changefilterSearch, - clearVideoList, setEditPlaylist, setEditVideo, -} from "../../state/features/videoSlice"; -import { categories, subCategories } from "../../constants/Categories.ts"; -import { Playlists } from "../../components/Playlists/Playlists"; -import { PlaylistSVG } from "../../assets/svgs/PlaylistSVG"; +} from "../../state/features/videoSlice.ts"; import BlockIcon from "@mui/icons-material/Block"; -import EditIcon from "@mui/icons-material/Edit"; -import { ListSuperLikeContainer } from "../../components/common/ListSuperLikes/ListSuperLikeContainer.tsx"; -import { VideoCardImageContainer } from "./VideoCardImageContainer"; -import { SubscribeButton } from "../../components/common/SubscribeButton.tsx"; - +import ResponsiveImage from "../../components/ResponsiveImage.tsx"; +import { formatDate } from "../../utils/time.ts"; +import { PlaylistSVG } from "../../assets/svgs/PlaylistSVG.tsx"; +import { VideoCardImageContainer } from "./VideoCardImageContainer.tsx"; +import React, { useState } from "react"; +import { Video } from "../../state/features/videoSlice.ts"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "../../state/store.ts"; +import { useNavigate } from "react-router-dom"; interface VideoListProps { - mode?: string; + videos: Video[]; } -export const VideoList = ({ mode }: VideoListProps) => { - const theme = useTheme(); - const prevVal = useRef(""); - const isFiltering = useSelector( - (state: RootState) => state.video.isFiltering - ); - const filterValue = useSelector( - (state: RootState) => state.video.filterValue - ); - const [isLoading, setIsLoading] = useState(false); +export const VideoList = ({ videos }: VideoListProps) => { const [showIcons, setShowIcons] = useState(null); - const filterType = useSelector((state: RootState) => state.video.filterType); - - const setFilterType = payload => { - dispatch(changeFilterType(payload)); - }; - const filterSearch = useSelector( - (state: RootState) => state.video.filterSearch - ); - - const setFilterSearch = payload => { - dispatch(changefilterSearch(payload)); - }; - const filterName = useSelector((state: RootState) => state.video.filterName); - - const setFilterName = payload => { - dispatch(changefilterName(payload)); - }; - - const selectedCategoryVideos = useSelector( - (state: RootState) => state.video.selectedCategoryVideos - ); - - const setSelectedCategoryVideos = payload => { - dispatch(changeSelectedCategoryVideos(payload)); - }; - const selectedSubCategoryVideos = useSelector( - (state: RootState) => state.video.selectedSubCategoryVideos - ); - - const setSelectedSubCategoryVideos = payload => { - dispatch(changeSelectedSubCategoryVideos(payload)); - }; - - const dispatch = useDispatch(); - const filteredVideos = useSelector( - (state: RootState) => state.video.filteredVideos - ); - const username = useSelector((state: RootState) => state.auth?.user?.name); - const isFilterMode = useRef(false); - const firstFetch = useRef(false); - const afterFetch = useRef(false); - const isFetchingFiltered = useRef(false); - const isFetching = useRef(false); const hashMapVideos = useSelector( (state: RootState) => state.video.hashMapVideos ); - const countNewVideos = useSelector( - (state: RootState) => state.video.countNewVideos - ); const userAvatarHash = useSelector( (state: RootState) => state.global.userAvatarHash ); + const username = useSelector((state: RootState) => state.auth?.user?.name); - const { videos: globalVideos } = useSelector( - (state: RootState) => state.video - ); const navigate = useNavigate(); - const { getVideos, getNewVideos, checkNewVideos, getVideosFiltered } = - useFetchVideos(); - - const getVideosHandler = React.useCallback( - async (reset?: boolean, resetFilers?: boolean) => { - if (!firstFetch.current || !afterFetch.current) return; - if (isFetching.current) return; - isFetching.current = true; - await getVideos( - { - name: filterName, - category: selectedCategoryVideos?.id, - subcategory: selectedSubCategoryVideos?.id, - keywords: filterSearch, - type: filterType, - }, - reset ? true : false, - resetFilers - ); - isFetching.current = false; - }, - [ - getVideos, - filterValue, - getVideosFiltered, - isFiltering, - filterName, - selectedCategoryVideos, - selectedSubCategoryVideos, - filterSearch, - filterType, - ] - ); - - useEffect(() => { - if (isFiltering && filterValue !== prevVal?.current) { - prevVal.current = filterValue; - getVideosHandler(); - } - }, [filterValue, isFiltering, filteredVideos]); - - const getVideosHandlerMount = React.useCallback(async () => { - if (firstFetch.current) return; - firstFetch.current = true; - setIsLoading(true); - - await getVideos(); - afterFetch.current = true; - isFetching.current = false; - - setIsLoading(false); - }, [getVideos]); - - let videos = globalVideos; - - if (isFiltering) { - videos = filteredVideos; - isFilterMode.current = true; - } else { - isFilterMode.current = false; - } - - // const interval = useRef(null); - - // const checkNewVideosFunc = useCallback(() => { - // let isCalling = false; - // interval.current = setInterval(async () => { - // if (isCalling || !firstFetch.current) return; - // isCalling = true; - // await checkNewVideos(); - // isCalling = false; - // }, 30000); // 1 second interval - // }, [checkNewVideos]); - - // useEffect(() => { - // if (isFiltering && interval.current) { - // clearInterval(interval.current); - // return; - // } - // checkNewVideosFunc(); - - // return () => { - // if (interval?.current) { - // clearInterval(interval.current); - // } - // }; - // }, [mode, checkNewVideosFunc, isFiltering]); - - useEffect(() => { - if ( - !firstFetch.current && - !isFilterMode.current && - globalVideos.length === 0 - ) { - isFetching.current = true; - getVideosHandlerMount(); - } else { - firstFetch.current = true; - afterFetch.current = true; - } - }, [getVideosHandlerMount, globalVideos]); - - const filtersToDefault = async () => { - setFilterType("videos"); - setFilterSearch(""); - setFilterName(""); - setSelectedCategoryVideos(null); - setSelectedSubCategoryVideos(null); - - ReactDOM.flushSync(() => { - getVideosHandler(true, true); - }); - }; - - const handleOptionCategoryChangeVideos = ( - event: SelectChangeEvent - ) => { - const optionId = event.target.value; - const selectedOption = categories.find(option => option.id === +optionId); - setSelectedCategoryVideos(selectedOption || null); - }; - const handleOptionSubCategoryChangeVideos = ( - event: SelectChangeEvent, - subcategories: any[] - ) => { - const optionId = event.target.value; - const selectedOption = subcategories.find( - option => option.id === +optionId - ); - setSelectedSubCategoryVideos(selectedOption || null); - }; + const dispatch = useDispatch(); + const theme = useTheme(); const blockUserFunc = async (user: string) => { if (user === "Q-Tube") return; @@ -288,483 +62,226 @@ export const VideoList = ({ mode }: VideoListProps) => { } catch (error) {} }; - const handleInputKeyDown = (event: any) => { - if (event.key === "Enter") { - getVideosHandler(true); - } - }; - return ( - - - - { - setFilterSearch(e.target.value); - }} - value={filterSearch} - placeholder="Search" - onKeyDown={handleInputKeyDown} - sx={{ - borderBottom: "1px solid white", - "&&:before": { - borderBottom: "none", - }, - "&&:after": { - borderBottom: "none", - }, - "&&:hover:before": { - borderBottom: "none", - }, - "&&.Mui-focused:before": { - borderBottom: "none", - }, - "&&.Mui-focused": { - outline: "none", - }, - fontSize: "18px", - }} - /> - { - setFilterName(e.target.value); - }} - value={filterName} - placeholder="User's Name (Exact)" - onKeyDown={handleInputKeyDown} - sx={{ - marginTop: "20px", - borderBottom: "1px solid white", - "&&:before": { - borderBottom: "none", - }, - "&&:after": { - borderBottom: "none", - }, - "&&:hover:before": { - borderBottom: "none", - }, - "&&.Mui-focused:before": { - borderBottom: "none", - }, - "&&.Mui-focused": { - outline: "none", - }, - fontSize: "18px", - }} - /> - - Categories - - - - - + {videos.map((video: any) => { + const fullId = video ? `${video.id}-${video.user}` : undefined; + const existingVideo = hashMapVideos[fullId]; + let hasHash = false; + let videoObj = video; + if (existingVideo) { + videoObj = existingVideo; + hasHash = true; + } + + let avatarUrl = ""; + if (userAvatarHash[videoObj?.user]) { + avatarUrl = userAvatarHash[videoObj?.user]; + } + + // nb. this prevents showing metadata for a video which + // belongs to a different user + if ( + videoObj?.user && + videoObj?.videoReference?.name && + videoObj.user != videoObj.videoReference.name + ) { + return null; + } + + if (hasHash && !videoObj?.videoImage && !videoObj?.image) { + return null; + } + const isPlaylist = videoObj?.service === "PLAYLIST"; + + if (isPlaylist) { + return ( + setShowIcons(videoObj.id)} + onMouseLeave={() => setShowIcons(null)} + key={videoObj.id} + > + - - + + { + dispatch(setEditPlaylist(videoObj)); + }} + /> + + + )} + + + + { + blockUserFunc(videoObj?.user); + }} + /> + + + + { + if (!hasHash) return; + navigate(`/playlist/${videoObj?.user}/${videoObj?.id}`); + }} + > + + {videoObj?.title} + + { + e.stopPropagation(); + navigate(`/channel/${videoObj?.user}`); }} - id="Category" > - Category - - - - {selectedCategoryVideos && - subCategories[selectedCategoryVideos?.id] && ( - - - Sub-Category - - - - )} - - - - - Type - - - - - Videos - ) => { - setFilterType("videos"); - }} - inputProps={{ "aria-label": "controlled" }} - /> - - - Playlists - ) => { - setFilterType("playlists"); - }} - inputProps={{ "aria-label": "controlled" }} - /> - - - - - - - - - - - - - {videos.map((video: any, index: number) => { - const fullId = video ? `${video.id}-${video.user}` : undefined; - const existingVideo = hashMapVideos[fullId]; - let hasHash = false; - let videoObj = video; - if (existingVideo) { - videoObj = existingVideo; - hasHash = true; - } - - let avatarUrl = ""; - if (userAvatarHash[videoObj?.user]) { - avatarUrl = userAvatarHash[videoObj?.user]; - } - - // nb. this prevents showing metadata for a video which - // belongs to a different user - if (videoObj?.user && videoObj?.videoReference?.name - && videoObj.user != videoObj.videoReference.name) { - return null; - } - - if (hasHash && !videoObj?.videoImage && !videoObj?.image) { - return null; - } - const isPlaylist = videoObj?.service === "PLAYLIST"; - - if (isPlaylist) { - return ( - setShowIcons(videoObj.id)} - onMouseLeave={() => setShowIcons(null)} - key={videoObj.id} - > - - {videoObj?.user === username && ( - - - { - dispatch(setEditPlaylist(videoObj)); - }} - /> - - - )} - - - - { - blockUserFunc(videoObj?.user); - }} - /> - - - - { - if (!hasHash) return; - navigate( - `/playlist/${videoObj?.user}/${videoObj?.id}` - ); - }} - > - - {videoObj?.title} - - { - e.stopPropagation(); - navigate(`/channel/${videoObj?.user}`); - }} - > - - - {videoObj?.user} - - - {videoObj?.created && ( - - {formatDate(videoObj.created)} - - )} - - - - - - - - ); - } - - return ( - setShowIcons(videoObj.id)} - onMouseLeave={() => setShowIcons(null)} - > - - {videoObj?.user === username && ( - - - { - dispatch(setEditVideo(videoObj)); - }} - /> - - - )} - - - - { - blockUserFunc(videoObj?.user); - }} - /> - - - - + {videoObj?.user === username && ( + + + { - navigate(`/video/${videoObj?.user}/${videoObj?.id}`); + dispatch(setEditVideo(videoObj)); }} - > - - {/* + + + )} + + + + { + blockUserFunc(videoObj?.user); + }} + /> + + + + { + navigate(`/video/${videoObj?.user}/${videoObj?.id}`); + }} + > + + {/* */} - {videoObj.title} - - { - e.stopPropagation(); - navigate(`/channel/${videoObj?.user}`); - }} - > - - - {videoObj?.user} - - - - {videoObj?.created && ( - - {formatDate(videoObj.created)} - - )} - - - - ); - })} - - - - - - - - - - + {videoObj.title} + + { + e.stopPropagation(); + navigate(`/channel/${videoObj?.user}`); + }} + > + + + {videoObj?.user} + + + {videoObj?.created && ( + + + {formatDate(videoObj.created)} + + + )} + + + + ); + })} + ); }; + +export default VideoList; diff --git a/src/pages/PlaylistContent/PlaylistContent.tsx b/src/pages/PlaylistContent/PlaylistContent.tsx index c8c7718..cffeb30 100644 --- a/src/pages/PlaylistContent/PlaylistContent.tsx +++ b/src/pages/PlaylistContent/PlaylistContent.tsx @@ -9,7 +9,7 @@ import { useDispatch, useSelector } from "react-redux"; import { useNavigate, useParams } from "react-router-dom"; import { setIsLoadingGlobal } from "../../state/features/globalSlice"; import { Avatar, Box, Typography, useTheme } from "@mui/material"; -import { VideoPlayer } from "../../components/common/VideoPlayer"; +import { VideoPlayer } from "../../components/common/VideoPlayer/VideoPlayer.tsx"; import { RootState } from "../../state/store"; import { addToHashMap } from "../../state/features/videoSlice"; import AttachFileIcon from "@mui/icons-material/AttachFile"; @@ -440,6 +440,7 @@ export const PlaylistContent = () => { nextVideo={nextVideo} onEnd={onEndVideo} autoPlay={doAutoPlay} + customStyle={{ aspectRatio: "16/9" }} /> )} {playlistData && ( diff --git a/src/pages/VideoContent/VideoContent.tsx b/src/pages/VideoContent/VideoContent.tsx index a526b1b..b50735f 100644 --- a/src/pages/VideoContent/VideoContent.tsx +++ b/src/pages/VideoContent/VideoContent.tsx @@ -9,7 +9,7 @@ import { useDispatch, useSelector } from "react-redux"; import { useNavigate, useParams } from "react-router-dom"; import { setIsLoadingGlobal } from "../../state/features/globalSlice"; import { Avatar, Box, Typography, useTheme } from "@mui/material"; -import { VideoPlayer } from "../../components/common/VideoPlayer"; +import { VideoPlayer } from "../../components/common/VideoPlayer/VideoPlayer.tsx"; import { RootState } from "../../state/store"; import { addToHashMap } from "../../state/features/videoSlice"; import AttachFileIcon from "@mui/icons-material/AttachFile"; @@ -52,7 +52,10 @@ import { QTUBE_VIDEO_BASE, SUPER_LIKE_BASE, } from "../../constants/Identifiers.ts"; -import { minPriceSuperlike } from "../../constants/Misc.ts"; +import { + minPriceSuperlike, + titleFormatterOnSave, +} from "../../constants/Misc.ts"; import { SubscribeButton } from "../../components/common/SubscribeButton.tsx"; export function isTimestampWithinRange(resTimestamp, resCreated) { @@ -186,12 +189,12 @@ export const VideoContent = () => { } } - return videoData.title + ext; + return (videoData.title + ext).replace(titleFormatterOnSave, ""); } // otherwise use QDN filename if applicable if (videoData?.filename) { - return videoData.filename; + return videoData.filename.replace(titleFormatterOnSave, ""); } // TODO: this was the previous value, leaving here as the @@ -360,6 +363,9 @@ export const VideoContent = () => { if (!nameAddress || !id) return; getComments(id, nameAddress); }, [getComments, id, nameAddress]); + const subList = useSelector( + (state: RootState) => state.video.subscriptionList + ); return ( { sx={{ marginBottom: "30px", width: "70vw", - height: "70vw", }} > {videoReference && ( @@ -385,15 +390,15 @@ export const VideoContent = () => { user={name} jsonId={id} poster={videoCover || ""} + customStyle={{ aspectRatio: "16/9" }} /> )} - - diff --git a/src/state/features/persistSlice.ts b/src/state/features/persistSlice.ts new file mode 100644 index 0000000..30e0cda --- /dev/null +++ b/src/state/features/persistSlice.ts @@ -0,0 +1,59 @@ +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; +import { subscriptionTabValue } from "../../constants/Misc.ts"; + +type StretchVideoType = "contain" | "fill" | "cover" | "none" | "scale-down"; +interface settingsState { + selectedTab: string; + stretchVideoSetting: StretchVideoType; + filterType: string; + subscriptionList: string[]; + playbackRate: number; +} + +const initialState: settingsState = { + selectedTab: subscriptionTabValue, + stretchVideoSetting: "contain", + filterType: "videos", + subscriptionList: [], + playbackRate: 1, +}; + +export const persistSlice = createSlice({ + name: "persist", + initialState, + reducers: { + setHomePageSelectedTab: (state, action) => { + state.selectedTab = action.payload; + }, + setStretchVideoSetting: (state, action) => { + state.stretchVideoSetting = action.payload; + }, + subscribe: (state, action: PayloadAction) => { + const currentSubscriptions = state.subscriptionList; + if (!currentSubscriptions.includes(action.payload)) { + state.subscriptionList = [...currentSubscriptions, action.payload]; + } + }, + unSubscribe: (state, action) => { + state.subscriptionList = state.subscriptionList.filter( + item => item !== action.payload + ); + }, + setReduxPlaybackRate: (state, action) => { + state.playbackRate = action.payload; + }, + changeFilterType: (state, action) => { + state.filterType = action.payload; + }, + }, +}); + +export const { + setHomePageSelectedTab, + subscribe, + unSubscribe, + setReduxPlaybackRate, + changeFilterType, +} = persistSlice.actions; + +export default persistSlice.reducer; diff --git a/src/state/features/videoSlice.ts b/src/state/features/videoSlice.ts index 57340a5..d3b86e0 100644 --- a/src/state/features/videoSlice.ts +++ b/src/state/features/videoSlice.ts @@ -1,23 +1,21 @@ -import { createSlice } from '@reduxjs/toolkit'; -import { RootState } from '../store' - +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; interface GlobalState { - videos: Video[] - filteredVideos: Video[] - hashMapVideos: Record - hashMapSuperlikes: Record - countNewVideos: number - isFiltering: boolean - filterValue: string - filterType: string - filterSearch: string - filterName: string - selectedCategoryVideos: any - selectedSubCategoryVideos: any - editVideoProperties: any - editPlaylistProperties: any + videos: Video[]; + filteredVideos: Video[]; + hashMapVideos: Record; + hashMapSuperlikes: Record; + countNewVideos: number; + isFiltering: boolean; + filterValue: string; + filterSearch: string; + filterName: string; + selectedCategoryVideos: any; + selectedSubCategoryVideos: any; + editVideoProperties: any; + editPlaylistProperties: any; } + const initialState: GlobalState = { videos: [], filteredVideos: [], @@ -25,159 +23,153 @@ const initialState: GlobalState = { hashMapSuperlikes: {}, countNewVideos: 0, isFiltering: false, - filterValue: '', - filterType: 'videos', - filterSearch: '', - filterName: '', + filterValue: "", + filterSearch: "", + filterName: "", selectedCategoryVideos: null, selectedSubCategoryVideos: null, editVideoProperties: null, - editPlaylistProperties: null -} + editPlaylistProperties: null, +}; export interface Video { - title: string - description: string - created: number | string - user: string - service?: string - videoImage?: string - id: string - category?: string - categoryName?: string - tags?: string[] - updated?: number | string - isValid?: boolean - code?: string + title: string; + description: string; + created: number | string; + user: string; + service?: string; + videoImage?: string; + id: string; + category?: string; + categoryName?: string; + tags?: string[]; + updated?: number | string; + isValid?: boolean; + code?: string; } - - export const videoSlice = createSlice({ - name: 'video', + name: "video", initialState, reducers: { setEditVideo: (state, action) => { - state.editVideoProperties = action.payload + state.editVideoProperties = action.payload; }, setEditPlaylist: (state, action) => { - state.editPlaylistProperties = action.payload - }, - changeFilterType: (state, action) => { - state.filterType = action.payload + state.editPlaylistProperties = action.payload; }, + changefilterSearch: (state, action) => { - state.filterSearch = action.payload + state.filterSearch = action.payload; }, changefilterName: (state, action) => { - state.filterName = action.payload + state.filterName = action.payload; }, changeSelectedCategoryVideos: (state, action) => { - state.selectedCategoryVideos = action.payload + state.selectedCategoryVideos = action.payload; }, changeSelectedSubCategoryVideos: (state, action) => { - state.selectedSubCategoryVideos = action.payload + state.selectedSubCategoryVideos = action.payload; }, setCountNewVideos: (state, action) => { - state.countNewVideos = action.payload + state.countNewVideos = action.payload; }, addVideos: (state, action) => { - state.videos = action.payload + state.videos = action.payload; }, addFilteredVideos: (state, action) => { - state.filteredVideos = action.payload + state.filteredVideos = action.payload; }, removeVideo: (state, action) => { - const idToDelete = action.payload - state.videos = state.videos.filter((item) => item.id !== idToDelete) + const idToDelete = action.payload; + state.videos = state.videos.filter(item => item.id !== idToDelete); state.filteredVideos = state.filteredVideos.filter( - (item) => item.id !== idToDelete - ) + item => item.id !== idToDelete + ); }, addVideoToBeginning: (state, action) => { - state.videos.unshift(action.payload) + state.videos.unshift(action.payload); }, - clearVideoList: (state) => { - state.videos = [] + clearVideoList: state => { + state.videos = []; }, updateVideo: (state, action) => { - const { id } = action.payload - const index = state.videos.findIndex((video) => video.id === id) + const { id } = action.payload; + const index = state.videos.findIndex(video => video.id === id); if (index !== -1) { - state.videos[index] = { ...action.payload } + state.videos[index] = { ...action.payload }; } - const index2 = state.filteredVideos.findIndex((video) => video.id === id) + const index2 = state.filteredVideos.findIndex(video => video.id === id); if (index2 !== -1) { - state.filteredVideos[index2] = { ...action.payload } + state.filteredVideos[index2] = { ...action.payload }; } }, addToHashMap: (state, action) => { - const video = action.payload - state.hashMapVideos[video.id + '-' + video.user] = video + const video = action.payload; + state.hashMapVideos[video.id + "-" + video.user] = video; }, addtoHashMapSuperlikes: (state, action) => { - const superlike = action.payload - state.hashMapSuperlikes[superlike.identifier] = superlike - }, + const superlike = action.payload; + state.hashMapSuperlikes[superlike.identifier] = superlike; + }, updateInHashMap: (state, action) => { - const { id, user } = action.payload - const video = action.payload - state.hashMapVideos[id + '-' + user] = { ...video } + const { id, user } = action.payload; + const video = action.payload; + state.hashMapVideos[id + "-" + user] = { ...video }; }, removeFromHashMap: (state, action) => { - const idToDelete = action.payload - delete state.hashMapVideos[idToDelete] + const idToDelete = action.payload; + delete state.hashMapVideos[idToDelete]; }, addArrayToHashMap: (state, action) => { - const videos = action.payload + const videos = action.payload; videos.forEach((video: Video) => { - state.hashMapVideos[video.id + '-' + video.user] = video - }) + state.hashMapVideos[video.id + "-" + video.user] = video; + }); }, upsertVideos: (state, action) => { action.payload.forEach((video: Video) => { - const index = state.videos.findIndex((p) => p.id === video.id) + const index = state.videos.findIndex(p => p.id === video.id); if (index !== -1) { - state.videos[index] = video + state.videos[index] = video; } else { - state.videos.push(video) + state.videos.push(video); } - }) + }); }, upsertFilteredVideos: (state, action) => { action.payload.forEach((video: Video) => { - const index = state.filteredVideos.findIndex((p) => p.id === video.id) + const index = state.filteredVideos.findIndex(p => p.id === video.id); if (index !== -1) { - state.filteredVideos[index] = video + state.filteredVideos[index] = video; } else { - state.filteredVideos.push(video) + state.filteredVideos.push(video); } - }) + }); }, upsertVideosBeginning: (state, action) => { action.payload.reverse().forEach((video: Video) => { - const index = state.videos.findIndex((p) => p.id === video.id) + const index = state.videos.findIndex(p => p.id === video.id); if (index !== -1) { - state.videos[index] = video + state.videos[index] = video; } else { - state.videos.unshift(video) + state.videos.unshift(video); } - }) + }); }, setIsFiltering: (state, action) => { - state.isFiltering = action.payload + state.isFiltering = action.payload; }, setFilterValue: (state, action) => { - state.filterValue = action.payload + state.filterValue = action.payload; }, blockUser: (state, action) => { - const username = action.payload - - state.videos = state.videos.filter((item) => item.user !== username) - - } - } -}) + const username = action.payload; + + state.videos = state.videos.filter(item => item.user !== username); + }, + }, +}); export const { setCountNewVideos, @@ -196,7 +188,6 @@ export const { setIsFiltering, setFilterValue, clearVideoList, - changeFilterType, changefilterSearch, changefilterName, changeSelectedCategoryVideos, @@ -204,8 +195,7 @@ export const { blockUser, setEditVideo, setEditPlaylist, - addtoHashMapSuperlikes -} = videoSlice.actions - -export default videoSlice.reducer + addtoHashMapSuperlikes, +} = videoSlice.actions; +export default videoSlice.reducer; diff --git a/src/state/store.ts b/src/state/store.ts index 0400841..e5f0657 100644 --- a/src/state/store.ts +++ b/src/state/store.ts @@ -1,27 +1,47 @@ -import { configureStore } from '@reduxjs/toolkit' -import notificationsReducer from './features/notificationsSlice' -import authReducer from './features/authSlice' -import globalReducer from './features/globalSlice' -import videoReducer from './features/videoSlice' +import { combineReducers, configureStore } from "@reduxjs/toolkit"; +import notificationsReducer from "./features/notificationsSlice"; +import authReducer from "./features/authSlice"; +import globalReducer from "./features/globalSlice"; +import videoReducer from "./features/videoSlice"; +import settingsReducer from "./features/persistSlice.ts"; +import { + persistReducer, + FLUSH, + REHYDRATE, + PAUSE, + PERSIST, + PURGE, + REGISTER, +} from "redux-persist"; +import storage from "redux-persist/lib/storage"; + +const persistSettingsConfig = { + key: "persist", + version: 1, + storage, +}; + +const reducer = combineReducers({ + notifications: notificationsReducer, + auth: authReducer, + global: globalReducer, + video: videoReducer, + persist: persistReducer(persistSettingsConfig, settingsReducer), +}); export const store = configureStore({ - reducer: { - notifications: notificationsReducer, - auth: authReducer, - global: globalReducer, - video: videoReducer, - }, - middleware: (getDefaultMiddleware) => + reducer, + middleware: getDefaultMiddleware => getDefaultMiddleware({ - serializableCheck: false + serializableCheck: false, }), - preloadedState: undefined // optional, can be any valid state object -}) + preloadedState: undefined, // optional, can be any valid state object +}); // Define the RootState type, which is the type of the entire Redux state tree. // This is useful when you need to access the state in a component or elsewhere. -export type RootState = ReturnType +export type RootState = ReturnType; // Define the AppDispatch type, which is the type of the Redux store's dispatch function. // This is useful when you need to dispatch an action in a component or elsewhere. -export type AppDispatch = typeof store.dispatch +export type AppDispatch = typeof store.dispatch; diff --git a/src/wrappers/GlobalWrapper.tsx b/src/wrappers/GlobalWrapper.tsx index 0bbbfc1..f4852a4 100644 --- a/src/wrappers/GlobalWrapper.tsx +++ b/src/wrappers/GlobalWrapper.tsx @@ -15,7 +15,7 @@ import { setSuperlikesAll, setUserAvatarHash, } from "../state/features/globalSlice"; -import { VideoPlayerGlobal } from "../components/common/VideoPlayerGlobal"; +import { VideoPlayerGlobal } from "../components/common/VideoPlayer/VideoPlayerGlobal.tsx"; import { Rnd } from "react-rnd"; import { RequestQueue } from "../utils/queue"; import { EditVideo } from "../components/EditVideo/EditVideo";