diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..d4c88ef --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,20 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": ["eslint:recommended", "plugin:react/recommended", "plugin:@typescript-eslint/recommended"], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaFeatures": { + "jsx": true + }, + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": ["react", "@typescript-eslint"], + "rules": { + "react/display-name": "off", + "react/prop-types": "off" + } +} diff --git a/constants.ts b/constants.ts index 55cc2ac..f43abc1 100644 --- a/constants.ts +++ b/constants.ts @@ -1 +1,2 @@ -export const BACKEND_URL: string = 'http://localhost:3333'; +export const BACKEND_URL = 'http://localhost:3333'; +export const WS_URL = 'ws://localhost:3333'; diff --git a/index.html b/index.html index cd4d8a1..39f5472 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,5 @@ - + diff --git a/package-lock.json b/package-lock.json index 41e8227..8854cb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1043,10 +1043,81 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" }, + "@eslint/eslintrc": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", + "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.2.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", + "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + } + } + }, "@hookform/resolvers": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.8.2.tgz", - "integrity": "sha512-oDTGrm7yHxT4VIv4kJcfjvWvozCbdcL0/jrpbAkeo39FYn78XnKOrrGTNmrXdfu+EQVkNIdZ47IYRFManZ4jUA==" + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.8.5.tgz", + "integrity": "sha512-n7eFm4snsejpfZVH8q2NU7YJbsGhF61IHB0TxgK11nmg08RymEr3KscnbTAZaPd9RaXa3vUPoULgBRN2nVDtMg==" + }, + "@humanwhocodes/config-array": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz", + "integrity": "sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } }, "@popperjs/core": { "version": "2.4.4", @@ -1093,6 +1164,16 @@ "picomatch": "^2.2.2" } }, + "@socket.io/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==" + }, + "@socket.io/component-emitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz", + "integrity": "sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q==" + }, "@types/history": { "version": "4.7.9", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz", @@ -1114,6 +1195,12 @@ "integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==", "dev": true }, + "@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, "@types/lodash": { "version": "4.14.175", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.175.tgz", @@ -1234,6 +1321,135 @@ "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", "integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI=" }, + "@typescript-eslint/eslint-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.6.0.tgz", + "integrity": "sha512-MIbeMy5qfLqtgs1hWd088k1hOuRsN9JrHUPwVVKCD99EOUqScd7SrwoZl4Gso05EAP9w1kvLWUVGJOVpRPkDPA==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "5.6.0", + "@typescript-eslint/scope-manager": "5.6.0", + "debug": "^4.3.2", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", + "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.6.0.tgz", + "integrity": "sha512-VDoRf3Qj7+W3sS/ZBXZh3LBzp0snDLEgvp6qj0vOAIiAPM07bd5ojQ3CTzF/QFl5AKh7Bh1ycgj6lFBJHUt/DA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.6.0", + "@typescript-eslint/types": "5.6.0", + "@typescript-eslint/typescript-estree": "5.6.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "@typescript-eslint/parser": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.6.0.tgz", + "integrity": "sha512-YVK49NgdUPQ8SpCZaOpiq1kLkYRPMv9U5gcMrywzI8brtwZjr/tG3sZpuHyODt76W/A0SufNjYt9ZOgrC4tLIQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.6.0", + "@typescript-eslint/types": "5.6.0", + "@typescript-eslint/typescript-estree": "5.6.0", + "debug": "^4.3.2" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.6.0.tgz", + "integrity": "sha512-1U1G77Hw2jsGWVsO2w6eVCbOg0HZ5WxL/cozVSTfqnL/eB9muhb8THsP0G3w+BB5xAHv9KptwdfYFAUfzcIh4A==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.6.0", + "@typescript-eslint/visitor-keys": "5.6.0" + } + }, + "@typescript-eslint/types": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.6.0.tgz", + "integrity": "sha512-OIZffked7mXv4mXzWU5MgAEbCf9ecNJBKi+Si6/I9PpTaj+cf2x58h2oHW5/P/yTnPkKaayfjhLvx+crnl5ubA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.6.0.tgz", + "integrity": "sha512-92vK5tQaE81rK7fOmuWMrSQtK1IMonESR+RJR2Tlc7w4o0MeEdjgidY/uO2Gobh7z4Q1hhS94Cr7r021fMVEeA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.6.0", + "@typescript-eslint/visitor-keys": "5.6.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.6.0.tgz", + "integrity": "sha512-1p7hDp5cpRFUyE3+lvA74egs+RWSgumrBpzBCDzfTFv0aQ7lIeay80yU0hIxgAhwQ6PcasW35kaOCyDOv6O/Ng==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.6.0", + "eslint-visitor-keys": "^3.0.0" + } + }, "@virtuoso.dev/react-urx": { "version": "0.2.8", "resolved": "https://registry.npmjs.org/@virtuoso.dev/react-urx/-/react-urx-0.2.8.tgz", @@ -1263,6 +1479,36 @@ "resolve": "^1.20.0" } }, + "acorn": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", + "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1277,6 +1523,12 @@ "color-convert": "^1.9.0" } }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "aria-hidden": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.1.3.tgz", @@ -1292,6 +1544,36 @@ } } }, + "array-includes": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array.prototype.flatmap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", + "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + } + }, "axios": { "version": "0.21.4", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", @@ -1310,6 +1592,36 @@ "resolve": "^1.12.0" } }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "browserslist": { "version": "4.17.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", @@ -1337,11 +1649,6 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, "caniuse-lite": { "version": "1.0.30001267", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001267.tgz", @@ -1376,6 +1683,12 @@ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz", "integrity": "sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ==" }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, "convert-source-map": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", @@ -1404,6 +1717,17 @@ "yaml": "^1.7.2" } }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, "css-box-model": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", @@ -1421,16 +1745,53 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, "requires": { "ms": "2.1.2" } }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "electron-to-chromium": { "version": "1.3.870", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.870.tgz", @@ -1443,6 +1804,39 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "engine.io-client": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.1.1.tgz", + "integrity": "sha512-V05mmDo4gjimYW+FGujoGmmmxRaDsrVr7AXA3ZIfa04MWM1jOfZfUwou0oNqhNwy/votUDvGDt4JA4QF4e0b4g==", + "requires": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.0", + "has-cors": "1.1.0", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~8.2.3", + "xmlhttprequest-ssl": "~2.0.0", + "yeast": "0.1.2" + } + }, + "engine.io-parser": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", + "integrity": "sha512-BtQxwF27XUNnSafQLvDi0dQ8s3i6VgzSoQMJacpIcGNrlUdfHSKbgm3jmjCVvQluGzqwujQMPAoMai3oYSTurg==", + "requires": { + "@socket.io/base64-arraybuffer": "~1.0.2" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1451,6 +1845,45 @@ "is-arrayish": "^0.2.1" } }, + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "esbuild": { "version": "0.13.6", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.6.tgz", @@ -1606,17 +2039,340 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "eslint": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-TxU/p7LB1KxQ6+7aztTnO7K0i+h0tDi81YRY9VzB6Id71kNz+fFYnf5HD5UOQmxkzcoa0TlVZf9dpMtUv0GpWg==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.0.5", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.0", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.2.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.2.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "globals": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", + "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "eslint-plugin-react": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.27.1.tgz", + "integrity": "sha512-meyunDjMMYeWr/4EBLTV1op3iSG3mjT/pz5gti38UzfM4OPpNc2m0t2xvKCOMU5D6FSdd34BIMFOvQbW+i8GAA==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.6" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-scope": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", + "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", + "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", + "dev": true + }, + "espree": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.2.0.tgz", + "integrity": "sha512-oP3utRkynpZWF/F2x/HZJ+AGtnIclaR7z1pYPxy7NYM2fSO6LgK/Rkny8anRSPK/VwEA1eqm2squui0T7ZMOBg==", + "dev": true, + "requires": { + "acorn": "^8.6.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.1.0" + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, "estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", + "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", + "dev": true + }, "focus-lock": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-0.8.1.tgz", @@ -1675,6 +2431,12 @@ "tslib": "^2.1.0" } }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, "fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -1687,6 +2449,12 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -1714,12 +2482,67 @@ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==" }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", + "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", + "dev": true + } + } + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -1728,6 +2551,17 @@ "function-bind": "^1.1.1" } }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -1738,6 +2572,15 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, "hey-listen": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz", @@ -1764,6 +2607,17 @@ "react-is": "^16.7.0" } }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "immutability-helper": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/immutability-helper/-/immutability-helper-3.1.1.tgz", + "integrity": "sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ==" + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -1773,6 +2627,39 @@ "resolve-from": "^4.0.0" } }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -1786,6 +2673,31 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, "is-core-module": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", @@ -1794,18 +2706,106 @@ "has": "^1.0.3" } }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "dev": true + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -1820,6 +2820,12 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, "js-cookie": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz", @@ -1830,6 +2836,15 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -1841,6 +2856,18 @@ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json5": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", @@ -1850,11 +2877,36 @@ "minimist": "^1.2.5" } }, + "jsx-ast-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", + "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "object.assign": "^4.1.2" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, + "load-script": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", + "integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ=" + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -1865,6 +2917,12 @@ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "lodash.mergewith": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", @@ -1878,11 +2936,36 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, "mini-create-react-context": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", @@ -1892,6 +2975,15 @@ "tiny-warning": "^1.0.3" } }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", @@ -1924,8 +3016,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "nanoclone": { "version": "0.2.1", @@ -1938,6 +3029,12 @@ "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", "dev": true }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "node-releases": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", @@ -1954,6 +3051,76 @@ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, "open": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", @@ -1964,6 +3131,20 @@ "is-wsl": "^2.1.1" } }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1983,6 +3164,28 @@ "lines-and-columns": "^1.1.6" } }, + "parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -2043,6 +3246,18 @@ } } }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "prop-types": { "version": "15.7.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", @@ -2058,6 +3273,12 @@ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz", "integrity": "sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg==" }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, "qs": { "version": "6.10.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", @@ -2066,6 +3287,12 @@ "side-channel": "^1.0.4" } }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "raf-schd": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", @@ -2150,23 +3377,32 @@ } }, "react-hook-form": { - "version": "7.17.4", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.17.4.tgz", - "integrity": "sha512-7XhbCr7d9fDC1TgcK/BUbt7D3q0VJMu7jPErfsa0JrxVjv/nni41xWdJcy0Zb7R+Np8OsCkQ2lMyloAtE3DLiQ==" + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.22.5.tgz", + "integrity": "sha512-Q2zaeQFXdVQ8l3hcywhltH+Nzj4vo50wMVujHDVN/1Xy9IOaSZJwYBXA2CYTpK6rq41fnXviw3jTLb04c7Gu9Q==" }, "react-icons": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.11.0.tgz", - "integrity": "sha512-JRgiI/vdF6uyBgyZhVyYJUZAop95Sy4XDe/jmT3R/bKliFWpO/uZBwvSjWEdxwzec7SYbEPNPck0Kff2tUGM2Q==", - "requires": { - "camelcase": "^5.0.0" - } + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz", + "integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==" }, "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-player": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-player/-/react-player-2.9.0.tgz", + "integrity": "sha512-jNUkTfMmUhwPPAktAdIqiBcVUKsFKrVGH6Ocutj6535CNfM91yrvWxHg6fvIX8Y/fjYUPoejddwh7qboNV9vGA==", + "requires": { + "deepmerge": "^4.0.0", + "load-script": "^1.0.0", + "memoize-one": "^5.1.1", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.0.1" + } + }, "react-redux": { "version": "7.2.6", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz", @@ -2311,6 +3547,22 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, + "regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2336,6 +3588,21 @@ "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "rollup": { "version": "2.58.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.58.0.tgz", @@ -2438,6 +3705,15 @@ } } }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -2458,6 +3734,21 @@ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -2468,6 +3759,34 @@ "object-inspect": "^1.9.0" } }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "socket.io-client": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.4.1.tgz", + "integrity": "sha512-N5C/L5fLNha5Ojd7Yeb/puKcPWWcoB/A09fEjjNsg91EDVr5twk/OEyO6VT9dlLSUNY85NpW6KBhVMvaLKQ3vQ==", + "requires": { + "@socket.io/component-emitter": "~3.0.0", + "backo2": "~1.0.2", + "debug": "~4.3.2", + "engine.io-client": "~6.1.1", + "parseuri": "0.0.6", + "socket.io-parser": "~4.1.1" + } + }, + "socket.io-parser": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.1.1.tgz", + "integrity": "sha512-USQVLSkDWE5nbcY760ExdKaJxCE65kcsG/8k5FDGZVVxpD1pA7hABYXYkCUvxUuYYh/+uQw0N/fvBzfT8o07KA==", + "requires": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1" + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -2490,6 +3809,42 @@ "strip-ansi": "^6.0.1" } }, + "string.prototype.matchall": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", + "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -2499,6 +3854,12 @@ "ansi-regex": "^5.0.1" } }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "style-value-types": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-4.1.4.tgz", @@ -2521,6 +3882,12 @@ "has-flag": "^3.0.0" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "tiny-invariant": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", @@ -2536,6 +3903,15 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, "toggle-selection": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", @@ -2551,12 +3927,65 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, - "typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "typescript": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", + "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "use-callback-ref": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz", @@ -2583,6 +4012,12 @@ } } }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "validator": { "version": "13.6.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz", @@ -2614,11 +4049,66 @@ "loose-envify": "^1.0.0" } }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==" + }, + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, "yup": { "version": "0.32.11", "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz", diff --git a/package.json b/package.json index a7d06b4..1baea90 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "educt-client", - "version": "0.1.0", + "version": "1.0.0", "scripts": { "dev": "vite", "build": "tsc && vite build", @@ -13,9 +13,10 @@ "@chakra-ui/react": "^1.6.10", "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@hookform/resolvers": "^2.8.0", + "@hookform/resolvers": "^2.8.5", "axios": "^0.21.1", "framer-motion": "^4.0.0", + "immutability-helper": "^3.1.1", "js-cookie": "^3.0.0", "mobx": "^6.3.2", "mobx-react": "^7.2.0", @@ -26,11 +27,13 @@ "react-dom": "^17.0.0", "react-error-boundary": "^3.1.3", "react-helmet": "^6.1.0", - "react-hook-form": "^7.12.2", - "react-icons": "^3.11.0", + "react-hook-form": "^7.22.5", + "react-icons": "^4.3.1", + "react-player": "^2.9.0", "react-router-dom": "^5.2.0", "react-spinners": "^0.11.0", "react-virtuoso": "^2.2.8", + "socket.io-client": "^4.4.1", "validator": "^13.6.0", "yup": "^0.32.9" }, @@ -44,9 +47,13 @@ "@types/react-helmet": "^6.1.2", "@types/react-router-dom": "^5.1.8", "@types/validator": "^13.6.3", + "@typescript-eslint/eslint-plugin": "^5.6.0", + "@typescript-eslint/parser": "^5.6.0", "@vitejs/plugin-react": "^1.0.0", + "eslint": "^8.4.1", + "eslint-plugin-react": "^7.27.1", "rollup-plugin-visualizer": "^5.5.2", - "typescript": "^4.3.2", + "typescript": "^4.5.2", "vite": "^2.6.4" } } diff --git a/src/App.tsx b/src/App.tsx index ec5e270..ce78a65 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,6 +5,7 @@ import { routes } from './routes.config'; /** * Hooks */ +import { useContext } from 'react'; import { useRootStore } from '@educt/hooks/useRootStore'; /** @@ -12,11 +13,67 @@ import { useRootStore } from '@educt/hooks/useRootStore'; */ import PrivateRoute from '@educt/components/PrivateRoute'; import PublicRoute from '@educt/components/PublicRoute'; +import { useSocketEvent } from './hooks/useSocketEvent'; +import { SocketContext } from './contexts'; +import { HistoryMessageType, UserOnlineListType, UserSeesionType } from './types'; +import { useToast } from '@chakra-ui/react'; const App = () => { const { + userStore, uiStore: { history }, + onlineStore, } = useRootStore(); + const { socket } = useContext(SocketContext); + const toast = useToast(); + + useSocketEvent('connect', () => console.info('[WebSocket]: Connected.')); + useSocketEvent('disconnect', () => console.info('[WebSocket]: Disconnected.')); + useSocketEvent('connect_error', err => console.error(err)); + useSocketEvent('user:session', data => { + if (socket) { + const { sessionId } = data; + if (sessionId) { + socket.auth = { sessionId }; + window.localStorage.setItem('sessionId', sessionId); + } + } + }); + useSocketEvent('chat:message', data => { + const chatId = new URLSearchParams(location.search).get('chat_id'); + const user = onlineStore.getUser(data.from); + + if (user && data.from !== chatId) { + if (data.to === data.from) return; + + /** + * Notify user about new message + */ + toast({ + title: `${user.userName}`, + description: data.content, + variant: 'left-accent', + position: 'bottom-right', + status: 'info', + duration: 5000, + }); + + if (!window.location.pathname.includes('messages')) { + /** + * Update user store + */ + if (data.notificationId) { + userStore.addNotification({ + id: data.notificationId, + content: 'You received a new private message', + time: new Date().toISOString(), + type: 'MESSAGE', + }); + } + } + } + }); + useSocketEvent('user:online', online => onlineStore.loadOnline(online)); return ( diff --git a/src/api.config.ts b/src/api.config.ts index 6a20d45..aa818a4 100644 --- a/src/api.config.ts +++ b/src/api.config.ts @@ -1,7 +1,8 @@ import { AxiosRequestConfig } from 'axios'; +import * as constants from '../constants'; const apiConfig: AxiosRequestConfig = { - baseURL: '/api/', + baseURL: `${constants.BACKEND_URL}/api/`, responseType: 'json', withCredentials: true, }; diff --git a/src/components/Buttons/index.tsx b/src/components/Buttons/index.tsx new file mode 100644 index 0000000..212f487 --- /dev/null +++ b/src/components/Buttons/index.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { ButtonProps, Button } from '@chakra-ui/button'; +import { AddIcon, DeleteIcon, EditIcon } from '@chakra-ui/icons'; +import { MdSave } from 'react-icons/md'; + +export const CreateButton: React.FC = props => ( + +); + +export const AddButton: React.FC = props => ( + +); + +export const DeleteButton: React.FC = props => ( + +); + +export const EditButton: React.FC = props => ( + +); + +export const SaveButton: React.FC = props => ( + +); diff --git a/src/components/Card/Card.tsx b/src/components/Card/Card.tsx new file mode 100644 index 0000000..4978adb --- /dev/null +++ b/src/components/Card/Card.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { Box, BoxProps, useColorModeValue } from '@chakra-ui/react'; + +const Card: React.FC = (props: BoxProps) => ( + +); + +export default Card; diff --git a/src/components/Card/index.ts b/src/components/Card/index.ts new file mode 100644 index 0000000..8c371a2 --- /dev/null +++ b/src/components/Card/index.ts @@ -0,0 +1,3 @@ +import Card from './Card'; + +export { Card }; diff --git a/src/components/Chat/ChatContextProvider.tsx b/src/components/Chat/ChatContextProvider.tsx new file mode 100644 index 0000000..ad1d2f6 --- /dev/null +++ b/src/components/Chat/ChatContextProvider.tsx @@ -0,0 +1,10 @@ +import React, { useState } from 'react'; +import { ChatContext } from './context'; + +const ChatContextProvider: React.FC = ({ children }) => { + const [search, setSearch] = useState(''); + + return {children}; +}; + +export { ChatContextProvider }; diff --git a/src/components/Chat/Sidebar/Heading.tsx b/src/components/Chat/Sidebar/Heading.tsx new file mode 100644 index 0000000..451c916 --- /dev/null +++ b/src/components/Chat/Sidebar/Heading.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { + Flex, + Heading as ChakraHeading, + Input, + InputGroup, + InputLeftElement, + HStack, + Button, + Box, + BoxProps, +} from '@chakra-ui/react'; +import { SearchIcon } from '@chakra-ui/icons'; + +/** + * Hooks + */ +import { useChatContext } from '../context'; + +const Heading: React.FC = props => { + const { search, setSearch } = useChatContext(); + + const onSearch = (e: React.ChangeEvent) => setSearch(e.target.value); + + return ( + + + + Chats + + + + + + + + + + + {/* */} + + + ); +}; + +export { Heading }; diff --git a/src/components/Chat/Sidebar/Sidebar.tsx b/src/components/Chat/Sidebar/Sidebar.tsx new file mode 100644 index 0000000..0537fb8 --- /dev/null +++ b/src/components/Chat/Sidebar/Sidebar.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { BoxProps, GridItem, GridItemProps } from '@chakra-ui/react'; +import { Heading } from './Heading'; +import { Users } from './Users/Users'; + +export interface ISidebarComposition { + Heading: React.FC; + Users: React.FC; +} + +const Sidebar: React.FC & ISidebarComposition = props => { + return ( + + {props.children} + + ); +}; + +Sidebar.Heading = Heading; +Sidebar.Users = Users; + +export { Sidebar }; diff --git a/src/components/Chat/Sidebar/Users/User/Avatar.tsx b/src/components/Chat/Sidebar/Users/User/Avatar.tsx new file mode 100644 index 0000000..d5caa58 --- /dev/null +++ b/src/components/Chat/Sidebar/Users/User/Avatar.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Avatar as ChakraAvatar, AvatarBadge, WrapItem } from '@chakra-ui/react'; +import { useRootStore } from '@educt/hooks/useRootStore'; +import { MdOutlineBookmark } from 'react-icons/md'; + +export interface IAvatarProps { + fullname: string; + isOnline: boolean; +} + +const Avatar: React.FC = ({ fullname: name, isOnline }) => { + const { + userStore: { me }, + } = useRootStore(); + const isMe = me?.fullname === name; + const onlineBg = isOnline ? 'green.500' : 'red.500'; + + return ( + + } + size='md' + > + {!isMe && } + + + ); +}; + +export { Avatar }; diff --git a/src/components/Chat/Sidebar/Users/User/Info.tsx b/src/components/Chat/Sidebar/Users/User/Info.tsx new file mode 100644 index 0000000..913eb00 --- /dev/null +++ b/src/components/Chat/Sidebar/Users/User/Info.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Box, Text } from '@chakra-ui/react'; +import { useRootStore } from '@educt/hooks/useRootStore'; +import { HistoryMessageType } from '@educt/types'; + +export interface IInfoProps { + fullname: string; + lastMessage?: HistoryMessageType | undefined; +} + +const Info: React.FC = ({ fullname, lastMessage }) => { + const { + userStore: { me }, + } = useRootStore(); + const isMe = me?.fullname === fullname; + + return ( + + + {isMe ? 'Favorites' : fullname}
+ {lastMessage && ( + + {lastMessage.from === me?.id && `You: `} + {lastMessage.content.length >= 20 ? lastMessage.content.slice(0, 20 - 1) + '...' : lastMessage.content} + + )} +
+
+ ); +}; + +export { Info }; diff --git a/src/components/Chat/Sidebar/Users/User/Time.tsx b/src/components/Chat/Sidebar/Users/User/Time.tsx new file mode 100644 index 0000000..c7fa5c3 --- /dev/null +++ b/src/components/Chat/Sidebar/Users/User/Time.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Box, Text } from '@chakra-ui/react'; + +export interface ITimeProps { + time: string; +} + +const Time: React.FC = ({ time }) => { + return ( + + + {time} + + + ); +}; + +export { Time }; diff --git a/src/components/Chat/Sidebar/Users/User/User.tsx b/src/components/Chat/Sidebar/Users/User/User.tsx new file mode 100644 index 0000000..aba67e8 --- /dev/null +++ b/src/components/Chat/Sidebar/Users/User/User.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { Box, Flex } from '@chakra-ui/react'; +import { IInfoProps, Info } from './Info'; +import { ITimeProps, Time } from './Time'; +import { IAvatarProps, Avatar } from './Avatar'; + +/** + * Hooks + */ +import { useHistory, useLocation } from 'react-router-dom'; +import { useColorModeValue } from '@chakra-ui/react'; + +interface IUserComposition { + Avatar: React.FC; + Info: React.FC; + Time: React.FC; +} + +interface IUserProps { + id: string; +} + +const User: React.FC & IUserComposition = props => { + const history = useHistory(); + const location = useLocation(); + const chatId = new URLSearchParams(location.search).get('chat_id'); + const bg = useColorModeValue('gray.50', 'gray.700'); + + const handleChat = () => { + history.replace({ pathname: location.pathname, search: new URLSearchParams({ ['chat_id']: props.id }).toString() }); + }; + + return ( + + + {props.children} + + + ); +}; + +User.Avatar = Avatar; +User.Info = Info; +User.Time = Time; + +export { User }; diff --git a/src/components/Chat/Sidebar/Users/User/index.ts b/src/components/Chat/Sidebar/Users/User/index.ts new file mode 100644 index 0000000..403fc94 --- /dev/null +++ b/src/components/Chat/Sidebar/Users/User/index.ts @@ -0,0 +1 @@ +export { User } from './User'; diff --git a/src/components/Chat/Sidebar/Users/Users.tsx b/src/components/Chat/Sidebar/Users/Users.tsx new file mode 100644 index 0000000..040b53b --- /dev/null +++ b/src/components/Chat/Sidebar/Users/Users.tsx @@ -0,0 +1,67 @@ +import React from 'react'; +import { observer } from 'mobx-react'; +import { Stack, StackProps } from '@chakra-ui/react'; +import { User } from './User'; +import { useChatContext } from '../../context'; +import { useRootStore } from '@educt/hooks/useRootStore'; +import { Skeleton } from '@chakra-ui/react'; +import { useFetchConversations } from '@educt/hooks/queries'; + +const Wrapper: React.FC = ({ children }) => { + return ( + + {children} + + ); +}; + +const Users: React.FC = observer(() => { + const { + userStore: { me }, + onlineStore, + } = useRootStore(); + const { data: conversations } = useFetchConversations(); + const { search } = useChatContext(); + + if (conversations === null || me === null) + return ( + + + + + ); + + const filtered = ( + !search ? conversations : conversations.filter(u => u.fullname.toLocaleLowerCase().includes(search)) + ) + .concat() + .sort((c1, c2) => new Date(c2.lastMessage.time).valueOf() - new Date(c1.lastMessage.time).valueOf()); + + const isEmpty = filtered.length === 0; + + return ( + + {/* Favorites */} + + + + + + {/* User list */} + {!isEmpty && + filtered.map( + c => + c.userId !== me.id && ( + + + + + + ) + )} + + ); +}); +export { Users }; diff --git a/src/components/Chat/Sidebar/Users/index.ts b/src/components/Chat/Sidebar/Users/index.ts new file mode 100644 index 0000000..a87a5f5 --- /dev/null +++ b/src/components/Chat/Sidebar/Users/index.ts @@ -0,0 +1 @@ +export { Users } from './Users'; diff --git a/src/components/Chat/Sidebar/index.ts b/src/components/Chat/Sidebar/index.ts new file mode 100644 index 0000000..d440597 --- /dev/null +++ b/src/components/Chat/Sidebar/index.ts @@ -0,0 +1 @@ +export { Sidebar } from './Sidebar'; diff --git a/src/components/Chat/Window/Message/Avatar.tsx b/src/components/Chat/Window/Message/Avatar.tsx new file mode 100644 index 0000000..85cad6d --- /dev/null +++ b/src/components/Chat/Window/Message/Avatar.tsx @@ -0,0 +1,16 @@ +import React, { memo } from 'react'; +import { WrapItem, Avatar as ChakraAvatar } from '@chakra-ui/react'; + +export interface IAvatarProps { + fullname: string; +} + +const Avatar: React.FC = memo(({ fullname: name }) => { + return ( + + + + ); +}); + +export { Avatar }; diff --git a/src/components/Chat/Window/Message/Message.tsx b/src/components/Chat/Window/Message/Message.tsx new file mode 100644 index 0000000..3d9aa13 --- /dev/null +++ b/src/components/Chat/Window/Message/Message.tsx @@ -0,0 +1,59 @@ +import React, { memo, useEffect, useRef } from 'react'; +import { Flex, Box, Stack, Text as ChakraText } from '@chakra-ui/react'; +import { Avatar, IAvatarProps } from './Avatar'; +import { Text, ITextProps } from './Text'; +import { MessageContext } from './context'; +import { MessageType } from '@educt/types'; + +interface IMessageComposition { + Avatar: React.FC; + Text: React.FC; +} + +interface IMyMessageProps { + isMyMessage: boolean; +} + +const MessageList: React.FC<{ messages: MessageType[] }> = memo(({ messages }) => { + const listRef = useRef(null); + + useEffect(() => { + if (listRef.current) { + listRef.current.scrollTo(0, listRef.current.scrollHeight); + } + }, [messages]); + + return ( + + {messages.length !== 0 ? ( + messages.map((message, i) => ( + + + + + )) + ) : ( + + + Your message history will be displayed here. + + + )} + + ); +}); + +const Message: React.FC & IMessageComposition = ({ children, isMyMessage }) => { + return ( + + + {children} + + + ); +}; + +Message.Avatar = Avatar; +Message.Text = Text; + +export { MessageList, Message }; diff --git a/src/components/Chat/Window/Message/Text.tsx b/src/components/Chat/Window/Message/Text.tsx new file mode 100644 index 0000000..714b11e --- /dev/null +++ b/src/components/Chat/Window/Message/Text.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { Box, Text as ChakraText, useColorModeValue } from '@chakra-ui/react'; +import { useMessageContext } from './context'; + +export interface ITextProps { + content: string; + time: string; +} + +const Text: React.FC = ({ content, time }) => { + const { isMyMessage } = useMessageContext(); + + const bgColor = !isMyMessage ? useColorModeValue('gray.50', 'gray.700') : useColorModeValue('gray.100', 'gray.600'); + + return ( + + + {content} + + {time} + + + + ); +}; + +export { Text }; diff --git a/src/components/Chat/Window/Message/context.ts b/src/components/Chat/Window/Message/context.ts new file mode 100644 index 0000000..8dd77ca --- /dev/null +++ b/src/components/Chat/Window/Message/context.ts @@ -0,0 +1,17 @@ +import { createContext, useContext } from 'react'; + +export type MessageContextType = { + isMyMessage: boolean; +}; + +export const MessageContext = createContext(undefined); + +export const useMessageContext = () => { + const context = useContext(MessageContext); + + if (!context) { + throw new Error('MessageContext was outside of its provider'); + } + + return context; +}; diff --git a/src/components/Chat/Window/Message/index.ts b/src/components/Chat/Window/Message/index.ts new file mode 100644 index 0000000..cd58e02 --- /dev/null +++ b/src/components/Chat/Window/Message/index.ts @@ -0,0 +1 @@ +export * from './Message'; diff --git a/src/components/Chat/Window/Window.tsx b/src/components/Chat/Window/Window.tsx new file mode 100644 index 0000000..6f94d01 --- /dev/null +++ b/src/components/Chat/Window/Window.tsx @@ -0,0 +1,215 @@ +import React, { ChangeEvent } from 'react'; +import axios from 'axios'; +import { Link as ReactRouterLink } from 'react-router-dom'; +import { + GridItem, + GridItemProps, + Flex, + Box, + Icon, + Text, + Input, + Heading, + IconButton, + Divider, + Link, +} from '@chakra-ui/react'; +import { MdOutlineChat, MdSend } from 'react-icons/md'; +import { MessageList } from './Message'; +import { SocketContext } from '@educt/contexts'; +import { HistoryMessageType, MessageType } from '@educt/types'; +import { UserServiceInstance } from '@educt/services'; +import { IUser } from '@educt/interfaces'; +import LoadingList from '@educt/components/LoadingList'; + +/** + * Hooks + */ +import { useContext, useEffect, useState } from 'react'; +import { useToast } from '@chakra-ui/react'; +import { useSocketEvent } from '@educt/hooks/useSocketEvent'; +import { useRootStore } from '@educt/hooks/useRootStore'; +import { useHistory } from 'react-router-dom'; + +const Wrapper: React.FC = props => ( + + {props.children} + +); + +const Window: React.FC = props => { + const { + userStore: { me }, + onlineStore, + } = useRootStore(); + const chatId = new URLSearchParams(location.search).get('chat_id'); + const [isLoading, setIsLoading] = useState(false); + const [selectedUser, setSelectedUser] = useState(null); + const [inputValue, setInputValue] = useState(''); + const [messages, setMessages] = useState([]); + const { socket } = useContext(SocketContext); + const history = useHistory(); + const toast = useToast(); + + const isMe = me?.id === selectedUser?.id; + + const onSubmit = (e: React.FormEvent) => { + e.preventDefault(); + + if (inputValue === '' || me === null) return; + + const message: MessageType = { + userName: me.fullname, + content: inputValue, + time: new Date().toLocaleTimeString(), + isMyMessage: true, + }; + + /** + * Emit event to server and update messages state + */ + if (chatId) { + socket?.emit('chat:message', { + content: message.content, + to: chatId, + }); + setMessages(prev => [...prev, message]); + setInputValue(''); + } + }; + + const onChangeInputValue = (e: ChangeEvent) => setInputValue(e.target.value); + + /** + * Load user data by `chat_id` + */ + useEffect(() => { + if (chatId) { + (async () => { + try { + setIsLoading(true); + const { data: user } = await UserServiceInstance.fetchUserById(chatId); + const { + data: { history }, + } = await UserServiceInstance.fetchChatHistory(chatId); + + const messages = history.map(message => { + return { + isMyMessage: message.from === me?.id, + content: message.content, + time: new Date(message.time).toLocaleTimeString(), + userName: message.from === me?.id ? me?.fullname : user.fullname, + }; + }); + + setSelectedUser(user); + setMessages(messages); + } catch (error) { + if (axios.isAxiosError(error)) { + if (error.response?.status === 404) { + toast({ title: 'Chat not found.', status: 'warning' }); + history.replace({ search: '' }); + } + } + + console.error(error); + } finally { + setIsLoading(false); + } + })(); + } + }, [chatId]); + + /** + * Event on accept new messages (set new message to state) + */ + useSocketEvent('chat:message', data => { + const user = onlineStore.getUser(data.from); + + if (user) { + if (chatId === data.from) { + /** + * Do not add duplicate of message + */ + if (data.to === data.from) return; + + const message: MessageType = { + content: data.content, + userName: user.userName, + isMyMessage: false, + time: new Date(data.time).toLocaleTimeString(), + }; + + setMessages(prev => [...prev, message]); + } + } + }); + + if (isLoading) { + return ( + + + + ); + } + + /** + * Unselected user + */ + if (!chatId || !selectedUser) { + return ( + + + + + Select a chat to start messaging + + + + ); + } + + return ( + + + + + {isMe && me ? 'Favorites' : selectedUser.fullname} + + {!isMe && ( + + See profile + + )} + + + +
onSubmit(e)}> + + + } + aria-label='Send message' + variant={'ghost'} + _hover={{ bg: 'inherit' }} + _active={{ bg: 'inherit' }} + _focus={{ outline: 'none' }} + /> + +
+
+
+ ); +}; + +export { Window }; diff --git a/src/components/Chat/Window/index.ts b/src/components/Chat/Window/index.ts new file mode 100644 index 0000000..6ec26f3 --- /dev/null +++ b/src/components/Chat/Window/index.ts @@ -0,0 +1 @@ +export { Window } from './Window'; diff --git a/src/components/Chat/context.ts b/src/components/Chat/context.ts new file mode 100644 index 0000000..246853b --- /dev/null +++ b/src/components/Chat/context.ts @@ -0,0 +1,21 @@ +import React, { useContext, createContext } from 'react'; + +export type ChatContextType = { + search: string; + setSearch: React.Dispatch>; +}; + +export const ChatContext = createContext({ + search: '', + setSearch: () => undefined, +}); + +export const useChatContext = () => { + const context = useContext(ChatContext); + + if (!context) { + throw new Error('ChatContext was outside of its provider'); + } + + return context; +}; diff --git a/src/components/Chat/index.tsx b/src/components/Chat/index.tsx new file mode 100644 index 0000000..c2ea525 --- /dev/null +++ b/src/components/Chat/index.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { Grid, GridItemProps, GridProps } from '@chakra-ui/react'; +import { Sidebar } from './Sidebar'; +import { Window } from './Window'; +import { ISidebarComposition } from './Sidebar/Sidebar'; +import { ChatContextProvider } from './ChatContextProvider'; + +interface IChatComposition { + Sidebar: React.FC & ISidebarComposition; + Window: React.FC; +} + +const Chat: React.FC & IChatComposition = props => { + return ( + + + {props.children} + + + ); +}; + +Chat.Sidebar = Sidebar; +Chat.Window = Window; + +export { Chat }; diff --git a/src/components/ColorModeSwitcher/ColorModeSwitcher.tsx b/src/components/ColorModeSwitcher/ColorModeSwitcher.tsx index bdeb9a5..0ab80da 100644 --- a/src/components/ColorModeSwitcher/ColorModeSwitcher.tsx +++ b/src/components/ColorModeSwitcher/ColorModeSwitcher.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { useColorMode, useColorModeValue, IconButton, IconButtonProps } from '@chakra-ui/react'; import { FaMoon, FaSun } from 'react-icons/fa'; -type ColorModeSwitcherProps = Omit; +export type ColorModeSwitcherProps = Omit; const ColorModeSwitcher: React.FC = props => { const { toggleColorMode } = useColorMode(); diff --git a/src/components/ConfirmDialog/ConfirmDialog.tsx b/src/components/ConfirmDialog/ConfirmDialog.tsx index 156b5e1..2621c37 100644 --- a/src/components/ConfirmDialog/ConfirmDialog.tsx +++ b/src/components/ConfirmDialog/ConfirmDialog.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React from 'react'; import { AlertDialog, AlertDialogBody, diff --git a/src/components/ConfirmDialog/index.ts b/src/components/ConfirmDialog/index.ts new file mode 100644 index 0000000..8e034e4 --- /dev/null +++ b/src/components/ConfirmDialog/index.ts @@ -0,0 +1,3 @@ +import ConfirmDialog from './ConfirmDialog'; + +export default ConfirmDialog; diff --git a/src/components/Dialogs/DeleteCategoryDialog/DeleteCategoryDialog.tsx b/src/components/Dialogs/DeleteCategoryDialog/DeleteCategoryDialog.tsx new file mode 100644 index 0000000..750cee7 --- /dev/null +++ b/src/components/Dialogs/DeleteCategoryDialog/DeleteCategoryDialog.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import ConfirmDialog from '@educt/components/ConfirmDialog'; +import { ICategory } from '@educt/interfaces'; +import useIsMountedRef from '@educt/hooks/useIsMountedRef'; +import { useDeleteCategory } from '@educt/hooks/queries'; + +type DeleteCategoryDialogPropsType = { + category: ICategory; + isOpen: boolean; + onClose: () => void; + onDeleted?: (category: ICategory) => void | undefined; +}; + +const DeleteCategoryDialog: React.FC = ({ onClose, onDeleted, isOpen, category }) => { + const { deleteCategory, isLoading } = useDeleteCategory(); + const isMountedRef = useIsMountedRef(); + const handleDelete = async (isConfirmed: boolean, id: string) => { + if (isConfirmed) { + try { + await deleteCategory(id); + onDeleted && onDeleted(category); + } catch (error) { + console.error(error); + } + } + + if (isMountedRef.current) { + /** + * Close dialog + */ + onClose(); + } + }; + + return ( + handleDelete(isConfirmed, category.id)} + title='Confirm deleting' + message={`The category with title "${category.title}" will be removed from the system. After deleting a category, the courses in it will also be deleted.`} + confirmMessage='Delete' + /> + ); +}; + +export default DeleteCategoryDialog; diff --git a/src/components/Dialogs/DeleteCategoryDialog/index.ts b/src/components/Dialogs/DeleteCategoryDialog/index.ts new file mode 100644 index 0000000..81e92bb --- /dev/null +++ b/src/components/Dialogs/DeleteCategoryDialog/index.ts @@ -0,0 +1,3 @@ +import DeleteCategoryDialog from './DeleteCategoryDialog'; + +export default DeleteCategoryDialog; diff --git a/src/components/Dialogs/DeleteCourseDialog/DeleteCourseDialog.tsx b/src/components/Dialogs/DeleteCourseDialog/DeleteCourseDialog.tsx new file mode 100644 index 0000000..b49c904 --- /dev/null +++ b/src/components/Dialogs/DeleteCourseDialog/DeleteCourseDialog.tsx @@ -0,0 +1,64 @@ +import React from 'react'; + +/** + * Types + */ +import { ICourse } from '@educt/interfaces'; + +/** + * Components + */ +import ConfirmDialog from '@educt/components/ConfirmDialog/ConfirmDialog'; + +/** + * Hooks + */ +import { useDeleteCourse } from '@educt/hooks/queries/course/useDeleteCourse'; +import { useHistory, useLocation } from 'react-router'; +import useIsMountedRef from '@educt/hooks/useIsMountedRef'; + +type DeleteCourseDialogPropsType = { + course: Pick; + onClose: () => void; + isOpen: boolean; +}; + +const DeleteCourseDialog: React.FC = ({ onClose, isOpen, course }) => { + const { deleteCourse, isLoading } = useDeleteCourse(); + const isMountedRef = useIsMountedRef(); + const history = useHistory(); + const location = useLocation(); + + const handleDelete = async (isConfirmed: boolean, id: string) => { + if (isConfirmed) { + try { + await deleteCourse(id); + if (isMountedRef.current && location.pathname !== '/courses') { + history.push('/courses'); + } + } catch (error) { + console.error(error); + } + } + + if (isMountedRef.current) { + /** + * Close dialog + */ + onClose(); + } + }; + + return ( + handleDelete(isConfirmed, course.id)} + title='Confirm deleting' + message={`The course with title "${course.title}" will be removed from the system. After deleting a course, the lessons in it will also be deleted.`} + confirmMessage='Delete' + /> + ); +}; + +export default DeleteCourseDialog; diff --git a/src/pages/courses/components/DeleteCourseDialog/index.ts b/src/components/Dialogs/DeleteCourseDialog/index.ts similarity index 100% rename from src/pages/courses/components/DeleteCourseDialog/index.ts rename to src/components/Dialogs/DeleteCourseDialog/index.ts diff --git a/src/components/Dialogs/DeleteLessonDialog/DeleteLessonDialog.tsx b/src/components/Dialogs/DeleteLessonDialog/DeleteLessonDialog.tsx new file mode 100644 index 0000000..c7a74d1 --- /dev/null +++ b/src/components/Dialogs/DeleteLessonDialog/DeleteLessonDialog.tsx @@ -0,0 +1,56 @@ +import React from 'react'; + +/** + * Types + */ +import { ILesson } from '@educt/interfaces'; + +/** + * Components + */ +import ConfirmDialog from '@educt/components/ConfirmDialog/ConfirmDialog'; + +/** + * Hooks + */ +import { useDeleteLesson } from '@educt/hooks/queries'; + +type DeleteLessonDialogPropsType = { + lesson: Pick; + isOpen: boolean; + onClose: () => void; + onConfirmed?: (id: string) => void | undefined; +}; + +const DeleteLessonDialog: React.FC = ({ lesson, isOpen, onConfirmed, onClose }) => { + const { deleteLesson, isLoading } = useDeleteLesson(); + + const handleDelete = async (isConfirmed: boolean) => { + if (isConfirmed) { + try { + await deleteLesson(lesson.id); + onConfirmed && onConfirmed(lesson.id); + } catch (error) { + console.error(error); + } + } + + /** + * Close dialog + */ + onClose(); + }; + + return ( + handleDelete(isConfirmed)} + title='Confirm deleting' + message={`Lesson with will be removed from the course. Attached materials will also be removed.`} + confirmMessage='Delete' + /> + ); +}; + +export default DeleteLessonDialog; diff --git a/src/components/Dialogs/DeleteLessonDialog/index.ts b/src/components/Dialogs/DeleteLessonDialog/index.ts new file mode 100644 index 0000000..0336573 --- /dev/null +++ b/src/components/Dialogs/DeleteLessonDialog/index.ts @@ -0,0 +1,3 @@ +import DeleteLessonDialog from './DeleteLessonDialog'; + +export default DeleteLessonDialog; diff --git a/src/pages/users/components/DeleteUserDialog/DeleteUserDialog.tsx b/src/components/Dialogs/DeleteUserDialog/DeleteUserDialog.tsx similarity index 63% rename from src/pages/users/components/DeleteUserDialog/DeleteUserDialog.tsx rename to src/components/Dialogs/DeleteUserDialog/DeleteUserDialog.tsx index d8b760e..dfbc1c1 100644 --- a/src/pages/users/components/DeleteUserDialog/DeleteUserDialog.tsx +++ b/src/components/Dialogs/DeleteUserDialog/DeleteUserDialog.tsx @@ -18,23 +18,20 @@ import { UsersPageContext } from '@educt/contexts'; /** * Hooks */ -import { useContext, useState } from 'react'; +import { useContext } from 'react'; import { useRootStore } from '@educt/hooks/useRootStore'; -import { useToast } from '@chakra-ui/react'; -import { useErrorHandler } from 'react-error-boundary'; +import { useDeleteUser } from '@educt/hooks/queries'; type DeleteUserDialogPropsType = { - user: IUser; + user: Pick; isOpen: boolean; onClose: () => void; }; const DeleteUserDialog: React.FC = ({ isOpen, onClose, user }) => { const { userStore } = useRootStore(); - const { setDeletingUser, searchingRole, searchingPage, search } = useContext(UsersPageContext); - const [isLoading, setIsLoading] = useState(false); - const handleError = useErrorHandler(); - const toast = useToast(); + const { searchingRole, searchingPage, search } = useContext(UsersPageContext); + const { deleteUser, isLoading } = useDeleteUser(); const { pagination } = userStore; @@ -47,23 +44,14 @@ const DeleteUserDialog: React.FC = ({ isOpen, onClose const deleteUserHandler = async (isConfirmed: boolean, id: string) => { if (isConfirmed) { try { - setIsLoading(true); - await userStore.deleteUser(id, { + await deleteUser(id, { page: searchingPage, limit: pagination?.per_page, role: searchingRole, search, }); - toast({ title: 'User deleted.', status: 'info' }); - } catch (error: any) { - if (error.response) { - toast({ title: error.message, status: 'error' }); - } else { - handleError(error); - } - } finally { - setIsLoading(false); - setDeletingUser(undefined); + } catch (error) { + console.error(error); } } diff --git a/src/pages/users/components/DeleteUserDialog/index.ts b/src/components/Dialogs/DeleteUserDialog/index.ts similarity index 100% rename from src/pages/users/components/DeleteUserDialog/index.ts rename to src/components/Dialogs/DeleteUserDialog/index.ts diff --git a/src/components/ErrorFallback.tsx b/src/components/ErrorFallback.tsx index eb76168..5d7f0b5 100644 --- a/src/components/ErrorFallback.tsx +++ b/src/components/ErrorFallback.tsx @@ -1,6 +1,8 @@ import React from 'react'; import Cookies from 'js-cookie'; -import { Flex, Box, Heading, Text } from '@chakra-ui/react'; +import axios, { AxiosError } from 'axios'; +import { Redirect } from 'react-router'; +import { Icon, Box, Heading, Text } from '@chakra-ui/react'; import { MdError } from 'react-icons/md'; /** @@ -9,9 +11,8 @@ import { MdError } from 'react-icons/md'; import { useEffect } from 'react'; import { useToast } from '@chakra-ui/toast'; import { useRootStore } from '@educt/hooks/useRootStore'; -import { Redirect } from 'react-router'; -const ErrorFallback: React.FC<{ error: any }> = props => { +const ErrorFallback: React.FC<{ error: Error | AxiosError }> = props => { const { userStore, authStore } = useRootStore(); const { error } = props; const toast = useToast(); @@ -20,19 +21,19 @@ const ErrorFallback: React.FC<{ error: any }> = props => { toast({ title: `${error.message}`, duration: 10000, isClosable: true, status: 'error' }); }); - if (error.response) { - if (error.response.status === 401) { - userStore.me = null; - authStore.setIsLoggedIn(false); - Cookies.remove('logged_in'); - } else if (error.response.status === 404) return ; + if (axios.isAxiosError(error)) { + if (error.response) { + if (error.response.status === 401) { + userStore.me = null; + authStore.setIsLoggedIn(false); + Cookies.remove('logged_in'); + } else if (error.response.status === 404) return ; + } } return ( - - - + Something went wrong diff --git a/src/components/Fields/PasswordField.tsx b/src/components/Fields/PasswordField.tsx new file mode 100644 index 0000000..38d25f9 --- /dev/null +++ b/src/components/Fields/PasswordField.tsx @@ -0,0 +1,80 @@ +import React, { useRef } from 'react'; +import { + Box, + Flex, + FormControl, + FormLabel, + Text, + IconButton, + Input, + InputGroup, + InputProps, + InputRightElement, + InputLeftElement, + Icon, + useDisclosure, + useMergeRefs, + useColorModeValue as mode, +} from '@chakra-ui/react'; +import { HiEye, HiEyeOff } from 'react-icons/hi'; +import { MdVpnKey } from 'react-icons/md'; + +interface PasswordFieldPropsType extends InputProps { + errorMessage?: string | undefined; +} + +export const PasswordField = React.forwardRef((props, ref) => { + const { errorMessage, ...other } = props; + const { isOpen, onToggle } = useDisclosure(); + const inputRef = useRef(null); + const mergeRef = useMergeRefs(inputRef, ref); + + const onClickReveal = () => { + onToggle(); + const input = inputRef.current; + if (input) { + input.focus({ preventScroll: true }); + const length = input.value.length * 2; + requestAnimationFrame(() => { + input.setSelectionRange(length, length); + }); + } + }; + + return ( + + + Password + + + + + + + : } + onClick={onClickReveal} + /> + + + + {errorMessage && ( + + {errorMessage} + + )} + + ); +}); + +PasswordField.displayName = 'PasswordField'; diff --git a/src/components/FileSelect/FileSelect.tsx b/src/components/FileSelect/FileSelect.tsx index 8e8eb88..21f69c2 100644 --- a/src/components/FileSelect/FileSelect.tsx +++ b/src/components/FileSelect/FileSelect.tsx @@ -60,8 +60,8 @@ const FileSelect: React.FC = ({ onChange, file, supportedFo ) : ( - - Choose a file... + + Select new file )} {supportedFormats && ( diff --git a/src/components/FilesUploader/FilesUploader.tsx b/src/components/FilesUploader/FilesUploader.tsx new file mode 100644 index 0000000..54967aa --- /dev/null +++ b/src/components/FilesUploader/FilesUploader.tsx @@ -0,0 +1,144 @@ +import React, { useState } from 'react'; +import * as helpers from '@educt/helpers'; +import { Stack, Flex, Box, Icon, Text, Input, IconButton, Button, useColorModeValue } from '@chakra-ui/react'; +import { MdAttachFile, MdOutlineFilePresent } from 'react-icons/md'; +import { CloseIcon } from '@chakra-ui/icons'; + +/** + * Hooks + */ +import { useRef } from 'react'; +import { FileSupportedFormatsEnum } from '@educt/enums'; +import { AttachmentFileType } from '@educt/types'; + +type FilesUploaderPropsType = { + onChange: (files: File[]) => void; + files?: File[] | undefined; + preloadedFiles?: AttachmentFileType[] | undefined; +}; + +const FileContent: React.FC<{ name: string; size: number }> = ({ name, size }) => ( + + + + {name} +
+ + {helpers.transformBytes(size)} + +
+
+); + +const FileWrapper: React.FC = ({ children }) => ( + + {children} + +); + +const FilesUploader: React.FC = ({ onChange, files, preloadedFiles }) => { + const [preloaded, setPreloaded] = useState(preloadedFiles || []); + const fileInputRef = useRef(null); + + const onSelectFileHandler = () => { + if (fileInputRef.current) { + fileInputRef.current.click(); + } + }; + + /** + * Detach file + */ + const onRemoveSelectedFileHandler = (selectedFile: File) => () => { + onChange([...Array.from(files?.filter(file => file.name !== selectedFile.name) || [])]); + }; + + /** + * Attach file + */ + const onChangeFileHandler = (e: React.ChangeEvent) => { + e.preventDefault(); + + if (e.target.files && e.target.files.length !== 0) { + const isAlreadySelected = (files || []).find(selectedFile => + Array.from(e.target.files || []).some(file => file.name === selectedFile.name) + ); + + if (isAlreadySelected) return; + onChange([...Array.from(files || []), ...e.target.files]); + } + }; + + return ( + + `.${ext.toLowerCase()}`) + .join(', ')} + /> + {preloadedFiles && files?.length === 0 && ( + + {preloaded.map((file, index) => ( + + + { + setPreloaded(prev => prev.filter(prevFile => prevFile.size !== file.size)); + onChange([]); + }} + aria-label='remove' + variant={'unstyled'} + size='xs' + icon={} + /> + + ))} + + )} + {files && ( + + {files.map((file, index) => ( + + + } + /> + + ))} + + )} + {files?.length === 0 && preloaded?.length === 0 && ( + + No file selected + + )} + + + ); +}; + +export default FilesUploader; diff --git a/src/components/FilesUploader/index.ts b/src/components/FilesUploader/index.ts new file mode 100644 index 0000000..9ba1ae9 --- /dev/null +++ b/src/components/FilesUploader/index.ts @@ -0,0 +1,3 @@ +import FilesUploader from './FilesUploader'; + +export default FilesUploader; diff --git a/src/components/Forms/CourseForm/CourseForm.tsx b/src/components/Forms/CourseForm/CourseForm.tsx index 55e077b..530b5f1 100644 --- a/src/components/Forms/CourseForm/CourseForm.tsx +++ b/src/components/Forms/CourseForm/CourseForm.tsx @@ -19,15 +19,19 @@ import FileSelect from '@educt/components/FileSelect'; /** * Hooks */ -import { useToast } from '@chakra-ui/toast'; -import { useRootStore } from '@educt/hooks/useRootStore'; import { useErrorHandler } from 'react-error-boundary'; +/** + * Services + */ +import { CategoryServiceInstance, UserServiceInstance } from '@educt/services'; + export type InputFields = { title: string; image?: File | undefined; category_id: string; description: string; + education_description: string | null; teacher_id: string; }; @@ -46,30 +50,21 @@ const CourseForm: React.FC = ({ onSubmit, buttonLabel, isLo formState: { errors, isDirty }, } = reactHookForm; - const { - userStore: { userService }, - categoryStore: { categoryService }, - } = useRootStore(); const handleError = useErrorHandler(); - const toast = useToast(); /** * Load users into select field */ const loadUsersOptions = async (): Promise => { try { - const users = await userService.fetchAll({ limit: 12, role: UserRoleEnum.TEACHER }); + const users = await UserServiceInstance.fetchAll({ limit: 12, role: UserRoleEnum.TEACHER }); return users.data.map(user => ({ label: user.fullname, value: user.id, })); - } catch (error: any) { - if (error.response) { - toast({ title: 'Error' }); - } else { - handleError(error); - } + } catch (error) { + handleError(error); } }; @@ -78,22 +73,19 @@ const CourseForm: React.FC = ({ onSubmit, buttonLabel, isLo */ const loadCategoriesOptions = async (): Promise => { try { - const categories = await categoryService.fetchAll(); + const categories = await CategoryServiceInstance.fetchAll(); return categories.data.map(category => ({ label: category.title, value: category.id, })); - } catch (error: any) { - if (error.response) { - toast({ title: 'Error' }); - } else { - handleError(error); - } + } catch (error) { + handleError(error); } }; const watchTitle = watch('title'); const watchDescription = watch('description'); + const watchEducationDescription = watch('education_description'); return (
@@ -102,14 +94,11 @@ const CourseForm: React.FC = ({ onSubmit, buttonLabel, isLo Name - 90 ? 'red.500' : 'gray.500'}> - {watchTitle?.length || 0}/90 - - } - /> + + 90 ? 'red.500' : 'gray.500'}> + {watchTitle?.length || 0}/90 + + e.g Web Development in Javascript @@ -130,6 +119,26 @@ const CourseForm: React.FC = ({ onSubmit, buttonLabel, isLo + + What you'll learn section +