diff --git a/kpoint-react/package-lock.json b/kpoint-react/package-lock.json index c7da7e1c..efc7652e 100644 --- a/kpoint-react/package-lock.json +++ b/kpoint-react/package-lock.json @@ -10,7 +10,6 @@ "dependencies": { "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", - "@lexical/react": "^0.13.1", "@mdi/js": "^7.4.47", "@mui/icons-material": "^5.15.8", "@mui/lab": "^5.0.0-alpha.167", @@ -18,14 +17,14 @@ "@react-oauth/google": "^0.12.1", "@reduxjs/toolkit": "^1.9.7", "i18next": "^23.7.18", - "lexical": "^0.13.1", "mdi-material-ui": "^7.8.0", "query-string": "^8.2.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-google-button": "^0.7.2", - "react-hook-form": "^7.49.3", + "react-hook-form": "^7.51.2", "react-i18next": "^14.0.1", + "react-markdown": "^9.0.1", "react-redux": "^8.1.0", "react-responsive-masonry": "^2.2.0", "react-router-dom": "^6.22.0", @@ -3728,243 +3727,6 @@ "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, - "node_modules/@lexical/clipboard": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.13.1.tgz", - "integrity": "sha512-gMSbVeqb7S+XAi/EMMlwl+FCurLPugN2jAXcp5k5ZaUd7be8B+iupbYdoKkjt4qBhxmvmfe9k46GoC0QOPl/nw==", - "dependencies": { - "@lexical/html": "0.13.1", - "@lexical/list": "0.13.1", - "@lexical/selection": "0.13.1", - "@lexical/utils": "0.13.1" - }, - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/code": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.13.1.tgz", - "integrity": "sha512-QK77r3QgEtJy96ahYXNgpve8EY64BQgBSnPDOuqVrLdl92nPzjqzlsko2OZldlrt7gjXcfl9nqfhZ/CAhStfOg==", - "dependencies": { - "@lexical/utils": "0.13.1", - "prismjs": "^1.27.0" - }, - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/dragon": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.13.1.tgz", - "integrity": "sha512-aNlqfif4//jW7gOxbBgdrbDovU6m3EwQrUw+Y/vqRkY+sWmloyAUeNwCPH1QP3Q5cvfolzOeN5igfBljsFr+1g==", - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/hashtag": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.13.1.tgz", - "integrity": "sha512-Dl0dUG4ZXNjYYuAUR0GMGpLGsA+cps2/ln3xEmy28bZR0sKkjXugsu2QOIxZjYIPBewDrXzPcvK8md45cMYoSg==", - "dependencies": { - "@lexical/utils": "0.13.1" - }, - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/history": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.13.1.tgz", - "integrity": "sha512-cZXt30MalEEiRaflE9tHeGYnwT1xSDjXLsf9M409DSU9POJyZ1fsULJrG1tWv2uFQOhwal33rve9+MatUlITrg==", - "dependencies": { - "@lexical/utils": "0.13.1" - }, - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/html": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.13.1.tgz", - "integrity": "sha512-XkZrnCSHIUavtpMol6aG8YsJ5KqC9hMxEhAENf3HTGi3ocysCByyXOyt1EhEYpjJvgDG4wRqt25xGDbLjj1/sA==", - "dependencies": { - "@lexical/selection": "0.13.1", - "@lexical/utils": "0.13.1" - }, - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/link": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.13.1.tgz", - "integrity": "sha512-7E3B2juL2UoMj2n+CiyFZ7tlpsdViAoIE7MpegXwfe/VQ66wFwk/VxGTa/69ng2EoF7E0kh+SldvGQDrWAWb1g==", - "dependencies": { - "@lexical/utils": "0.13.1" - }, - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/list": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.13.1.tgz", - "integrity": "sha512-6U1pmNZcKLuOWiWRML8Raf9zSEuUCMlsOye82niyF6I0rpPgYo5UFghAAbGISDsyqzM1B2L4BgJ6XrCk/dJptg==", - "dependencies": { - "@lexical/utils": "0.13.1" - }, - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/mark": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.13.1.tgz", - "integrity": "sha512-dW27PW8wWDOKFqXTBUuUfV+umU0KfwvXGkPUAxRJrvwUWk5RKaS48LhgbNlQ5BfT84Q8dSiQzvbaa6T40t9a3A==", - "dependencies": { - "@lexical/utils": "0.13.1" - }, - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/markdown": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.13.1.tgz", - "integrity": "sha512-6tbdme2h5Zy/M88loVQVH5G0Nt7VMR9UUkyiSaicyBRDOU2OHacaXEp+KSS/XuF+d7TA+v/SzyDq8HS77cO1wA==", - "dependencies": { - "@lexical/code": "0.13.1", - "@lexical/link": "0.13.1", - "@lexical/list": "0.13.1", - "@lexical/rich-text": "0.13.1", - "@lexical/text": "0.13.1", - "@lexical/utils": "0.13.1" - }, - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/offset": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.13.1.tgz", - "integrity": "sha512-j/RZcztJ7dyTrfA2+C3yXDzWDXV+XmMpD5BYeQCEApaHvlo20PHt1BISk7RcrnQW8PdzGvpKblRWf//c08LS9w==", - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/overflow": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.13.1.tgz", - "integrity": "sha512-Uw34j+qG2UJRCIR+bykfFMduFk7Pc4r/kNt8N1rjxGuGXAsreTVch1iOhu7Ev6tJgkURsduKuaJCAi7iHnKl7g==", - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/plain-text": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.13.1.tgz", - "integrity": "sha512-4j5KAsMKUvJ8LhVDSS4zczbYXzdfmgYSAVhmqpSnJtud425Nk0TAfpUBLFoivxZB7KMoT1LGWQZvd47IvJPvtA==", - "peerDependencies": { - "@lexical/clipboard": "0.13.1", - "@lexical/selection": "0.13.1", - "@lexical/utils": "0.13.1", - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/react": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.13.1.tgz", - "integrity": "sha512-Sy6EL230KAb0RZsZf1dZrRrc3+rvCDQWltcd8C/cqBUYlxsLYCW9s4f3RB2werngD/PtLYbBB48SYXNkIALITA==", - "dependencies": { - "@lexical/clipboard": "0.13.1", - "@lexical/code": "0.13.1", - "@lexical/dragon": "0.13.1", - "@lexical/hashtag": "0.13.1", - "@lexical/history": "0.13.1", - "@lexical/link": "0.13.1", - "@lexical/list": "0.13.1", - "@lexical/mark": "0.13.1", - "@lexical/markdown": "0.13.1", - "@lexical/overflow": "0.13.1", - "@lexical/plain-text": "0.13.1", - "@lexical/rich-text": "0.13.1", - "@lexical/selection": "0.13.1", - "@lexical/table": "0.13.1", - "@lexical/text": "0.13.1", - "@lexical/utils": "0.13.1", - "@lexical/yjs": "0.13.1", - "react-error-boundary": "^3.1.4" - }, - "peerDependencies": { - "lexical": "0.13.1", - "react": ">=17.x", - "react-dom": ">=17.x" - } - }, - "node_modules/@lexical/rich-text": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.13.1.tgz", - "integrity": "sha512-HliB9Ync06mv9DBg/5j0lIsTJp+exLHlaLJe+n8Zq1QNTzZzu2LsIT/Crquk50In7K/cjtlaQ/d5RB0LkjMHYg==", - "peerDependencies": { - "@lexical/clipboard": "0.13.1", - "@lexical/selection": "0.13.1", - "@lexical/utils": "0.13.1", - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/selection": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.13.1.tgz", - "integrity": "sha512-Kt9eSwjxPznj7yzIYipu9yYEgmRJhHiq3DNxHRxInYcZJWWNNHum2xKyxwwcN8QYBBzgfPegfM/geqQEJSV1lQ==", - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/table": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.13.1.tgz", - "integrity": "sha512-VQzgkfkEmnvn6C64O/kvl0HI3bFoBh3WA/U67ALw+DS11Mb5CKjbt0Gzm/258/reIxNMpshjjicpWMv9Miwauw==", - "dependencies": { - "@lexical/utils": "0.13.1" - }, - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/text": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.13.1.tgz", - "integrity": "sha512-NYy3TZKt3qzReDwN2Rr5RxyFlg84JjXP2JQGMrXSSN7wYe73ysQIU6PqdVrz4iZkP+w34F3pl55dJ24ei3An9w==", - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/utils": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.13.1.tgz", - "integrity": "sha512-AtQQKzYymkbOaQxaBXjRBS8IPxF9zWQnqwHTUTrJqJ4hX71aIQd/thqZbfQETAFJfC8pNBZw5zpxN6yPHk23dQ==", - "dependencies": { - "@lexical/list": "0.13.1", - "@lexical/selection": "0.13.1", - "@lexical/table": "0.13.1" - }, - "peerDependencies": { - "lexical": "0.13.1" - } - }, - "node_modules/@lexical/yjs": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.13.1.tgz", - "integrity": "sha512-4GbqQM+PwNTV59AZoNrfTe/0rLjs+cX6Y6yAdZSRPBwr5L3JzYeU1TTcFCVQTtsE7KF8ddVP8sD7w9pi8rOWLA==", - "dependencies": { - "@lexical/offset": "0.13.1" - }, - "peerDependencies": { - "lexical": "0.13.1", - "yjs": ">=13.5.22" - } - }, "node_modules/@ls-lint/ls-lint": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/@ls-lint/ls-lint/-/ls-lint-2.2.2.tgz", @@ -4990,6 +4752,14 @@ "@types/node": "*" } }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/eslint": { "version": "8.56.2", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", @@ -5013,6 +4783,14 @@ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/express": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", @@ -5043,6 +4821,14 @@ "@types/node": "*" } }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", @@ -5143,6 +4929,14 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, + "node_modules/@types/mdast": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", + "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -5154,6 +4948,11 @@ "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "dev": true }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, "node_modules/@types/node": { "version": "20.11.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz", @@ -5316,6 +5115,11 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==" }, + "node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, "node_modules/@types/use-sync-external-store": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", @@ -5541,6 +5345,11 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -6455,6 +6264,15 @@ "babel-plugin-transform-react-remove-prop-types": "^0.4.24" } }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -6771,6 +6589,15 @@ "node": ">=4" } }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6794,6 +6621,42 @@ "node": ">=10" } }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/check-types": { "version": "11.2.3", "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz", @@ -7043,6 +6906,15 @@ "node": ">= 0.8" } }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -7768,6 +7640,18 @@ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/decode-uri-component": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.4.1.tgz", @@ -7960,6 +7844,18 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -9058,6 +8954,15 @@ "node": ">=4.0" } }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/estree-walker": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", @@ -9192,6 +9097,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -10042,6 +9952,44 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", + "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -10215,6 +10163,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/html-url-attributes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.0.tgz", + "integrity": "sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/html-webpack-plugin": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", @@ -10530,6 +10487,11 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, + "node_modules/inline-style-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.3.tgz", + "integrity": "sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==" + }, "node_modules/internal-slot": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", @@ -10551,6 +10513,28 @@ "node": ">= 10" } }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -10672,6 +10656,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -10746,6 +10739,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", @@ -10983,16 +10985,6 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, - "node_modules/isomorphic.js": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz", - "integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==", - "peer": true, - "funding": { - "type": "GitHub Sponsors ❤", - "url": "https://github.com/sponsors/dmonad" - } - }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -13700,32 +13692,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lexical": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.13.1.tgz", - "integrity": "sha512-jaqRYzVEfBKbX4FwYpd/g+MyOjRaraAel0iQsTrwvx3hyN0bswUZuzb6H6nGlFSjcdrc77wKpyKwoWj4aUd+Bw==" - }, - "node_modules/lib0": { - "version": "0.2.91", - "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.91.tgz", - "integrity": "sha512-LRcTp8RmdHexL8olb7qErdROnJ2L6Js5Am99WQo0hiTRDWtk6vyUJJjTB6I/RcW8jwNQshM3NqH598DdhSOajA==", - "peer": true, - "dependencies": { - "isomorphic.js": "^0.2.4" - }, - "bin": { - "0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js", - "0gentesthtml": "bin/gentesthtml.js", - "0serve": "bin/0serve.js" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "type": "GitHub Sponsors ❤", - "url": "https://github.com/sponsors/dmonad" - } - }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -13810,11 +13776,20 @@ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { @@ -13906,6 +13881,151 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", + "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", + "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.2.tgz", + "integrity": "sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-remove-position": "^5.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.1.0.tgz", + "integrity": "sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", + "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdi-material-ui": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/mdi-material-ui/-/mdi-material-ui-7.8.0.tgz", @@ -14003,6 +14123,427 @@ "node": ">= 0.6" } }, + "node_modules/micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz", + "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz", + "integrity": "sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, "node_modules/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", @@ -14697,6 +15238,30 @@ "node": ">=6" } }, + "node_modules/parse-entities": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", + "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -16287,14 +16852,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", - "engines": { - "node": ">=6" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -16335,6 +16892,15 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -16601,21 +17167,6 @@ "react": "^18.2.0" } }, - "node_modules/react-error-boundary": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", - "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - }, - "peerDependencies": { - "react": ">=16.13.1" - } - }, "node_modules/react-error-overlay": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", @@ -16633,12 +17184,11 @@ } }, "node_modules/react-hook-form": { - "version": "7.49.3", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.49.3.tgz", - "integrity": "sha512-foD6r3juidAT1cOZzpmD/gOKt7fRsDhXXZ0y28+Al1CHgX+AY1qIN9VSIIItXRq1dN68QrRwl1ORFlwjBaAqeQ==", + "version": "7.51.2", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.51.2.tgz", + "integrity": "sha512-y++lwaWjtzDt/XNnyGDQy6goHskFualmDlf+jzEZvjvz6KWDf7EboL7pUvRCzPTJd0EOPpdekYaQLEvvG6m6HA==", "engines": { - "node": ">=18", - "pnpm": "8" + "node": ">=12.22.0" }, "funding": { "type": "opencollective", @@ -16674,6 +17224,31 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "node_modules/react-markdown": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.1.tgz", + "integrity": "sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg==", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, "node_modules/react-redux": { "version": "8.1.3", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz", @@ -18203,6 +18778,37 @@ "node": ">= 0.10" } }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.0.tgz", + "integrity": "sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/renderkid": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", @@ -18975,6 +19581,15 @@ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "deprecated": "Please use @jridgewell/sourcemap-codec instead" }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -19317,6 +19932,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/stringify-object": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", @@ -19421,6 +20049,14 @@ "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", "dev": true }, + "node_modules/style-to-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.6.tgz", + "integrity": "sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==", + "dependencies": { + "inline-style-parser": "0.2.3" + } + }, "node_modules/stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", @@ -20247,6 +20883,15 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/trim-newlines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", @@ -20256,6 +20901,15 @@ "node": ">=8" } }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/tryer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", @@ -20503,6 +21157,35 @@ "node": ">=4" } }, + "node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unique-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", @@ -20514,6 +21197,82 @@ "node": ">=8" } }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -20677,6 +21436,33 @@ "node": ">= 0.8" } }, + "node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", @@ -21627,23 +22413,6 @@ "node": ">=12" } }, - "node_modules/yjs": { - "version": "13.6.14", - "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.14.tgz", - "integrity": "sha512-D+7KcUr0j+vBCUSKXXEWfA+bG4UQBviAwP3gYBhkstkgwy5+8diOPMx0iqLIOxNo/HxaREUimZRxqHGAHCL2BQ==", - "peer": true, - "dependencies": { - "lib0": "^0.2.86" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=8.0.0" - }, - "funding": { - "type": "GitHub Sponsors ❤", - "url": "https://github.com/sponsors/dmonad" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -21654,6 +22423,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/kpoint-react/package.json b/kpoint-react/package.json index e1967b46..0490028b 100755 --- a/kpoint-react/package.json +++ b/kpoint-react/package.json @@ -6,7 +6,6 @@ "dependencies": { "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", - "@lexical/react": "^0.13.1", "@mdi/js": "^7.4.47", "@mui/icons-material": "^5.15.8", "@mui/lab": "^5.0.0-alpha.167", @@ -14,14 +13,14 @@ "@react-oauth/google": "^0.12.1", "@reduxjs/toolkit": "^1.9.7", "i18next": "^23.7.18", - "lexical": "^0.13.1", "mdi-material-ui": "^7.8.0", "query-string": "^8.2.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-google-button": "^0.7.2", - "react-hook-form": "^7.49.3", + "react-hook-form": "^7.51.2", "react-i18next": "^14.0.1", + "react-markdown": "^9.0.1", "react-redux": "^8.1.0", "react-responsive-masonry": "^2.2.0", "react-router-dom": "^6.22.0", diff --git a/kpoint-react/src/common/types/projects/projects-edit.type.ts b/kpoint-react/src/common/types/projects/projects-edit.type.ts index afb071b4..d28368e3 100644 --- a/kpoint-react/src/common/types/projects/projects-edit.type.ts +++ b/kpoint-react/src/common/types/projects/projects-edit.type.ts @@ -13,9 +13,5 @@ export type ProjectsEditType = { collectDeadline: string; goalSum: number; goalDeadline: string; - networksLinks: { - FACEBOOK: string | null; - INSTAGRAM: string | null; - YOUTUBE: string | null; - }; + networksLinks: object; }; \ No newline at end of file diff --git a/kpoint-react/src/common/types/projects/testRequest.ts b/kpoint-react/src/common/types/projects/testRequest.ts index 3b25e527..bd396f5d 100644 --- a/kpoint-react/src/common/types/projects/testRequest.ts +++ b/kpoint-react/src/common/types/projects/testRequest.ts @@ -1,4 +1,4 @@ -export type TestRequest = { +export type PostProject = { file: File | string, createdProject:{ title:string, @@ -9,6 +9,6 @@ export type TestRequest = { goalDeadline:string, collectDeadline:string, startSum:number, - networksLinks:{ FACEBOOK: string } + networksLinks: object, } }; diff --git a/kpoint-react/src/common/types/sign-up/sign-up.ts b/kpoint-react/src/common/types/sign-up/sign-up.ts index d7a91e0c..bb7cfd11 100644 --- a/kpoint-react/src/common/types/sign-up/sign-up.ts +++ b/kpoint-react/src/common/types/sign-up/sign-up.ts @@ -4,6 +4,7 @@ export type SignUpType = { username: string, email: string, password: string, + confirmPassword?: string, avatarImgUrl: string, description: string, tags: string[], diff --git a/kpoint-react/src/components/all-projects-page/projects-page.tsx b/kpoint-react/src/components/all-projects-page/projects-page.tsx index f5b673da..bde77976 100644 --- a/kpoint-react/src/components/all-projects-page/projects-page.tsx +++ b/kpoint-react/src/components/all-projects-page/projects-page.tsx @@ -21,7 +21,7 @@ const ProjectsPage: FC = () => { const projects = useAppSelector((state) => state.project.projects); - const isAuthenticated = useAppSelector((state) => state.token.isloggedIn); + const isAuthenticated = useAppSelector((state) => state.token.isLoggedIn); const [page, setPage] = useState(1); useLayoutEffect(() => { diff --git a/kpoint-react/src/components/all-projects-page/subscribe-button.tsx b/kpoint-react/src/components/all-projects-page/subscribe-button.tsx index cc21dde0..36e5fb56 100644 --- a/kpoint-react/src/components/all-projects-page/subscribe-button.tsx +++ b/kpoint-react/src/components/all-projects-page/subscribe-button.tsx @@ -1,7 +1,7 @@ import AddIcon from '@mui/icons-material/Add'; -// import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline'; -import { Typography } from '@mui/material'; +import { CircularProgress, Typography } from '@mui/material'; import Button from '@mui/material/Button'; +import { useAppSelector } from 'hooks/use-app-selector/use-app-selector.hook'; import { FC, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; @@ -10,10 +10,6 @@ import { projectAction } from 'store/actions'; import { StorageKey } from '../../common/enums/enums'; import { useAppDispatch } from '../../hooks/use-app-dispatch/use-app-dispatch.hook'; import { storage } from '../../services/services'; -import { - subscribeToProjectLocally, - unsubscribeFromProjectLocally, -} from '../../store/projects/reducer'; interface SubscribeButtonProps { projectId: string; @@ -33,6 +29,7 @@ const SubscribeButton: FC = ({ const dispatch = useAppDispatch(); const user = storage.getItem(StorageKey.TOKEN); const [isProcessing, setIsProcessing] = useState(false); + const isSubscribePending = useAppSelector((state) => state.project.isSubscribePending); const handleButtonSubClick = async (): Promise => { if (isProcessing) return; @@ -46,7 +43,6 @@ const SubscribeButton: FC = ({ await dispatch( projectAction.subscribeToProject({ projectId: projectId }), ); - dispatch(subscribeToProjectLocally(projectId)); toast.success(t('buttons.user_subscribed')); dispatch( projectAction.getAllProjectsDefault({ @@ -56,7 +52,6 @@ const SubscribeButton: FC = ({ ); } else if (user && isFollowed) { dispatch(projectAction.unSubscribe({ projectId: projectId })); - dispatch(unsubscribeFromProjectLocally(!isFollowed)); toast.success(t('buttons.user_unsubscribed')); } setIsProcessing(false); @@ -85,14 +80,20 @@ const SubscribeButton: FC = ({ }} onClick={handleButtonSubClick} > - {isFollowed ? ( - - {t('buttons.unfollow')} - - ) : ( - - {t('buttons.follow')} - + {isSubscribePending ? : ( + <> + {isFollowed ? ( + + {t('buttons.unfollow')} + + ) : ( + + {t('buttons.follow')} + + )} + )} ); diff --git a/kpoint-react/src/components/auth-page/oauth2.tsx b/kpoint-react/src/components/auth-page/oauth2.tsx index 33cf05d9..ec94ef59 100644 --- a/kpoint-react/src/components/auth-page/oauth2.tsx +++ b/kpoint-react/src/components/auth-page/oauth2.tsx @@ -1,7 +1,7 @@ import './oauth2.css'; import { useGoogleLogin } from '@react-oauth/google'; -import { FC, useEffect } from 'react'; +import { FC } from 'react'; import GoogleButton from 'react-google-button'; import { useNavigate } from 'react-router-dom'; import { toast } from 'react-toastify'; @@ -41,10 +41,6 @@ const OAuth2: FC = () => { }, }); - useEffect(() => { - login(); - }, [login]); - return (
diff --git a/kpoint-react/src/components/auth-page/sign-in-page.tsx b/kpoint-react/src/components/auth-page/sign-in-page.tsx index ee17e037..6768d9d5 100644 --- a/kpoint-react/src/components/auth-page/sign-in-page.tsx +++ b/kpoint-react/src/components/auth-page/sign-in-page.tsx @@ -1,3 +1,4 @@ + import LockOutlinedIcon from '@mui/icons-material/LockOutlined'; import { Divider, FormLabel } from '@mui/material'; import Avatar from '@mui/material/Avatar'; @@ -13,18 +14,16 @@ import TextField from '@mui/material/TextField'; import Typography from '@mui/material/Typography'; import { GoogleOAuthProvider } from '@react-oauth/google'; import * as React from 'react'; -import { FC, useState } from 'react'; +import { FC, useEffect } from 'react'; +import { SubmitHandler, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { toast } from 'react-toastify'; import { authAction } from 'store/actions'; -import { ENV, StorageKey } from '../../common/enums/enums'; -import { ResponseType } from '../../common/types/response/response'; +import { ENV } from '../../common/enums/enums'; import { SignInType } from '../../common/types/sign-in/sign-in'; import { useAppDispatch } from '../../hooks/hooks'; -import { storage } from '../../services/services'; -import { EmailRegx } from '../common/inputField/email-regx'; import { OAuth2 } from './oauth2'; const defaultTheme = createTheme(); @@ -33,69 +32,27 @@ const SignInPage: FC = () => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const navigate = useNavigate(); - const [loginError, setLoginError] = useState(null); - const [errors, setErrors] = useState>({}); - - const [formData, setFormData] = useState({ - email: '', - password: '', - }); - - React.useEffect(() => { + const { register, handleSubmit } = useForm(); + useEffect(() => { document.body.style.backgroundColor = '#E4E5E9'; }, []); - - const validateForm = (data: SignInType): Record => { - const errors: Record = {}; - - if(!EmailRegx.test(data.email) || data.email.trim() === '') { - toast.error(t('errors.invalid_email')); - errors.email = t('errors.invalid_email'); - } - - if (data.password.trim().length === 0) { - errors.password = t('errors.password_short'); - errors.confirmPassword = t('errors.password_short'); - toast.error(t('errors.password_short'), { position: 'top-right' }); - } - - return errors; + + const onSubmit = ( e: React.FormEvent ): void => { + e.preventDefault(); + + handleSubmit(signIn)(e); }; - const handleFieldFocus = (field: string): void => { - setErrors((prevErrors) => ({ ...prevErrors, [field]: '' })); - }; - - const handleSubmit = (event: React.FormEvent): void => { - event.preventDefault(); - - const formErrors = validateForm(formData); - setErrors(formErrors); - - if (Object.keys(formErrors).length > 0) { - return; - } - - dispatch(authAction.login(formData)) - .then((action) => { - const responseType: ResponseType = action.payload as ResponseType; - const user = responseType.user; - storage.setItem(StorageKey.TOKEN, responseType.token); - storage.setItem(StorageKey.USER, JSON.stringify(user)); + const signIn: SubmitHandler = async (data): Promise => { + + await dispatch(authAction.login(data)).then((requestStatus) => { + if (requestStatus.type === 'login/fulfilled') { navigate('/'); - }) - .catch(() => { - setLoginError('Невірний логін або пароль'); - }); - }; - - const handleOnChange = (event: React.ChangeEvent): void => { - event.preventDefault(); - const { name, value } = event.target; - setFormData((formData) => ({ - ...formData, - [name]: value, - })); + } + }).catch(() => { + toast.error(t('errors.can_not_login')); + }); + }; return ( @@ -128,39 +85,30 @@ const SignInPage: FC = () => { {t('welcome')} {t('sign_in_to_continue')} - + ): void => onSubmit(e)}> {t('email')} handleFieldFocus('email')} + autoComplete="email" autoFocus - error={!!errors.email} - helperText={errors.email} + {...register('email')} /> {t('password')} handleFieldFocus('password')} - error={!!errors.password} + autoComplete="current-password" + {...register('password')} /> - {loginError && {loginError}} { const { t } = useTranslation(); const dispatch = useAppDispatch(); const navigate = useNavigate(); - const [registerError, setRegisterError] = useState(null); - + const { register, handleSubmit, formState, getValues, setError } = useForm(); + const [showPassword, setShowPassword] = useState(false); + const [tag, setTag] = useState(''); const [formData, setFormData] = useState({ firstName: '', lastName: '', @@ -58,136 +57,84 @@ const SignUpPage: FC = () => { tags: [], }); - const location = useLocation(); - const [errors, setErrors] = useState>({}); - const [userData, setUserData] = useState({ - email: '', - avatarImgUrl: '', - }); - const [confirmPassword, setConfirmPassword] = useState(''); - useEffect(() => { - if (location.state && location.state.userData) { - const { email, avatarImgUrl } = location.state.userData; - setUserData({ email, avatarImgUrl }); - setFormData((formData) => ({ - ...formData, - email: email, - avatarImgUrl: avatarImgUrl, - })); - } - }, [location.state]); - - const [tag, setTag] = useState(''); - - React.useEffect(() => { document.body.style.backgroundColor = '#E4E5E9'; }, []); - const getChipTags = (): ChipTag[] => { - const result: ChipTag[] = []; - for (let i = 0; i < formData.tags.length; i++) { - result.push({ key: i, tag: formData.tags[i].trim().toLowerCase() }); - } - - return result; + const handleClickShowPassword = (): void => { + setShowPassword((show)=> !show); }; - const [chipTags, setChipTags] = useState(getChipTags()); + const handleChange = (e: React.ChangeEvent): void => { - const validateForm = (data: SignUpType): Record => { - const errors: Record = {}; + switch (e.target.id) { - if (data.username.length < 2) { - toast.error(t('errors.invalid_username')); - errors.username = t('errors.invalid_username'); - } - - if(!EmailRegx.test(data.email) || data.email.trim() === '') { - toast.error(t('errors.invalid_email')); - errors.email = t('errors.invalid_email'); - } + case 'userTags': + setTag(e.target.value); + break; - if (data.password.trim().length === 0) { - errors.password = t('errors.password_short'); - errors.confirmPassword = t('errors.password_short'); - toast.error(t('errors.password_short'), { position: 'top-right' }); - } else if (data.password.trim() !== confirmPassword.trim()) { - errors.password = t('errors.sign_up_password_not_same'); - errors.confirmPassword = t('errors.sign_up_password_not_same'); - toast.error(t('errors.sign_up_password_not_same'), { position: 'top-right' }); - } + case 'confirmPassword': + if (e.target.value !== getValues().password) setError('confirmPassword', + { message: t('errors.sign_up_password_not_same') }); + break; - if (data.tags.length === 0 || data.tags.length > 10) { - toast.error(t('errors.user_tags')); - errors.tag = t('errors.user_tags'); + default: + break; } - - return errors; }; - const handleDeleteTag = (chipToDelete: ChipTag) => () => { - setChipTags((chips) => - chips.filter((chip) => chip.key !== chipToDelete.key), - ); - formData.tags = formData.tags.filter((tag) => tag.trim() !== chipToDelete.tag.trim()); + const handleDeleteTag = (tag: string) => () => { + setFormData((prevFormData) => ({ + ...prevFormData, + tags: [...prevFormData.tags.filter((item) => item !== tag)], + })); }; - const handleClickAddTag = (): void => { - if (tag.trim().length === 0) { - return; - } + const addTag = (tag: string): void => { - if (formData.tags.length === 10) { - toast.warn(t('errors.user_tags')); + if (tag.length < 1) { + toast.warn(t('errors.tag_length')); return; } - if (tag.trim().length > 10) { - errors.tags = t('errors.tag_length'); - setErrors(errors); + if (formData.tags.length === 10) { + toast.warn(t('errors.user_tags')); return; } - if (formData.tags.indexOf(tag.toLowerCase().trim()) === -1) { - formData.tags.push(tag.trim().toLowerCase()); - setChipTags(getChipTags); - setTag(''); + if (!formData.tags.includes(tag)) { + setFormData((prevFormData) => ({ + ...prevFormData, + tags: [...prevFormData.tags, tag], + })); } }; - const handleAddTag = (event: React.KeyboardEvent): void => { + const handleAddByEnter = (event: React.KeyboardEvent): void => { if (event.key === 'Enter') { - handleClickAddTag(); + const tag = event.currentTarget.value; + addTag(tag.trim().toLowerCase()); event.preventDefault(); } }; - const handleMouseDownAddTag = (event: React.MouseEvent): void => { - event.preventDefault(); + const handleAddByClick = (): void => { + addTag(tag.trim().toLowerCase()); }; - const handleSubmit = async ( - event: React.FormEvent, - ): Promise => { - event.preventDefault(); - const formErrors = validateForm(formData); - setErrors(formErrors); - - if (Object.keys(formErrors).length > 0 || tag.trim().length > 0) { - return; - } - - const dataToSend = { - ...formData, - email: userData.email || formData.email, - avatarImgUrl: userData.avatarImgUrl || 'placeholder', - tags: Array.from(formData.tags), + const onSubmit: SubmitHandler = ( + data, + ): void => { + + const dataToSend: SignUpType = { + ...data, + avatarImgUrl: formData.avatarImgUrl, + tags: formData.tags, }; - await dispatch(authAction.register(dataToSend)) + dispatch(authAction.register(dataToSend)) .unwrap() .then((user) => { if (user != null) { @@ -196,48 +143,10 @@ const SignUpPage: FC = () => { } }) .catch((error) => { - setRegisterError(error.message); + toast.error(error.message); }); }; - const handleOnChange = (event: React.ChangeEvent): void => { - event.preventDefault(); - const { name, value } = event.target; - - if (name === 'email' && userData.email && userData.email !== formData.email) { - setFormData((formData) => ({ - ...formData, - email: userData.email, - })); - } else { - setFormData((formData) => ({ - ...formData, - [name]: value, - })); - } - }; - - const handleOnChangeConfirmPassword = (event: React.ChangeEvent): void => { - event.preventDefault(); - setConfirmPassword(event.target.value); - }; - - const handleFieldFocus = (field: string): void => { - setErrors((prevErrors) => ({ ...prevErrors, [field]: '' })); - }; - - const handleOnChangeTag = (event: React.ChangeEvent): void => { - event.preventDefault(); - - if (event.target.value.trim().length > 10) { - errors.tags = t('errors.tag_length'); - } else { - errors.tags = ''; - } - setTag(event.target.value); - setErrors(errors); - }; - return ( @@ -267,22 +176,20 @@ const SignUpPage: FC = () => { {t('sign_up')} - + {t('first_name')} handleFieldFocus('firstName')} + {...register('firstName')} autoFocus - error={!!errors.firstName} - helperText={errors.firstName} + error={!!formState.errors.firstName?.message} + helperText={formState.errors.firstName?.message} /> @@ -293,12 +200,10 @@ const SignUpPage: FC = () => { required fullWidth id="lastName" - name="lastName" autoComplete="family-name" - onChange={handleOnChange} - onFocus={(): void => handleFieldFocus('lastName')} - error={!!errors.lastName} - helperText={errors.lastName} + {...register('lastName')} + error={!!formState.errors.lastName?.message} + helperText={formState.errors.lastName?.message} /> @@ -309,12 +214,19 @@ const SignUpPage: FC = () => { required fullWidth id="username" - name="username" autoComplete="username" - onChange={handleOnChange} - onFocus={(): void => handleFieldFocus('username')} - error={!!errors.username} - helperText={errors.username} + {...register('username', { + minLength: { + value: 3, + message: t('errors.invalid_username'), + }, + maxLength: { + value: 16, + message: t('errors.invalid_username'), + }, + })} + error={!!formState.errors.username?.message} + helperText={formState.errors.username?.message} /> @@ -325,46 +237,89 @@ const SignUpPage: FC = () => { required fullWidth id="email" - name="email" - value={userData.email || formData.email} autoComplete="email" - onChange={handleOnChange} - onFocus={(): void => handleFieldFocus('email')} - disabled={!!userData.email} - error={!!errors.email} - helperText={errors.email} + {...register('email', { + pattern: { + value: EmailRegx, + message: t('errors.invalid_email'), + }, + })} + error={!!formState.errors.email?.message} + helperText={formState.errors.email?.message} /> - handleFieldFocus('password')} - error={!!errors.password} - /> + + + {t('password')} + ): void => { + if (!PasswordRegex.test(event.currentTarget.value)) { + setError('password', { message: t('errors.password_short') }); + } + }, + })} + error={!!formState.errors.password?.message} + required + endAdornment={ + + + {showPassword ? : } + + + } + /> + {formState.errors.password?.message && + {formState.errors.password?.message} + } + - handleFieldFocus('confirmPassword')} - error={!!errors.confirmPassword} - /> + + {t('confirm_password')} + + + {showPassword ? : } + + + } + /> + {formState.errors.confirmPassword?.message && + {formState.errors.confirmPassword?.message} + } + {t('description')} handleFieldFocus('description')} - error={!!errors.description} - helperText={errors.description} + {...register('description')} + error={!!formState.errors.description?.message} + helperText={formState.errors.description?.message} /> @@ -374,18 +329,19 @@ const SignUpPage: FC = () => { handleFieldFocus('tags')} - onKeyDown={(event): void => handleAddTag(event)} + fullWidth + onKeyDown={handleAddByEnter} + onChange={handleChange} + inputProps={ + { + maxLength: 10, + minLength: 1, + } + } endAdornment={ @@ -393,10 +349,8 @@ const SignUpPage: FC = () => { } /> - - {errors.tags || - 'Введіть від 1 до 10 тегів, розділяючи їх "ENTER"'} + + 'Введіть від 1 до 10 тегів, розділяючи їх "ENTER"' { }} component="ul" > - {chipTags.map((data) => { + {formData.tags.map((tag) => { return ( { whiteSpace: 'normal', }, }} - label={data.tag} - onDelete={handleDeleteTag(data)} + label={tag} + onDelete={handleDeleteTag(tag)} /> ); })} - {registerError && ( - {registerError} - )} } )} - {user && user.tags.map((tag, index) => ( + {currentUser.tags.map((tag, index) => ( { maxHeight: '24px', }} onMouseEnter={(): void => { - if (user && user.tags.length > 1) { + if (currentUser.tags.length > 1) { setShowButton(!showButton); }}} /> @@ -420,14 +289,13 @@ const MyProfile: FC = () => { ))} - {controlsVisible && + justifyContent={'space-between'} bottom={'-120px'} paddingLeft={'15px'}> @@ -442,7 +310,7 @@ const MyProfile: FC = () => { {t('buttons.save')} - } + diff --git a/kpoint-react/src/components/profile-page/profile-layout/profile-layout.tsx b/kpoint-react/src/components/profile-page/profile-layout/profile-layout.tsx index 575b048e..cd6a89cd 100644 --- a/kpoint-react/src/components/profile-page/profile-layout/profile-layout.tsx +++ b/kpoint-react/src/components/profile-page/profile-layout/profile-layout.tsx @@ -31,7 +31,7 @@ export const ProfileLayout:FC = ({ children })=> { window.location.href = '/'; }; - const changeHandlerAvatar = (field: string, file: string | File): void => { + const changeHandlerAvatar = (file: string | File): void => { const logo = file as File; dispatch(profileAction.updateAvatar({ logo })) .unwrap() @@ -122,7 +122,7 @@ export const ProfileLayout:FC = ({ children })=> { component="profile-page" xs={6} lg={12} - handleChange={changeHandlerAvatar} + handlers={{ changeHandlerDefault: changeHandlerAvatar }} imageUrl={avatarImgUrl}/> { const { t } = useTranslation(); - - const [passwordsValues, setPasswordsValues] = useState(DEFAULT_PASSWORDS_VALUES); - - const [errors, setErrors] = useState>({}); + const { register, formState, getValues, setError } = useForm(); const dispatch = useAppDispatch(); - const handleChangeIsValid = (): Record => { - const errors: Record = {}; - - if(!passwordsValues.oldPassword || passwordsValues.oldPassword.trim().length === 0) { - errors.oldPassword = true; - toast.error(t('errors.password_short'), { position: 'top-right' }); - } else if (!passwordsValues.newPassword || passwordsValues.newPassword.trim().length === 0) { - errors.newPassword = true; - toast.error(t('errors.password_short'), { position: 'top-right' }); - } else if(!passwordsValues.confirmPassword || passwordsValues.confirmPassword.trim().length === 0) { - errors.confirmPassword = true; - toast.error(t('errors.password_short'), { position: 'top-right' }); - } else if (passwordsValues.newPassword.trim() !== passwordsValues.confirmPassword.trim()) { - errors.newPassword = true; - errors.confirmPassword = true; - toast.error(t('errors.profile_password_not_same'), { position: 'top-right' }); - } else if (passwordsValues.newPassword.trim() === passwordsValues.oldPassword.trim()) { - errors.newPassword = true; - errors.confirmPassword = true; - toast.error(t('errors.profile_password_new_current'), { position: 'top-right' }); - } - - return errors; - }; - const changePassword = async(): Promise => { - try { - const bodyData = { - oldPassword: passwordsValues.oldPassword, - newPassword: passwordsValues.newPassword, - }; - - dispatch(profileAction.changePassword( bodyData )) - .unwrap() - .then((action): void => { - toast.success(`${action.message}`); - }) - .catch(() => { - setErrors((prevErrors) => ({ - ...prevErrors, - oldPassword: true })); - }); - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch(e: unknown) { - toast.error('Error while changing password', { - position: 'top-right', - }); - } + + const bodyData = { + oldPassword: getValues().oldPassword, + newPassword: getValues().newPassword, + }; + + dispatch(profileAction.changePassword( bodyData )) + .unwrap() + .then((action): void => { + toast.success(`${action.message}`); + }); }; const handleSubmit = async(): Promise => { - const isFormValid = handleChangeIsValid(); - - if (Object.keys(isFormValid).length === 0) { - setErrors({}); + + if (getValues().newPassword === getValues().confirmNewPassword) { await changePassword(); } else { - setErrors(isFormValid); + toast.error(t('errors.profile_password_not_same'), { position: 'top-right' }); } }; - const handleChangePasswordsValue = (e: React.ChangeEvent, id: string): void => { - setPasswordsValues((prevState) => ({ - ...prevState, - [id]: e.target.value, - })); - }; + const [showPassword, setShowPassword] = useState(false); - const handleFieldFocus = (field: string): void => { - setErrors((prevErrors) => ({ ...prevErrors, [field]: false })); + const handleClickShowPassword = (): void => { + setShowPassword((show)=> !show); }; return( - handleFieldFocus('currentPassword')} - error={errors.oldPassword} - /> - handleFieldFocus('newPassword')} - error={errors.newPassword} - /> - handleFieldFocus('confirmPassword')} - error={errors.confirmPassword} - /> + + {t('current_password')} + + + {showPassword ? : } + + + } + /> + + + {t('new_password')} + ): void => { + if (!PasswordRegex.test(event.currentTarget.value)) { + setError('newPassword', { message: t('errors.password_short') }); + } + }, + })} + error={!!formState.errors.newPassword?.message} + required + endAdornment={ + + + {showPassword ? : } + + + } + /> + {formState.errors.newPassword?.message && + {formState.errors.newPassword?.message} + } + + + {t('new_password_confirm')} + + + {showPassword ? : } + + + } + /> + ); }; diff --git a/kpoint-react/src/components/projects/project-create/components/project-create-step-1.tsx b/kpoint-react/src/components/projects/project-create/components/project-create-step-1.tsx index b77ac8dd..243b330e 100644 --- a/kpoint-react/src/components/projects/project-create/components/project-create-step-1.tsx +++ b/kpoint-react/src/components/projects/project-create/components/project-create-step-1.tsx @@ -18,7 +18,6 @@ import getSlug from 'speakingurl'; import { CitiesType, - EditProjectsPropsType, } from '../../../../common/types/types'; import { cities } from './cities'; @@ -32,8 +31,24 @@ type ChipTag = { tag: string; }; -export const ProjectCreateStep1Form: FC = ({ - projectData, +type FirstStep = { + title: string, + url: string, + tags: string[], + summary: string, +}; + +type FirstStepProps = FirstStep & { + handleChange: (fields: Partial) => void; + handleFieldFocus: (field: string) => void; + errors: Record; +}; + +export const ProjectCreateStep1Form: FC = ({ + title, + url, + tags, + summary, handleChange, handleFieldFocus, errors, @@ -43,8 +58,8 @@ export const ProjectCreateStep1Form: FC = ({ const getChipTags = (): ChipTag[] => { const result: ChipTag[] = []; - for (let i = 0; i < projectData.tags.length; i++) { - result.push({ key: i, tag: projectData.tags[i].toLowerCase() }); + for (let i = 0; i < tags.length; i++) { + result.push({ key: i, tag: tags[i].toLowerCase() }); } return result; @@ -59,7 +74,7 @@ export const ProjectCreateStep1Form: FC = ({ return; } - if (projectData.tags.length === 5) { + if (tags.length === 5) { toast.warn(t('errors.project_tags')); return; @@ -71,8 +86,8 @@ export const ProjectCreateStep1Form: FC = ({ return; } - if (projectData.tags.indexOf(tag.toLowerCase().trim()) === -1) { - projectData.tags.push(tag.trim().toLowerCase()); + if (tags.indexOf(tag.toLowerCase().trim()) === -1) { + tags.push(tag.trim().toLowerCase()); setChipTags(getChipTags); setTag(''); } @@ -93,7 +108,7 @@ export const ProjectCreateStep1Form: FC = ({ setChipTags((chips) => chips.filter((chip: ChipTag): boolean => chip.key !== chipToDelete.key), ); - projectData.tags = projectData.tags.filter( + tags = tags.filter( (tag: string): boolean => tag !== chipToDelete.tag, ); }; @@ -101,16 +116,17 @@ export const ProjectCreateStep1Form: FC = ({ return ( - + {t('project_name')} { - handleChange('title', e.target.value); + handleChange({ title: e.target.value }); let slug = getSlug(e.target.value, { maintainCase: true, }); @@ -118,7 +134,7 @@ export const ProjectCreateStep1Form: FC = ({ if (slug.length > 30) { slug = slug.slice(0, 30); } - handleChange('url', slug); + handleChange({ url: slug }); setProjectURL(slug); }} inputProps={{ maxLength: 30 }} @@ -137,12 +153,12 @@ export const ProjectCreateStep1Form: FC = ({ fullWidth sx={{ marginTop: 0 }} placeholder={t('url_placeholder')} - value={projectData.url} + value={url} onChange={(e): void => { const slug = getSlug(e.target.value, { maintainCase: true, }); - handleChange('url', slug); + handleChange({ url: slug }); setProjectURL(slug); }} inputProps={{ maxLength: 30 }} @@ -249,8 +265,8 @@ export const ProjectCreateStep1Form: FC = ({ {t('summary')} handleChange('summary', e.target.value)} + value={summary} + onChange={(e): void => handleChange({ summary: e.target.value })} onFocus={(): void => handleFieldFocus('summary')} error={!!errors.summary} helperText={errors.summary} diff --git a/kpoint-react/src/components/projects/project-create/components/project-create-step-2.tsx b/kpoint-react/src/components/projects/project-create/components/project-create-step-2.tsx index eb4c3eb0..12dede94 100644 --- a/kpoint-react/src/components/projects/project-create/components/project-create-step-2.tsx +++ b/kpoint-react/src/components/projects/project-create/components/project-create-step-2.tsx @@ -1,92 +1,31 @@ -import { TextField } from '@mui/material'; +import { FormLabel, TextField } from '@mui/material'; import Grid from '@mui/material/Grid'; -import { Editor } from 'lexical/lexical-components/lexical-editor/lexical-editor'; import React, { FC } from 'react'; import { useTranslation } from 'react-i18next'; -import { EditProjectsPropsType } from '../../../../common/types/types'; -import { descriptionPlaceholder } from './project-default'; +type SecondStep = { + description: string; +}; + +type SecondStepProps = SecondStep & { + handleChange: (fields: Partial) => void, +}; -export const ProjectCreateStep2Form: FC = ( - { handleChange }) => { +export const ProjectCreateStep2Form: FC = ( + { description, handleChange }) => { const { t } = useTranslation(); return ( - - - - handleChange('title', e.target.value)} - // onFocus={(): void => handleFieldFocus('title')} - // error={!!errors.title} - // helperText={errors.title} - // - // type={'text'} - // required - // id="description" - // name="description" - // helperText={'Ідея. Проблема, яку вирішує проєкт'} - // value={project.description} - // autoComplete="given-name" - variant="outlined" - // onChange={ (event: React.ChangeEvent): void => { - // event.preventDefault(); - // project.description = event.target.value; - // setProject(project); - // }} - /> - - - handleChange('title', e.target.value)} - // onFocus={(): void => handleFieldFocus('title')} - // error={!!errors.title} - // helperText={errors.title} - // - // type={'text'} - // required - // id="description" - // name="description" - // label="Опис проєкта" - // helperText={'Ідея. Проблема, яку вирішує проєкт'} - // value={project.description} - // autoComplete="given-name" - variant="outlined" - // onChange={ (event: React.ChangeEvent): void => { - // event.preventDefault(); - // project.description = event.target.value; - // setProject(project); - // }} - /> - - - ): void => { - // event.preventDefault(); - // project.description = event.target.value; - // setProject(project); - // }} - /> + {t('about_project')} + ): void => handleChange({ description: e.target.value })} + placeholder="Почніть писати опис проєкту. (Підтримується markdown)"/> ); diff --git a/kpoint-react/src/components/projects/project-create/components/project-create-step-3.tsx b/kpoint-react/src/components/projects/project-create/components/project-create-step-3.tsx index 755f74a5..8db3fab5 100644 --- a/kpoint-react/src/components/projects/project-create/components/project-create-step-3.tsx +++ b/kpoint-react/src/components/projects/project-create/components/project-create-step-3.tsx @@ -3,10 +3,20 @@ import Grid from '@mui/material/Grid'; import React, { FC } from 'react'; import { useTranslation } from 'react-i18next'; -import { EditProjectsPropsType } from '../../../../common/types/types'; +type ThirdStep = { + collectDeadline: string, + goalDeadline: string, + startSum: number, +}; + +type ThirdStepProps = ThirdStep & { + handleChange: (fields: Partial) => void; + handleFieldFocus: (field: string) => void; + errors: Record; +}; -export const ProjectCreateStep3Form: FC = ( - { projectData, handleChange, handleFieldFocus, errors }) => { +export const ProjectCreateStep3Form: FC = ( + { collectDeadline, handleChange, handleFieldFocus, errors }) => { const { t } = useTranslation(); @@ -18,15 +28,13 @@ export const ProjectCreateStep3Form: FC = ( {t('collect_deadline')} handleChange('collectDeadline', e.target.value)} + value={collectDeadline} + onChange={(e): void => handleChange({ collectDeadline: e.target.value })} onFocus={(): void => handleFieldFocus('collectDeadline')} error={!!errors.deadline} helperText={errors.deadline} type={'date'} required - // autoComplete="given-name" variant="outlined" /> @@ -34,15 +42,12 @@ export const ProjectCreateStep3Form: FC = ( {t('goal_deadline')} handleChange('goalDeadline', e.target.value)} + onChange={(e): void => handleChange({ goalDeadline: e.target.value })} onFocus={(): void => handleFieldFocus('goalDeadline')} error={!!errors.deadline} helperText={errors.deadline} type={'date'} required - // autoComplete="given-name" variant="outlined" /> @@ -52,12 +57,12 @@ export const ProjectCreateStep3Form: FC = ( {t('start_sum')} handleChange('startSum', e.target.value)} + onChange={(e): void => handleChange({ startSum: Number(e.target.value) })} onFocus={(): void => handleFieldFocus('startSum')} error={!!errors.startSum} helperText={errors.startSum} type={'number'} + required autoComplete="start_sum" variant="outlined" /> diff --git a/kpoint-react/src/components/projects/project-create/components/project-default.ts b/kpoint-react/src/components/projects/project-create/components/project-default.ts index 5e6405fa..0bcbabad 100644 --- a/kpoint-react/src/components/projects/project-create/components/project-default.ts +++ b/kpoint-react/src/components/projects/project-create/components/project-default.ts @@ -2,9 +2,6 @@ import { ProjectsEditType } from '../../../../common/types/projects/projects-edi const currentDate = new Date().toISOString().substring(0, 10); -const descriptionPlaceholder = (): string => { - return '

Почніть писати опис проєкту

'; -}; const projectDefault: ProjectsEditType = { title: '', url: '', @@ -19,13 +16,8 @@ const projectDefault: ProjectsEditType = { startSum: 0, collectDeadline: currentDate, goalSum: 0, - goalDeadline: currentDate, - networksLinks: - { - FACEBOOK: null, - INSTAGRAM: null, - YOUTUBE: null, - }, + goalDeadline: '', + networksLinks:{}, }; -export { descriptionPlaceholder, projectDefault }; \ No newline at end of file +export { projectDefault }; \ No newline at end of file diff --git a/kpoint-react/src/components/projects/project-create/project-create.tsx b/kpoint-react/src/components/projects/project-create/project-create.tsx index 269b404f..a1997166 100644 --- a/kpoint-react/src/components/projects/project-create/project-create.tsx +++ b/kpoint-react/src/components/projects/project-create/project-create.tsx @@ -1,5 +1,7 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import { Box, Button, Container, Paper, Step, StepLabel, Stepper, Typography } from '@mui/material'; -import { TestRequest } from 'common/types/projects/testRequest'; +import { PostProject } from 'common/types/projects/testRequest'; +import { useMultistepForm } from 'components/common/common'; import React, { FC, ReactElement, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; @@ -13,21 +15,35 @@ import { ProjectCreateStep2Form } from './components/project-create-step-2'; import { ProjectCreateStep3Form } from './components/project-create-step-3'; import { projectDefault } from './components/project-default'; -export const ProjectCreate: FC = () => { +const ProjectCreate: FC = () => { const { t } = useTranslation(); - const steps: string[] = [ - t('general_information'), - t('about'), - t('implementation_plan'), - ]; + const [projectData, setProjectData] = useState(projectDefault); + + const handleChange = (fields: Partial): void => { + setProjectData((prevData) => ({ ...prevData, ...fields })); + }; const [errors, setErrors] = useState>({}); - const [activeStep, setActiveStep] = useState(1); + const handleFieldFocus = (field: string): void => { + setErrors((prevErrors) => ({ ...prevErrors, [field]: '' })); + }; + + const { steps, currentStepIndex, step, isFirstStep, isLastStep, back, next } = + useMultistepForm([ + , + , + , + ]); - const [projectData, setProjectData] = - useState(projectDefault); + const stepTitles: string[] = [ + t('general_information'), + t('about_project'), + t('implementation_plan'), + ]; const dispatch = useAppDispatch(); @@ -36,61 +52,11 @@ export const ProjectCreate: FC = () => { useEffect(() => { document.body.style.backgroundColor = '#E4E5E9'; }, []); - const handleNext = (): void => { - const validationErrors = validateForm(projectData); - - if (Object.keys(validationErrors).length === 0) { - setErrors({}); - setActiveStep((prevActiveStep) => prevActiveStep + 1); - } else { - setErrors(validationErrors); - } - - const testData: TestRequest = { - file: projectData.logo ? projectData.logo : '', - createdProject: - { - title: projectData.title, - url: projectData.url, - summary: projectData.summary, - description: projectData.description, - tags: projectData.tags, - goalDeadline: projectData.goalDeadline, - collectDeadline: projectData.collectDeadline, - startSum: projectData.startSum, - networksLinks: { FACEBOOK: 'https://www.facebook.com/example' }, - }, - }; - - if (activeStep === steps.length) { - dispatch(projectAction.createNew( { testData } )) - .unwrap() - - .then((action): void => { - navigate('/projects/' + action.url); - }) - .catch(() => { - return; - }); - } - }; - - const handleBack = (): void => { - setActiveStep((prevActiveStep) => prevActiveStep - 1); - }; - - const handleChange = (field: string, value: string | File): void => { - setProjectData((prevData) => ({ ...prevData, [field]: value })); - }; - - const handleFieldFocus = (field: string): void => { - setErrors((prevErrors) => ({ ...prevErrors, [field]: '' })); - }; const validateForm = (data: ProjectsEditType): Record => { const errors: Record = {}; - switch (activeStep) { + switch (currentStepIndex) { case 1: { if (!data.title.trim() || data.title.trim().length > 30) { errors.title = t('errors.project_title'); @@ -126,44 +92,82 @@ export const ProjectCreate: FC = () => { return errors; }; - const getStepContent = (step: number): ReactElement => { - switch (step) { - case 1: - return ( - - ); - case 2: - return ( - - ); - case 3: - return ( - - ); - default: - throw new Error('Unknown step'); + // switch (step) { + // case 1: + // return ( + // + // ); + // case 2: + // return ( + // + // ); + // case 3: + // return ( + // + // ); + // default: + // throw new Error('Unknown step'); + // } + // }; + + const onSubmit = (e: React.FormEvent): void => { + e.preventDefault(); + + const formErrors = validateForm(projectData); + + if (Object.keys(formErrors).length === 0) { + setErrors({}); + } else { + setErrors(formErrors); } + + const bodyData: PostProject = { + file: projectData.logo ? projectData.logo : '', + createdProject: + { + title: projectData.title, + url: projectData.url, + summary: projectData.summary, + description: projectData.description, + tags: projectData.tags, + goalDeadline: projectData.goalDeadline, + collectDeadline: projectData.collectDeadline, + startSum: projectData.startSum, + networksLinks: projectData.networksLinks, + }, + }; + + dispatch(projectAction.createNew( { bodyData } )) + .unwrap() + .then((action): void => { + navigate('/projects/' + action.url); + }) + .catch(() => { + return; + }); + }; return ( - + {t('new_project')} @@ -171,31 +175,33 @@ export const ProjectCreate: FC = () => { variant="outlined" sx={{ my: { xs: 3, md: 1 }, p: { xs: 2, md: 3 } }} > - - {steps.map((label) => ( + + {stepTitles.map((label) => ( {label} ))} - - {activeStep > steps.length ? <>{setActiveStep(1)} : ( - - {getStepContent(activeStep)} - - {activeStep !== 1 && ( - - )} - - + { t('buttons.save') } + ) + : ()} - )} + - + ); }; + +export { ProjectCreate }; \ No newline at end of file diff --git a/kpoint-react/src/i18n/en-translation.js b/kpoint-react/src/i18n/en-translation.js index 20f0fbb8..366d8447 100644 --- a/kpoint-react/src/i18n/en-translation.js +++ b/kpoint-react/src/i18n/en-translation.js @@ -122,14 +122,15 @@ const enTranslation = { 'The starting amount cannot be negative', suggestion_size: 'The field must contain from 1 to 200 characters', profile_password_not_same: 'New and repeat passwords are not the same', - password_short: 'The entered password is empty', + password_short: `Your password must be at least 8 characters long, contain at least one + number and have a mixture of uppercase and lowercase letters and at least one special symbol.`, profile_password_new_current: 'The new profile password must be different from the current one', - can_not_login: 'Can`t login', + can_not_login: 'Invalid email or password', profile_can_not_update: 'Can`t update profile', sign_up_password_not_same: 'Passwords are not the same', invalid_email: 'Invalid email', - invalid_username: 'Invalid username. The field must contain at least 1 character.', + invalid_username: 'Invalid username. The field must contain from 3 to 16 characters.', invalid_firstname: 'Invalid firstname', invalid_lastname: 'Invalid lastname', invalid_tags: 'Tags should be unique', diff --git a/kpoint-react/src/i18n/uk-translation.js b/kpoint-react/src/i18n/uk-translation.js index 35396a9b..6d2a0d39 100644 --- a/kpoint-react/src/i18n/uk-translation.js +++ b/kpoint-react/src/i18n/uk-translation.js @@ -124,12 +124,13 @@ const ukTranslation = { profile_password_not_same: 'Введені нові паролі не збігаються', profile_password_new_current: 'Новий пароль профілю має відрізнятися від поточного', - can_not_login: 'Не можу увійти', + can_not_login: 'Неправильний логін або пароль', profile_can_not_update: 'Не вдається оновити профіль', sign_up_password_not_same: 'Введені паролі не збігаються', - password_short: 'Введений пароль пустий', + password_short: `Ваш пароль має бути принаймні з 8 символів, містити принаймні одину + цифру, одну велику і малу літеру і хоча б один спеціальний символ.`, invalid_email: 'Невірна електронна пошта', - invalid_username: 'Невірне імʼя користувача. Поле повинне містити від 1 символа', + invalid_username: 'Невірне імʼя користувача. Поле повинне містити від 3 до 16 символів.', invalid_firstname: 'Невірне імʼя', invalid_lastname: 'Невірне прізвище', invalid_tags: 'Tеги мають бути унікальні', diff --git a/kpoint-react/src/index.css b/kpoint-react/src/index.css index a63eb725..eaafda74 100755 --- a/kpoint-react/src/index.css +++ b/kpoint-react/src/index.css @@ -22,4 +22,9 @@ code { monospace; } -/*# sourceMappingURL=index.css.map */ +.description { + overflow-y: auto; + scrollbar-width: thin; +} + + diff --git a/kpoint-react/src/lexical/config/lexical-editor-config.ts b/kpoint-react/src/lexical/config/lexical-editor-config.ts deleted file mode 100644 index 40652fb7..00000000 --- a/kpoint-react/src/lexical/config/lexical-editor-config.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { CodeHighlightNode, CodeNode } from '@lexical/code'; -import { AutoLinkNode, LinkNode } from '@lexical/link'; -import { ListItemNode,ListNode } from '@lexical/list'; -import { HeadingNode, QuoteNode } from '@lexical/rich-text'; -import { TableCellNode, TableNode, TableRowNode } from '@lexical/table'; -import { toast } from 'react-toastify'; - -import { lexicalEditorTheme } from '../theme/lexical-editor-theme'; - -// Catch any errors that occur during Lexical updates and log them -// or throw them as needed. If you don't throw them, Lexical will -// try to recover gracefully without losing user data. -const onError = (error: Error): void => { - toast.error(error.message); -}; - -export const lexicalEditorConfig = { - namespace: 'MyEditor', - theme: lexicalEditorTheme, - onError, - nodes: [ - HeadingNode, - ListNode, - ListItemNode, - QuoteNode, - CodeNode, - CodeHighlightNode, - TableNode, - TableCellNode, - TableRowNode, - AutoLinkNode, - LinkNode, - ], -}; \ No newline at end of file diff --git a/kpoint-react/src/lexical/images/emoji/1F600.png b/kpoint-react/src/lexical/images/emoji/1F600.png deleted file mode 100644 index ba0e4feb..00000000 Binary files a/kpoint-react/src/lexical/images/emoji/1F600.png and /dev/null differ diff --git a/kpoint-react/src/lexical/images/emoji/1F641.png b/kpoint-react/src/lexical/images/emoji/1F641.png deleted file mode 100644 index 0dd4e5be..00000000 Binary files a/kpoint-react/src/lexical/images/emoji/1F641.png and /dev/null differ diff --git a/kpoint-react/src/lexical/images/emoji/1F642.png b/kpoint-react/src/lexical/images/emoji/1F642.png deleted file mode 100644 index b37115fd..00000000 Binary files a/kpoint-react/src/lexical/images/emoji/1F642.png and /dev/null differ diff --git a/kpoint-react/src/lexical/images/emoji/2764.png b/kpoint-react/src/lexical/images/emoji/2764.png deleted file mode 100644 index 6dd2cd56..00000000 Binary files a/kpoint-react/src/lexical/images/emoji/2764.png and /dev/null differ diff --git a/kpoint-react/src/lexical/images/emoji/LICENSE.md b/kpoint-react/src/lexical/images/emoji/LICENSE.md deleted file mode 100644 index 87b04e9a..00000000 --- a/kpoint-react/src/lexical/images/emoji/LICENSE.md +++ /dev/null @@ -1,5 +0,0 @@ -OpenMoji -https://openmoji.org - -Licensed under Attribution-ShareAlike 4.0 International -https://creativecommons.org/licenses/by-sa/4.0/ diff --git a/kpoint-react/src/lexical/lexical-components/auto-link-plugin/auto-link-plugin.tsx b/kpoint-react/src/lexical/lexical-components/auto-link-plugin/auto-link-plugin.tsx deleted file mode 100644 index 1c645492..00000000 --- a/kpoint-react/src/lexical/lexical-components/auto-link-plugin/auto-link-plugin.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - AutoLinkPlugin, - createLinkMatcherWithRegExp, -} from '@lexical/react/LexicalAutoLinkPlugin'; -import { FC } from 'react'; - -const URL_REGEX = - // eslint-disable-next-line max-len - /(https?:\/\/)?((\w+:\w+@)?(([a-zA-Z\d]([a-zA-Z\d-]*[a-zA-Z\d])*)\.)+[a-zA-Z]{2,}|localhost|(\d{1,3}\.){3}\d{1,3})(:\d+)?(\/[-a-zA-Z\d%_.~+]*)*(\?[;&a-zA-Z\d%_.~+=-]*)?(#[-a-zA-Z\d_]*)?/; -const EMAIL_REGEX = - // eslint-disable-next-line max-len - /(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/; - -const MATCHERS = [ - createLinkMatcherWithRegExp(URL_REGEX, (text) => { - return text.startsWith('http') ? text : `https://${text}`; - }), - createLinkMatcherWithRegExp(EMAIL_REGEX, (text) => { - return `mailto:${text}`; - }), -]; - -const LexicalAutoLinkPlugin: FC = () => { - return ; -}; - -export { LexicalAutoLinkPlugin }; \ No newline at end of file diff --git a/kpoint-react/src/lexical/lexical-components/dropdown/dropdown.tsx b/kpoint-react/src/lexical/lexical-components/dropdown/dropdown.tsx deleted file mode 100644 index 18b028d8..00000000 --- a/kpoint-react/src/lexical/lexical-components/dropdown/dropdown.tsx +++ /dev/null @@ -1,245 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - -import { ExpandMoreOutlined } from '@mui/icons-material'; -import { - FC, - ReactNode, - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from 'react'; -import * as React from 'react'; -import { createPortal } from 'react-dom'; - - type DropDownContextType = { - registerItem: (ref: React.RefObject) => void; - }; - -const DropDownContext = React.createContext(null); - -interface DropDownItemProps { - children: React.ReactNode; - className: string; - onClick: (event: React.MouseEvent) => void; - title?: string; -} - -interface DropDownItemsProps { - children: React.ReactNode; - dropDownRef: React.Ref; - onClose: () => void; -} - -interface DropDownProps { - disabled?: boolean; - buttonAriaLabel?: string; - buttonClassName: string; - buttonIconClassName?: string; - buttonLabel?: string; - children: ReactNode; - stopCloseOnClickSelf?: boolean; -} - -const DropDownItem: FC = ({ - children, - className, - onClick, - title, -}) => { - const ref = useRef(null); - - const dropDownContext = React.useContext(DropDownContext); - - if (dropDownContext === null) { - throw new Error('DropDownItem must be used within a DropDown'); - } - - const { registerItem } = dropDownContext; - - useEffect(() => { - if (ref && ref.current) { - registerItem(ref); - } - }, [ref, registerItem]); - - return ( - - ); -}; - -const DropDownItems: FC = ({ - children, - dropDownRef, - onClose, -}) => { - const [items, setItems] = useState[]>(); - const [highlightedItem, setHighlightedItem] = - useState>(); - - const registerItem = useCallback( - (itemRef: React.RefObject) => { - setItems((prev) => (prev ? [...prev, itemRef] : [itemRef])); - }, - [setItems], - ); - - const handleKeyDown = (event: React.KeyboardEvent): - React.RefObject[] | undefined => { - if (!items) return; - - const key = event.key; - - if (['Escape', 'ArrowUp', 'ArrowDown', 'Tab'].includes(key)) { - event.preventDefault(); - } - - if (key === 'Escape' || key === 'Tab') { - onClose(); - } else if (key === 'ArrowUp') { - setHighlightedItem((prev) => { - if (!prev) return items[0]; - const index = items.indexOf(prev) - 1; - - return items[index === -1 ? items.length - 1 : index]; - }); - } else if (key === 'ArrowDown') { - setHighlightedItem((prev) => { - if (!prev) return items[0]; - - return items[items.indexOf(prev) + 1]; - }); - } - }; - - const contextValue = useMemo( - () => ({ - registerItem, - }), - [registerItem], - ); - - useEffect(() => { - if (items && !highlightedItem) { - setHighlightedItem(items[0]); - } - - if (highlightedItem && highlightedItem.current) { - highlightedItem.current.focus(); - } - }, [items, highlightedItem]); - - return ( - -
- {children} -
-
- ); -}; - -const DropDown: FC = ({ - disabled = false, - buttonLabel, - buttonAriaLabel, - buttonClassName, - buttonIconClassName, - children, - stopCloseOnClickSelf, -}) => { - const dropDownRef = useRef(null); - const buttonRef = useRef(null); - const [showDropDown, setShowDropDown] = useState(false); - - const handleClose = (): void => { - setShowDropDown(false); - - if (buttonRef && buttonRef.current) { - buttonRef.current.focus(); - } - }; - - useEffect(() => { - const button = buttonRef.current; - const dropDown = dropDownRef.current; - - if (showDropDown && button !== null && dropDown !== null) { - const { top, left } = button.getBoundingClientRect(); - dropDown.style.top = `${top + 40}px`; - dropDown.style.left = `${Math.min( - left, - window.innerWidth - dropDown.offsetWidth - 20, - )}px`; - } - }, [dropDownRef, buttonRef, showDropDown]); - - useEffect(() => { - const button = buttonRef.current; - - if (button !== null && showDropDown) { - const handle = (event: MouseEvent): void => { - const target = event.target; - - if (stopCloseOnClickSelf) { - if ( - dropDownRef.current && - dropDownRef.current.contains(target as Node) - ) - return; - } - - if (!button.contains(target as Node)) { - setShowDropDown(false); - } - }; - document.addEventListener('click', handle); - - return () => { - document.removeEventListener('click', handle); - }; - } - }, [dropDownRef, buttonRef, showDropDown, stopCloseOnClickSelf]); - - return ( - <> - - - {showDropDown && - createPortal( - - {children} - , - document.body, - )} - - ); -}; - -export { DropDown, DropDownItem }; \ No newline at end of file diff --git a/kpoint-react/src/lexical/lexical-components/index.css b/kpoint-react/src/lexical/lexical-components/index.css deleted file mode 100644 index 1c59be19..00000000 --- a/kpoint-react/src/lexical/lexical-components/index.css +++ /dev/null @@ -1,41 +0,0 @@ -.link-editor { - display: flex; - position: absolute; - top: 0; - left: 0; - z-index: 10; - max-width: 400px; - width: 100%; - opacity: 0; - background-color: #fff; - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3); - border-radius: 0 0 8px 8px; - transition: opacity 0.5s; - will-change: transform; - } - - .link-editor .button { - width: 20px; - height: 20px; - display: inline-block; - padding: 6px; - border-radius: 8px; - cursor: pointer; - margin: 0 2px; - } - - .link-editor .button.hovered { - width: 20px; - height: 20px; - display: inline-block; - background-color: #eee; - } - - .link-editor .button i, - .actions i { - background-size: contain; - display: inline-block; - height: 20px; - width: 20px; - vertical-align: -0.25em; - } \ No newline at end of file diff --git a/kpoint-react/src/lexical/lexical-components/lexical-default-value-plugin/lexical-default-value-plugin.tsx b/kpoint-react/src/lexical/lexical-components/lexical-default-value-plugin/lexical-default-value-plugin.tsx deleted file mode 100644 index 410ad95d..00000000 --- a/kpoint-react/src/lexical/lexical-components/lexical-default-value-plugin/lexical-default-value-plugin.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { $generateNodesFromDOM } from '@lexical/html'; -import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; -import { $getRoot, LexicalEditor } from 'lexical'; -import { FC, useEffect } from 'react'; - -const LexicalDefaultValuePlugin: FC<{ value: string | null }> = ({ value }) => { - const [editor] = useLexicalComposerContext(); - - const updateHTML = (editor: LexicalEditor, value: string, clear: boolean): void => { - const root = $getRoot(); - const parser = new DOMParser(); - const dom = parser.parseFromString(value, 'text/html'); - const nodes = $generateNodesFromDOM(editor, dom); - - if (clear) { - root.clear(); - } - root.append(...nodes); - }; - - useEffect(() => { - if (editor && value) { - editor.update(() => { - updateHTML(editor, value, true); - }); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [value]); - - return null; -}; - -export { LexicalDefaultValuePlugin }; \ No newline at end of file diff --git a/kpoint-react/src/lexical/lexical-components/lexical-editor/editorStyle.ts b/kpoint-react/src/lexical/lexical-components/lexical-editor/editorStyle.ts deleted file mode 100644 index feee802c..00000000 --- a/kpoint-react/src/lexical/lexical-components/lexical-editor/editorStyle.ts +++ /dev/null @@ -1,15 +0,0 @@ -import styled from '@emotion/styled'; -import { ContentEditable } from '@lexical/react/LexicalContentEditable'; - -const MuiContentEditable = styled(ContentEditable)({ - minHeight: '150px', - resize: 'none', - fontSize: '15px', - caretColor: 'rgb(5, 5, 5)', - position: 'relative', - tabSize: 1, - outline: 0, - padding: '15px 10px', -}); - -export { MuiContentEditable }; \ No newline at end of file diff --git a/kpoint-react/src/lexical/lexical-components/lexical-editor/lexical-editor.tsx b/kpoint-react/src/lexical/lexical-components/lexical-editor/lexical-editor.tsx deleted file mode 100644 index e7584456..00000000 --- a/kpoint-react/src/lexical/lexical-components/lexical-editor/lexical-editor.tsx +++ /dev/null @@ -1,117 +0,0 @@ - -import { $generateHtmlFromNodes } from '@lexical/html'; -import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin'; -import { LexicalComposer } from '@lexical/react/LexicalComposer'; -import { EditorRefPlugin } from '@lexical/react/LexicalEditorRefPlugin'; -import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary'; -import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin'; -import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin'; -import { ListPlugin } from '@lexical/react/LexicalListPlugin'; -import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'; -import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'; -import { Box } from '@mui/material'; -import { EditorState, LexicalEditor } from 'lexical'; -import { lexicalEditorConfig } from 'lexical/config/lexical-editor-config'; -import { FC, useRef, useState } from 'react'; - -import { LexicalAutoLinkPlugin } from '../auto-link-plugin/auto-link-plugin'; -import { LexicalDefaultValuePlugin } from '../lexical-default-value-plugin/lexical-default-value-plugin'; -import { FloatingLinkEditorPlugin } from '../lexical-floating-text-format-plugin/lexical-floating-text-format-plugin'; -import { ToolbarPlugin } from '../lexical-toolbar-plugin/lexical-toolbar-plugin'; -import { MuiContentEditable } from './editorStyle'; - -const Placeholder: FC = () => { - return - Почніть писати опис проєкту - ; -}; - -interface EditorProps { - onChange?: (htmlString: string) => void, - onCreate?: (field: string, value: string | File) => void, - description: string; -} - -const Editor:FC = ({ onChange, onCreate, description }) => { - const editor = useRef(null); - const [floatingAnchorElem, setFloatingAnchorElem] = - useState(null); - const [isLinkEditMode, setIsLinkEditMode] = useState(false); - - const onRef = (_floatingAnchorElem: HTMLDivElement): void => { - if (_floatingAnchorElem !== null) { - setFloatingAnchorElem(_floatingAnchorElem); - } - }; - - const transformNodesToHTMLString = (editorState: EditorState): void => { - editorState.read(() => { - - if (onChange) onChange(($generateHtmlFromNodes(editor.current as LexicalEditor, null))); - else if (onCreate) onCreate('description', ($generateHtmlFromNodes(editor.current as LexicalEditor, null))); - }); - }; - - return ( - - - - - -
- -
-
- } - placeholder={} - ErrorBoundary={LexicalErrorBoundary} - /> - - - - - - - {floatingAnchorElem && ( - - )} - - - - - - ); -}; - -export { Editor }; \ No newline at end of file diff --git a/kpoint-react/src/lexical/lexical-components/lexical-floating-text-format-plugin/lexical-floating-text-format-plugin.tsx b/kpoint-react/src/lexical/lexical-components/lexical-floating-text-format-plugin/lexical-floating-text-format-plugin.tsx deleted file mode 100644 index 398a0c18..00000000 --- a/kpoint-react/src/lexical/lexical-components/lexical-floating-text-format-plugin/lexical-floating-text-format-plugin.tsx +++ /dev/null @@ -1,366 +0,0 @@ -import '../index.css'; - -import { - $isAutoLinkNode, - $isLinkNode, - TOGGLE_LINK_COMMAND, -} from '@lexical/link'; -import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; -import { $findMatchingParent, mergeRegister } from '@lexical/utils'; -import { CancelRounded, CheckCircleRounded, DeleteRounded, EditRounded } from '@mui/icons-material'; -import { - $getSelection, - $isRangeSelection, - BaseSelection, - CLICK_COMMAND, - COMMAND_PRIORITY_CRITICAL, - COMMAND_PRIORITY_HIGH, - COMMAND_PRIORITY_LOW, - KEY_ESCAPE_COMMAND, - LexicalEditor, - NodeSelection, - RangeSelection, - SELECTION_CHANGE_COMMAND, -} from 'lexical'; -import { Dispatch, useCallback, useEffect, useRef, useState } from 'react'; -import * as React from 'react'; -import { createPortal } from 'react-dom'; - -import { getSelectedNode } from '../../utils/get-select-node'; -import { setFloatingElemPositionForLinkEditor } from '../../utils/set-floating-elem-position-for-link-editor'; -import { sanitizeUrl } from '../../utils/url'; - -function FloatingLinkEditor({ - editor, - isLink, - setIsLink, - anchorElem, - isLinkEditMode, - setIsLinkEditMode, -}: { - editor: LexicalEditor; - isLink: boolean; - setIsLink: Dispatch; - anchorElem: HTMLElement; - isLinkEditMode: boolean; - setIsLinkEditMode: Dispatch; -}): JSX.Element { - const editorRef = useRef(null); - const inputRef = useRef(null); - const [linkUrl, setLinkUrl] = useState(''); - const [editedLinkUrl, setEditedLinkUrl] = useState('https://'); - const [lastSelection, setLastSelection] = useState< - RangeSelection | NodeSelection | BaseSelection| null - >(null); - - const updateLinkEditor = useCallback(() => { - const selection = $getSelection(); - - if ($isRangeSelection(selection)) { - const node = getSelectedNode(selection); - const linkParent = $findMatchingParent(node, $isLinkNode); - - if (linkParent) { - setLinkUrl(linkParent.getURL()); - } else if ($isLinkNode(node)) { - setLinkUrl(node.getURL()); - } else { - setLinkUrl(''); - } - } - const editorElem = editorRef.current; - const nativeSelection = window.getSelection(); - const activeElement = document.activeElement; - - if (editorElem === null) { - return; - } - - const rootElement = editor.getRootElement(); - - if ( - selection !== null && - nativeSelection !== null && - rootElement !== null && - rootElement.contains(nativeSelection.anchorNode) && - editor.isEditable() - ) { - const domRect: DOMRect | undefined = - nativeSelection.focusNode?.parentElement?.getBoundingClientRect(); - - if (domRect) { - domRect.y += 40; - setFloatingElemPositionForLinkEditor(domRect, editorElem, anchorElem); - } - setLastSelection(selection); - } else if (!activeElement || activeElement.className !== 'link-input') { - if (rootElement !== null) { - setFloatingElemPositionForLinkEditor(null, editorElem, anchorElem); - } - setLastSelection(null); - setIsLinkEditMode(false); - setLinkUrl(''); - } - - return true; - }, [anchorElem, editor, setIsLinkEditMode]); - - useEffect(() => { - const scrollerElem = anchorElem.parentElement; - - const update = (): void => { - editor.getEditorState().read(() => { - updateLinkEditor(); - }); - }; - - window.addEventListener('resize', update); - - if (scrollerElem) { - scrollerElem.addEventListener('scroll', update); - } - - return () => { - window.removeEventListener('resize', update); - - if (scrollerElem) { - scrollerElem.removeEventListener('scroll', update); - } - }; - }, [anchorElem.parentElement, editor, updateLinkEditor]); - - useEffect(() => { - return mergeRegister( - editor.registerUpdateListener(({ editorState }) => { - editorState.read(() => { - updateLinkEditor(); - }); - }), - - editor.registerCommand( - SELECTION_CHANGE_COMMAND, - () => { - updateLinkEditor(); - - return true; - }, - COMMAND_PRIORITY_LOW, - ), - editor.registerCommand( - KEY_ESCAPE_COMMAND, - () => { - if (isLink) { - setIsLink(false); - - return true; - } - - return false; - }, - COMMAND_PRIORITY_HIGH, - ), - ); - }, [editor, updateLinkEditor, setIsLink, isLink]); - - useEffect(() => { - editor.getEditorState().read(() => { - updateLinkEditor(); - }); - }, [editor, updateLinkEditor]); - - useEffect(() => { - if (isLinkEditMode && inputRef.current) { - inputRef.current.focus(); - } - }, [isLinkEditMode, isLink]); - - const monitorInputInteraction = ( - event: React.KeyboardEvent, - ): void => { - if (event.key === 'Enter') { - event.preventDefault(); - handleLinkSubmission(); - } else if (event.key === 'Escape') { - event.preventDefault(); - setIsLinkEditMode(false); - } - }; - - const handleLinkSubmission = (): void => { - if (lastSelection !== null) { - if (linkUrl !== '') { - editor.dispatchCommand(TOGGLE_LINK_COMMAND, sanitizeUrl(editedLinkUrl)); - } - setEditedLinkUrl('https://'); - setIsLinkEditMode(false); - } - }; - - return ( -
- {!isLink ? null : isLinkEditMode ? ( - <> - { - setEditedLinkUrl(event.target.value); - }} - onKeyDown={(event): void => { - monitorInputInteraction(event); - }} - /> -
-
event.preventDefault()} - onClick={(): void => { - setIsLinkEditMode(false); - }} - >
- -
event.preventDefault()} - onClick={handleLinkSubmission} - >
-
- - ) : ( -
- - {linkUrl} - -
event.preventDefault()} - onClick={(): void => { - setEditedLinkUrl(linkUrl); - setIsLinkEditMode(true); - }} - >
-
event.preventDefault()} - onClick={(): void => { - editor.dispatchCommand(TOGGLE_LINK_COMMAND, null); - }} - >
-
- )} -
- ); -} - -function useFloatingLinkEditorToolbar( - editor: LexicalEditor, - anchorElem: HTMLElement, - isLinkEditMode: boolean, - setIsLinkEditMode: Dispatch, -): JSX.Element | null { - const [activeEditor, setActiveEditor] = useState(editor); - const [isLink, setIsLink] = useState(false); - - useEffect(() => { - function updateToolbar(): void { - const selection = $getSelection(); - - if ($isRangeSelection(selection)) { - const node = getSelectedNode(selection); - const linkParent = $findMatchingParent(node, $isLinkNode); - const autoLinkParent = $findMatchingParent(node, $isAutoLinkNode); - - // We don't want this menu to open for auto links. - if (linkParent !== null && autoLinkParent === null) { - setIsLink(true); - } else { - setIsLink(false); - } - } - } - - return mergeRegister( - editor.registerUpdateListener(({ editorState }) => { - editorState.read(() => { - updateToolbar(); - }); - }), - editor.registerCommand( - SELECTION_CHANGE_COMMAND, - (_payload, newEditor) => { - updateToolbar(); - setActiveEditor(newEditor); - - return false; - }, - COMMAND_PRIORITY_CRITICAL, - ), - editor.registerCommand( - CLICK_COMMAND, - (payload) => { - const selection = $getSelection(); - - if ($isRangeSelection(selection)) { - const node = getSelectedNode(selection); - const linkNode = $findMatchingParent(node, $isLinkNode); - - if ($isLinkNode(linkNode) && (payload.metaKey || payload.ctrlKey)) { - window.open(linkNode.getURL(), '_blank'); - - return true; - } - } - - return false; - }, - COMMAND_PRIORITY_LOW, - ), - ); - }, [editor]); - - return createPortal( - , - anchorElem, - ); -} - -function FloatingLinkEditorPlugin({ - anchorElem = document.body, - isLinkEditMode, - setIsLinkEditMode, -}: { - anchorElem?: HTMLElement; - isLinkEditMode: boolean; - setIsLinkEditMode: Dispatch; -}): JSX.Element | null { - const [editor] = useLexicalComposerContext(); - - return useFloatingLinkEditorToolbar( - editor, - anchorElem, - isLinkEditMode, - setIsLinkEditMode, - ); -} - -export { FloatingLinkEditorPlugin }; \ No newline at end of file diff --git a/kpoint-react/src/lexical/lexical-components/lexical-toolbar-plugin/lexical-toolbar-plugin.tsx b/kpoint-react/src/lexical/lexical-components/lexical-toolbar-plugin/lexical-toolbar-plugin.tsx deleted file mode 100644 index 0a282e8c..00000000 --- a/kpoint-react/src/lexical/lexical-components/lexical-toolbar-plugin/lexical-toolbar-plugin.tsx +++ /dev/null @@ -1,688 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { - $createCodeNode, - $isCodeNode, - CODE_LANGUAGE_FRIENDLY_NAME_MAP, - CODE_LANGUAGE_MAP, - getLanguageFriendlyName, -} from '@lexical/code'; -import { $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link'; -import { - $isListNode, - INSERT_CHECK_LIST_COMMAND, - INSERT_ORDERED_LIST_COMMAND, - INSERT_UNORDERED_LIST_COMMAND, - ListNode, - REMOVE_LIST_COMMAND, -} from '@lexical/list'; -import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; -import { - $createHeadingNode, - $createQuoteNode, - $isHeadingNode, - HeadingTagType, -} from '@lexical/rich-text'; -import { - $getSelectionStyleValueForProperty, - $isParentElementRTL, - $patchStyleText, - $selectAll, - $setBlocksType, -} from '@lexical/selection'; -import { - $findMatchingParent, - $getNearestBlockElementAncestorOrThrow, - $getNearestNodeOfType, - mergeRegister, -} from '@lexical/utils'; -import { FormatAlignCenterOutlined, FormatListBulletedOutlined, FormatListNumberedOutlined, - FormatQuoteOutlined, SegmentOutlined } from '@mui/icons-material'; -import CodeIcon from '@mui/icons-material/Code'; -import FormatAlignJustifyOutlined from '@mui/icons-material/FormatAlignJustifyOutlined'; -import FormatAlignLeftOutlined from '@mui/icons-material/FormatAlignLeftOutlined'; -import FormatAlignRightOutlined from '@mui/icons-material/FormatAlignRightOutlined'; -import FormatBoldOutlinedIcon from '@mui/icons-material/FormatBoldOutlined'; -import FormatItalicOutlinedIcon from '@mui/icons-material/FormatItalicOutlined'; -import FormatUnderlinedOutlinedIcon from '@mui/icons-material/FormatUnderlinedOutlined'; -import InsertLinkOutlinedIcon from '@mui/icons-material/InsertLinkOutlined'; -import RedoOutlinedIcon from '@mui/icons-material/RedoOutlined'; -import UndoOutlinedIcon from '@mui/icons-material/UndoOutlined'; -import { - $createParagraphNode, - $getNodeByKey, - $getRoot, - $getSelection, - $isRangeSelection, - $isRootOrShadowRoot, - $isTextNode, - CAN_REDO_COMMAND, - CAN_UNDO_COMMAND, - COMMAND_PRIORITY_CRITICAL, - FORMAT_ELEMENT_COMMAND, - FORMAT_TEXT_COMMAND, - INDENT_CONTENT_COMMAND, - LexicalEditor, - NodeKey, - OUTDENT_CONTENT_COMMAND, - REDO_COMMAND, - SELECTION_CHANGE_COMMAND, - UNDO_COMMAND, -} from 'lexical'; -import { FormatHeader1, FormatHeader2, FormatHeader3, FormatListChecks } from 'mdi-material-ui'; -import { FC, useCallback, useEffect, useState } from 'react'; - -import { getSelectedNode } from '../../utils/get-select-node'; -import { sanitizeUrl } from '../../utils/url'; -import { DropDown,DropDownItem } from '../dropdown/dropdown'; - -const blockTypeToBlockName = { - bullet: 'Bulleted List', - check: 'Check List', - code: 'Code Block', - h1: 'Heading 1', - h2: 'Heading 2', - h3: 'Heading 3', - h4: 'Heading 4', - h5: 'Heading 5', - h6: 'Heading 6', - number: 'Numbered List', - paragraph: 'Normal', - quote: 'Quote', -}; - -function getCodeLanguageOptions(): [string, string][] { - const options: [string, string][] = []; - - for (const [lang, friendlyName] of Object.entries( - CODE_LANGUAGE_FRIENDLY_NAME_MAP, - )) { - options.push([lang, friendlyName]); - } - - return options; -} - -const CODE_LANGUAGE_OPTIONS = getCodeLanguageOptions(); - -const FONT_FAMILY_OPTIONS: [string, string][] = [ - ['Arial', 'Arial'], - ['Courier New', 'Courier New'], - ['Georgia', 'Georgia'], - ['Times New Roman', 'Times New Roman'], - ['Trebuchet MS', 'Trebuchet MS'], - ['Verdana', 'Verdana'], -]; - -const FONT_SIZE_OPTIONS: [string, string][] = [ - ['10px', '10px'], - ['11px', '11px'], - ['12px', '12px'], - ['13px', '13px'], - ['14px', '14px'], - ['15px', '15px'], - ['16px', '16px'], - ['17px', '17px'], - ['18px', '18px'], - ['19px', '19px'], - ['20px', '20px'], -]; - -function dropDownActiveClass(active: boolean): string { - if (active) return 'active dropdown-item-active'; - - return ''; -} - -interface BlockFormatDropDownProps { - blockType: keyof typeof blockTypeToBlockName; - editor: LexicalEditor; - disabled?: boolean; -} - -interface FontDropDownProps { - editor: LexicalEditor; - value: string; - style: string; - disabled?: boolean; -} - -const BlockFormatDropDown: FC = ({ - editor, - blockType, - disabled = false, -}) => { - const formatParagraph = (): void => { - editor.update(() => { - const selection = $getSelection(); - - if ( - $isRangeSelection(selection) - ) { - $setBlocksType(selection, () => $createParagraphNode()); - } - }); - }; - - const formatHeading = (headingSize: HeadingTagType): void => { - if (blockType !== headingSize) { - editor.update(() => { - const selection = $getSelection(); - - if ( - $isRangeSelection(selection) - ) { - $setBlocksType(selection, () => $createHeadingNode(headingSize)); - } - }); - } - }; - - const formatBulletList = (): void => { - if (blockType !== 'bullet') { - editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined); - } else { - editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined); - } - }; - - const formatCheckList = (): void => { - if (blockType !== 'check') { - editor.dispatchCommand(INSERT_CHECK_LIST_COMMAND, undefined); - } else { - editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined); - } - }; - - const formatNumberedList = (): void => { - if (blockType !== 'number') { - editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined); - } else { - editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined); - } - }; - - const formatQuote = (): void => { - if (blockType !== 'quote') { - editor.update(() => { - const selection = $getSelection(); - - if ( - $isRangeSelection(selection) - ) { - $setBlocksType(selection, () => $createQuoteNode()); - } - }); - } - }; - - return ( - - - - Normal - - formatHeading('h1')} - > - - Heading 1 - - formatHeading('h2')} - > - - Heading 2 - - formatHeading('h3')} - > - - Heading 3 - - - - Bullet List - - - - Numbered List - - - - Check List - - - - Quote - - - ); -}; - -const Divider: FC = () => { - return
; -}; - -const FontDropDown: FC = ({ - editor, - value, - style, - disabled = false, -}) => { - const handleClick = useCallback( - (option: string) => { - editor.update(() => { - const selection = $getSelection(); - - if ($isRangeSelection(selection)) { - $patchStyleText(selection, { - [style]: option, - }); - } - }); - }, - [editor, style], - ); - - const buttonAriaLabel = - style === 'font-family' - ? 'Formatting options for font family' - : 'Formatting options for font size'; - - return ( - - {(style === 'font-family' ? FONT_FAMILY_OPTIONS : FONT_SIZE_OPTIONS).map( - ([option, text]) => ( - handleClick(option)} - key={option} - > - {text} - - ), - )} - - ); -}; - -const ToolbarPlugin: FC = () => { - const [editor] = useLexicalComposerContext(); - const [activeEditor, setActiveEditor] = useState(editor); - const [blockType, setBlockType] = - useState('paragraph'); - const [selectedElementKey, setSelectedElementKey] = useState( - null, - ); - const [fontSize, setFontSize] = useState('15px'); - const [, setFontColor] = useState('#000'); - const [, setBgColor] = useState('#fff'); - const [fontFamily, setFontFamily] = useState('Arial'); - const [isLink, setIsLink] = useState(false); - const [isBold, setIsBold] = useState(false); - const [isItalic, setIsItalic] = useState(false); - const [isUnderline, setIsUnderline] = useState(false); - const [, setIsStrikethrough] = useState(false); - const [, setIsSubscript] = useState(false); - const [, setIsSuperscript] = useState(false); - const [isCode, setIsCode] = useState(false); - const [canUndo, setCanUndo] = useState(false); - const [canRedo, setCanRedo] = useState(false); - const [, setIsRTL] = useState(false); - const [codeLanguage, setCodeLanguage] = useState(''); - const [isEditable, setIsEditable] = useState(() => editor.isEditable()); - const IS_APPLE = false; - - const updateToolbar = useCallback(() => { - const selection = $getSelection(); - - if ($isRangeSelection(selection)) { - const anchorNode = selection.anchor.getNode(); - let element = - anchorNode.getKey() === 'root' - ? anchorNode - : $findMatchingParent(anchorNode, (e) => { - const parent = e.getParent(); - - return parent !== null && $isRootOrShadowRoot(parent); - }); - - if (element === null) { - element = anchorNode.getTopLevelElementOrThrow(); - } - - const elementKey = element.getKey(); - const elementDOM = activeEditor.getElementByKey(elementKey); - - // Update text format - setIsBold(selection.hasFormat('bold')); - setIsItalic(selection.hasFormat('italic')); - setIsUnderline(selection.hasFormat('underline')); - setIsStrikethrough(selection.hasFormat('strikethrough')); - setIsSubscript(selection.hasFormat('subscript')); - setIsSuperscript(selection.hasFormat('superscript')); - setIsCode(selection.hasFormat('code')); - setIsRTL($isParentElementRTL(selection)); - - // Update links - const node = getSelectedNode(selection); - const parent = node.getParent(); - - if ($isLinkNode(parent) || $isLinkNode(node)) { - setIsLink(true); - } else { - setIsLink(false); - } - - if (elementDOM !== null) { - setSelectedElementKey(elementKey); - - if ($isListNode(element)) { - const parentList = $getNearestNodeOfType( - anchorNode, - ListNode, - ); - const type = parentList - ? parentList.getListType() - : element.getListType(); - setBlockType(type); - } else { - const type = $isHeadingNode(element) - ? element.getTag() - : element.getType(); - - if (type in blockTypeToBlockName) { - setBlockType(type as keyof typeof blockTypeToBlockName); - } - - if ($isCodeNode(element)) { - const language = - element.getLanguage() as keyof typeof CODE_LANGUAGE_MAP; - setCodeLanguage( - language ? CODE_LANGUAGE_MAP[language] || language : '', - ); - - return; - } - } - } - // Handle buttons - setFontSize( - $getSelectionStyleValueForProperty(selection, 'font-size', '15px'), - ); - setFontColor( - $getSelectionStyleValueForProperty(selection, 'color', '#000'), - ); - setBgColor( - $getSelectionStyleValueForProperty( - selection, - 'background-color', - '#fff', - ), - ); - setFontFamily( - $getSelectionStyleValueForProperty(selection, 'font-family', 'Arial'), - ); - } - }, [activeEditor]); - - useEffect(() => { - return editor.registerCommand( - SELECTION_CHANGE_COMMAND, - (_payload, newEditor) => { - updateToolbar(); - setActiveEditor(newEditor); - - return false; - }, - COMMAND_PRIORITY_CRITICAL, - ); - }, [editor, updateToolbar]); - - useEffect(() => { - return mergeRegister( - editor.registerEditableListener((editable) => { - setIsEditable(editable); - }), - activeEditor.registerUpdateListener(({ editorState }) => { - editorState.read(() => { - updateToolbar(); - }); - }), - activeEditor.registerCommand( - CAN_UNDO_COMMAND, - (payload) => { - setCanUndo(payload); - - return false; - }, - COMMAND_PRIORITY_CRITICAL, - ), - activeEditor.registerCommand( - CAN_REDO_COMMAND, - (payload) => { - setCanRedo(payload); - - return false; - }, - COMMAND_PRIORITY_CRITICAL, - ), - ); - }, [activeEditor, editor, updateToolbar]); - - const onCodeLanguageSelect = useCallback( - (value: string) => { - activeEditor.update(() => { - if (selectedElementKey !== null) { - const node = $getNodeByKey(selectedElementKey); - - if ($isCodeNode(node)) { - node.setLanguage(value); - } - } - }); - }, - [activeEditor, selectedElementKey], - ); - - const insertLink = useCallback(() => { - if (!isLink) { - editor.dispatchCommand(TOGGLE_LINK_COMMAND, sanitizeUrl('https://')); - } else { - editor.dispatchCommand(TOGGLE_LINK_COMMAND, null); - } - }, [editor, isLink]); - - return ( -
- - - {blockType in blockTypeToBlockName && activeEditor === editor && ( - <> - - - )} - <> - - - - - - - - - { - activeEditor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'left'); - }} - className="item" - > - - Left Align - - { - activeEditor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'center'); - }} - className="item" - > - - Center Align - - { - activeEditor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'right'); - }} - className="item" - > - - Right Align - - { - activeEditor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'justify'); - }} - className="item" - > - - Justify Align - - - -
- ); -}; - -export { ToolbarPlugin }; \ No newline at end of file diff --git a/kpoint-react/src/lexical/lexical-components/lexical.css b/kpoint-react/src/lexical/lexical-components/lexical.css deleted file mode 100644 index 9e5cde33..00000000 --- a/kpoint-react/src/lexical/lexical-components/lexical.css +++ /dev/null @@ -1,728 +0,0 @@ -.other h2 { - font-size: 18px; - color: #444; - margin-bottom: 7px; - } - - .other a { - color: #777; - text-decoration: underline; - font-size: 14px; - } - - .other ul { - padding: 0; - margin: 0; - list-style-type: none; - } - - .App { - font-family: sans-serif; - text-align: center; - } - - h1 { - font-size: 24px; - color: #333; - } - - .ltr { - text-align: left; - } - - .rtl { - text-align: right; - } - - .editor-container { - margin: 20px auto 20px auto; - border-radius: 2px; - max-width: 780px; - color: #000; - position: relative; - line-height: 20px; - font-weight: 400; - text-align: left; - border-top-left-radius: 10px; - border-top-right-radius: 10px; - } - - .editor-inner { - width: 788px; - background: #fff; - position: relative; - } - - .editor-input { - min-height: 150px; - resize: none; - font-size: 15px; - caret-color: rgb(5, 5, 5); - position: relative; - tab-size: 1; - outline: 0; - padding: 15px 10px; - caret-color: #444; - } - - .editor-placeholder { - color: #999; - overflow: hidden; - position: absolute; - text-overflow: ellipsis; - top: 15px; - left: 10px; - font-size: 15px; - user-select: none; - display: inline-block; - pointer-events: none; - } - - .editor-text-bold { - font-weight: bold; - } - - .editor-text-italic { - font-style: italic; - } - - .editor-text-underline { - text-decoration: underline; - } - - .editor-text-strikethrough { - text-decoration: line-through; - } - - .editor-text-underlineStrikethrough { - text-decoration: underline line-through; - } - - .editor-text-code { - background-color: rgb(240, 242, 245); - padding: 1px 0.25rem; - font-family: Menlo, Consolas, Monaco, monospace; - font-size: 94%; - } - - .editor-link { - color: rgb(33, 111, 219); - text-decoration: underline; - cursor: pointer; - } - - .tree-view-output { - display: block; - background: #222; - color: #fff; - padding: 5px; - font-size: 12px; - white-space: pre-wrap; - margin: 1px auto 10px auto; - max-height: 250px; - position: relative; - border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; - overflow: auto; - line-height: 14px; - } - - .editor-code { - background-color: rgb(240, 242, 245); - font-family: Menlo, Consolas, Monaco, monospace; - display: block; - padding: 8px 8px 8px 52px; - line-height: 1.53; - font-size: 13px; - margin: 0; - margin-top: 8px; - margin-bottom: 8px; - tab-size: 2; - /* white-space: pre; */ - overflow-x: auto; - position: relative; - } - - .editor-code:before { - content: attr(data-gutter); - position: absolute; - background-color: #eee; - left: 0; - top: 0; - border-right: 1px solid #ccc; - padding: 8px; - color: #777; - white-space: pre-wrap; - text-align: right; - min-width: 25px; - } - .editor-code:after { - content: attr(data-highlight-language); - top: 0; - right: 3px; - padding: 3px; - font-size: 10px; - text-transform: uppercase; - position: absolute; - color: rgba(0, 0, 0, 0.5); - } - - .editor-tokenComment { - color: slategray; - } - - .editor-tokenPunctuation { - color: #999; - } - - .editor-tokenProperty { - color: #905; - } - - .editor-tokenSelector { - color: #690; - } - - .editor-tokenOperator { - color: #9a6e3a; - } - - .editor-tokenAttr { - color: #07a; - } - - .editor-tokenVariable { - color: #e90; - } - - .editor-tokenFunction { - color: #dd4a68; - } - - .editor-paragraph { - margin: 0; - margin-bottom: 8px; - position: relative; - } - - .editor-paragraph:last-child { - margin-bottom: 0; - } - - .editor-heading-h1 { - font-size: 24px; - color: rgb(5, 5, 5); - font-weight: 400; - margin: 0; - margin-bottom: 12px; - padding: 0; - } - - .editor-heading-h2 { - font-size: 15px; - color: rgb(101, 103, 107); - font-weight: 700; - margin: 0; - margin-top: 10px; - padding: 0; - text-transform: uppercase; - } - - .editor-quote { - margin: 0; - margin-left: 20px; - font-size: 15px; - color: rgb(101, 103, 107); - border-left-color: rgb(206, 208, 212); - border-left-width: 4px; - border-left-style: solid; - padding-left: 16px; - } - - .editor-list-ol { - padding: 0; - margin: 0; - margin-left: 16px; - } - - .editor-list-ul { - padding: 0; - margin: 0; - margin-left: 16px; - } - - .editor-listitem { - margin: 8px 32px 8px 32px; - } - - .editor-nested-listitem { - list-style-type: none; - } - - pre::-webkit-scrollbar { - background: transparent; - width: 10px; - } - - pre::-webkit-scrollbar-thumb { - background: #999; - } - - .debug-timetravel-panel { - overflow: hidden; - padding: 0 0 10px 0; - margin: auto; - display: flex; - } - - .debug-timetravel-panel-slider { - padding: 0; - flex: 8; - } - - .debug-timetravel-panel-button { - padding: 0; - border: 0; - background: none; - flex: 1; - color: #fff; - font-size: 12px; - } - - .debug-timetravel-panel-button:hover { - text-decoration: underline; - } - - .debug-timetravel-button { - border: 0; - padding: 0; - font-size: 12px; - top: 10px; - right: 15px; - position: absolute; - background: none; - color: #fff; - } - - .debug-timetravel-button:hover { - text-decoration: underline; - } - - .emoji { - color: transparent; - background-size: 16px 16px; - background-position: center; - background-repeat: no-repeat; - vertical-align: middle; - margin: 0 -1px; - } - - .emoji-inner { - padding: 0 0.15em; - } - - .emoji-inner::selection { - color: transparent; - background-color: rgba(150, 150, 150, 0.4); - } - - .emoji-inner::moz-selection { - color: transparent; - background-color: rgba(150, 150, 150, 0.4); - } - - .emoji.happysmile { - background-image: url('../../lexical/images/emoji/1F642.png'); - } - - .toolbar { - display: grid; - grid-template-columns: repeat(8, 1fr); - grid-template-rows: repeat(2, 1fr); - margin-bottom: 1px; - background: hsl(0, 0%, 100%); - padding: 4px; - border-top-left-radius: 10px; - border-top-right-radius: 10px; - vertical-align: middle; - } - - @media screen and (max-width: 400px) { - .toolbar { - grid-template-columns: repeat(3, minmax(40px, 80px)); - } - - .toolbar button.toolbar-item { - max-width: 90px; - } - - .toolbar button.toolbar-item.spaced.bold { - max-width: 40px; - } - - .toolbar button.toolbar-item.spaced.italic { - max-width: 40px; - } - - .toolbar button.toolbar-item.spaced.underline { - max-width: 40px; - } - - .toolbar button.toolbar-item.spaced.code { - max-width: 40px; - } - - .toolbar button.toolbar-item.spaced.link { - max-width: 40px; - } - - .toolbar button.toolbar-item.spaced.undo { - max-width: 40px; - } - - .toolbar button.toolbar-item.redo { - max-width: 40px; - } - } - - .toolbar.proj-create-page { - border: 1px solid gray; - } - - .toolbar button.toolbar-item { - border: 0; - display: flex; - background: none; - border-radius: 10px; - padding: 8px; - cursor: pointer; - vertical-align: middle; - justify-content: center; - } - - .toolbar button.toolbar-item:disabled { - cursor: not-allowed; - } - - .toolbar button.toolbar-item.spaced { - margin-right: 2px; - } - - .toolbar button.toolbar-item i.format { - background-size: contain; - display: inline-block; - height: 18px; - width: 18px; - margin-top: 2px; - vertical-align: -0.25em; - display: flex; - opacity: 0.6; - } - - .toolbar button.toolbar-item:disabled i.format { - opacity: 0.2; - } - - .toolbar button.toolbar-item.active { - background-color: rgba(223, 232, 250, 0.3); - } - - .toolbar button.toolbar-item.active i { - opacity: 1; - } - - .toolbar .toolbar-item:hover:not([disabled]) { - background-color: #eee; - } - - .toolbar .divider { - width: 1px; - background-color: #eee; - margin: 0 4px; - } - - .toolbar select.toolbar-item { - border: 0; - display: flex; - background: none; - border-radius: 10px; - padding: 8px; - vertical-align: middle; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - width: 70px; - font-size: 14px; - color: #777; - text-overflow: ellipsis; - } - - .toolbar select.code-language { - text-transform: capitalize; - width: 130px; - } - - .toolbar .toolbar-item .text { - display: flex; - line-height: 20px; - width: 200px; - vertical-align: middle; - font-size: 14px; - color: #777; - text-overflow: ellipsis; - width: 70px; - overflow: hidden; - height: 20px; - text-align: left; - } - - .toolbar .toolbar-item .icon { - display: flex; - width: 20px; - height: 20px; - user-select: none; - margin-right: 8px; - line-height: 16px; - background-size: contain; - } - - .toolbar i.chevron-down { - margin-top: 3px; - width: 16px; - height: 16px; - display: flex; - user-select: none; - } - - .toolbar i.chevron-down.inside { - width: 16px; - height: 16px; - display: flex; - margin-left: -25px; - margin-top: 11px; - margin-right: 10px; - pointer-events: none; - } - - i.chevron-down { - background-color: transparent; - background-size: contain; - display: inline-block; - height: 8px; - width: 8px; - } - - #block-controls button:hover { - background-color: #efefef; - } - - #block-controls button:focus-visible { - border-color: blue; - } - - #block-controls span.block-type { - background-size: contain; - display: block; - width: 18px; - height: 18px; - margin: 2px; - } - - .dropdown { - z-index: 5; - display: block; - position: absolute; - box-shadow: 0 12px 28px 0 rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1), - inset 0 0 0 1px rgba(255, 255, 255, 0.5); - border-radius: 8px; - min-width: 100px; - min-height: 40px; - background-color: #fff; - } - - .dropdown .item { - margin: 0 8px 0 8px; - padding: 8px; - color: #050505; - cursor: pointer; - line-height: 16px; - font-size: 15px; - display: flex; - align-content: center; - flex-direction: row; - flex-shrink: 0; - justify-content: space-between; - background-color: #fff; - border-radius: 8px; - border: 0; - min-width: 268px; - } - - .dropdown .item .active { - display: flex; - width: 20px; - height: 20px; - background-size: contain; - } - - .dropdown .item:first-child { - margin-top: 8px; - } - - .dropdown .item:last-child { - margin-bottom: 8px; - } - - .dropdown .item:hover { - background-color: #eee; - } - - .dropdown .item .text { - display: flex; - line-height: 20px; - flex-grow: 1; - width: 200px; - } - - .dropdown .item .icon { - display: flex; - width: 20px; - height: 20px; - user-select: none; - margin-right: 12px; - line-height: 16px; - background-size: contain; - } - - .link-editor .button.active, - .toolbar .button.active { - background-color: rgb(223, 232, 250); - } - - .link-editor .link-input { - display: block; - width: calc(100% - 75px); - box-sizing: border-box; - margin: 12px 12px; - padding: 8px 12px; - border-radius: 15px; - background-color: #eee; - font-size: 15px; - color: rgb(5, 5, 5); - border: 0; - outline: 0; - position: relative; - font-family: inherit; - } - - .link-editor .link-view { - display: block; - width: calc(100% - 24px); - margin: 8px 12px; - padding: 8px 12px; - border-radius: 15px; - font-size: 15px; - color: rgb(5, 5, 5); - border: 0; - outline: 0; - position: relative; - font-family: inherit; - } - - .link-editor .link-view a { - display: block; - word-break: break-word; - width: calc(100% - 33px); - } - - .link-editor div.link-edit { - display: flex; - justify-content: center; - align-items: center; - background-size: 16px; - background-position: center; - background-repeat: no-repeat; - width: 35px; - vertical-align: -0.25em; - position: absolute; - right: 30px; - top: 0; - bottom: 0; - cursor: pointer; - } - - .link-editor div.link-trash { - display: flex; - justify-content: center; - align-items: center; - background-size: 16px; - background-position: center; - background-repeat: no-repeat; - width: 35px; - vertical-align: -0.25em; - position: absolute; - right: 0; - top: 0; - bottom: 0; - cursor: pointer; - } - - .link-editor div.link-cancel { - display: flex; - justify-content: center; - align-items: center; - background-size: 16px; - background-position: center; - background-repeat: no-repeat; - width: 35px; - vertical-align: -0.25em; - margin-right: 28px; - position: absolute; - right: 0; - top: 0; - bottom: 0; - cursor: pointer; - } - - .link-editor div.link-confirm { - display: flex; - justify-content: center; - align-items: center; - background-size: 16px; - background-position: center; - background-repeat: no-repeat; - width: 35px; - vertical-align: -0.25em; - margin-right: 2px; - position: absolute; - right: 0; - top: 0; - bottom: 0; - cursor: pointer; - } - - .link-editor .link-input a { - color: rgb(33, 111, 219); - text-decoration: underline; - white-space: nowrap; - overflow: hidden; - margin-right: 30px; - text-overflow: ellipsis; - } - - .link-editor .link-input a:hover { - text-decoration: underline; - } - - .link-editor .font-size-wrapper, - .link-editor .font-family-wrapper { - display: flex; - margin: 0 4px; - } - - .link-editor select { - padding: 6px; - border: none; - background-color: rgba(0, 0, 0, 0.075); - border-radius: 4px; - } \ No newline at end of file diff --git a/kpoint-react/src/lexical/theme/lexical-editor-theme.ts b/kpoint-react/src/lexical/theme/lexical-editor-theme.ts deleted file mode 100644 index e275ee4d..00000000 --- a/kpoint-react/src/lexical/theme/lexical-editor-theme.ts +++ /dev/null @@ -1,69 +0,0 @@ -const lexicalEditorTheme = { - ltr: 'ltr', - rtl: 'rtl', - placeholder: 'editor-placeholder', - paragraph: 'editor-paragraph', - quote: 'editor-quote', - heading: { - h1: 'editor-heading-h1', - h2: 'editor-heading-h2', - h3: 'editor-heading-h3', - h4: 'editor-heading-h4', - h5: 'editor-heading-h5', - }, - list: { - nested: { - listitem: 'editor-nested-listitem', - }, - ol: 'editor-list-ol', - ul: 'editor-list-ul', - listitem: 'editor-listitem', - }, - image: 'editor-image', - link: 'editor-link', - text: { - bold: 'editor-text-bold', - italic: 'editor-text-italic', - overflowed: 'editor-text-overflowed', - hashtag: 'editor-text-hashtag', - underline: 'editor-text-underline', - strikethrough: 'editor-text-strikethrough', - underlineStrikethrough: 'editor-text-underlineStrikethrough', - code: 'editor-text-code', - }, - code: 'editor-code', - codeHighlight: { - atrule: 'editor-tokenAttr', - attr: 'editor-tokenAttr', - boolean: 'editor-tokenProperty', - builtin: 'editor-tokenSelector', - cdata: 'editor-tokenComment', - char: 'editor-tokenSelector', - class: 'editor-tokenFunction', - 'class-name': 'editor-tokenFunction', - comment: 'editor-tokenComment', - constant: 'editor-tokenProperty', - deleted: 'editor-tokenProperty', - doctype: 'editor-tokenComment', - entity: 'editor-tokenOperator', - function: 'editor-tokenFunction', - important: 'editor-tokenVariable', - inserted: 'editor-tokenSelector', - keyword: 'editor-tokenAttr', - namespace: 'editor-tokenVariable', - number: 'editor-tokenProperty', - operator: 'editor-tokenOperator', - prolog: 'editor-tokenComment', - property: 'editor-tokenProperty', - punctuation: 'editor-tokenPunctuation', - regex: 'editor-tokenVariable', - selector: 'editor-tokenSelector', - string: 'editor-tokenSelector', - symbol: 'editor-tokenProperty', - tag: 'editor-tokenProperty', - url: 'editor-tokenOperator', - variable: 'editor-tokenVariable', - }, -}; - -export { lexicalEditorTheme }; \ No newline at end of file diff --git a/kpoint-react/src/lexical/utils/get-select-node.ts b/kpoint-react/src/lexical/utils/get-select-node.ts deleted file mode 100644 index e32cc041..00000000 --- a/kpoint-react/src/lexical/utils/get-select-node.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ -import { $isAtNodeEnd } from '@lexical/selection'; -import { ElementNode, RangeSelection, TextNode } from 'lexical'; - -function getSelectedNode( - selection: RangeSelection, -): TextNode | ElementNode { - const anchor = selection.anchor; - const focus = selection.focus; - const anchorNode = selection.anchor.getNode(); - const focusNode = selection.focus.getNode(); - - if (anchorNode === focusNode) { - return anchorNode; - } - const isBackward = selection.isBackward(); - - if (isBackward) { - return $isAtNodeEnd(focus) ? anchorNode : focusNode; - } - - return $isAtNodeEnd(anchor) ? anchorNode : focusNode; - -} - -export { getSelectedNode }; \ No newline at end of file diff --git a/kpoint-react/src/lexical/utils/set-floating-elem-position-for-link-editor.ts b/kpoint-react/src/lexical/utils/set-floating-elem-position-for-link-editor.ts deleted file mode 100644 index 3cc4cd6b..00000000 --- a/kpoint-react/src/lexical/utils/set-floating-elem-position-for-link-editor.ts +++ /dev/null @@ -1,42 +0,0 @@ -const VERTICAL_GAP = 10; -const HORIZONTAL_OFFSET = 5; - -function setFloatingElemPositionForLinkEditor( - targetRect: DOMRect | null, - floatingElem: HTMLElement, - anchorElem: HTMLElement, - verticalGap: number = VERTICAL_GAP, - horizontalOffset: number = HORIZONTAL_OFFSET, -): void { - const scrollerElem = anchorElem.parentElement; - - if (targetRect === null || !scrollerElem) { - floatingElem.style.opacity = '0'; - floatingElem.style.transform = 'translate(-10000px, -10000px)'; - - return; - } - - const floatingElemRect = floatingElem.getBoundingClientRect(); - const anchorElementRect = anchorElem.getBoundingClientRect(); - const editorScrollerRect = scrollerElem.getBoundingClientRect(); - - let top = targetRect.top - verticalGap; - let left = targetRect.left - horizontalOffset; - - if (top < editorScrollerRect.top) { - top += floatingElemRect.height + targetRect.height + verticalGap * 2; - } - - if (left + floatingElemRect.width > editorScrollerRect.right) { - left = editorScrollerRect.right - floatingElemRect.width - horizontalOffset; - } - - top -= anchorElementRect.top; - left -= anchorElementRect.left; - - floatingElem.style.opacity = '1'; - floatingElem.style.transform = `translate(${left}px, ${top}px)`; -} - -export { setFloatingElemPositionForLinkEditor }; \ No newline at end of file diff --git a/kpoint-react/src/lexical/utils/url.ts b/kpoint-react/src/lexical/utils/url.ts deleted file mode 100644 index bebf5b0f..00000000 --- a/kpoint-react/src/lexical/utils/url.ts +++ /dev/null @@ -1,16 +0,0 @@ -export function sanitizeUrl(url: string): string { - /** A pattern that matches safe URLs. */ - const SAFE_URL_PATTERN = - /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^&:/?#]*(?:[/?#]|$))/gi; - - /** A pattern that matches safe data URLs. */ - const DATA_URL_PATTERN = - // eslint-disable-next-line max-len - /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i; - - url = String(url).trim(); - - if (url.match(SAFE_URL_PATTERN) || url.match(DATA_URL_PATTERN)) return url; - - return 'https://'; -} \ No newline at end of file diff --git a/kpoint-react/src/services/http/http.service.ts b/kpoint-react/src/services/http/http.service.ts index 6e463d38..42328c4a 100755 --- a/kpoint-react/src/services/http/http.service.ts +++ b/kpoint-react/src/services/http/http.service.ts @@ -77,7 +77,8 @@ class Http { message: response.statusText, })); - if (response.status === 401) { + if (response.status === 401 && window.location.pathname !== '/sign-in') { + this.#storage.removeItem(StorageKey.USER); this.#storage.removeItem(StorageKey.TOKEN); window.location.href = '/sign-in'; diff --git a/kpoint-react/src/services/projects/project-api.ts b/kpoint-react/src/services/projects/project-api.ts index ae6a8eeb..1f236445 100644 --- a/kpoint-react/src/services/projects/project-api.ts +++ b/kpoint-react/src/services/projects/project-api.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { HttpMethod } from 'common/enums/http/http-method.enum'; -import { TestRequest } from 'common/types/projects/testRequest'; +import { PostProject } from 'common/types/projects/testRequest'; import { ProjectsPageType, ProjectType } from 'common/types/types'; import { ContentType } from '../../common/enums/file/content-type.enum'; @@ -71,7 +71,7 @@ class ProjectApi { ); } - public createNew(payload: TestRequest): Promise { + public createNew(payload: PostProject): Promise { const formData = new FormData(); formData.append( 'createdProject', @@ -113,7 +113,7 @@ class ProjectApi { ); } - public editProject(payload: { id: string; bodyData: any }): Promise { + public editProject(payload: { id: string; bodyData: any }): Promise { return this.#http.load( `${this.#apiPrefix}/projects/${payload.id}/settings`, { diff --git a/kpoint-react/src/store/auth/reducer.ts b/kpoint-react/src/store/auth/reducer.ts index c96de55e..142d8257 100644 --- a/kpoint-react/src/store/auth/reducer.ts +++ b/kpoint-react/src/store/auth/reducer.ts @@ -1,17 +1,21 @@ import { createSlice } from '@reduxjs/toolkit'; +import { StorageKey } from 'common/enums/app/storage-key.enum'; +import { storage } from 'services/services'; import { UserTypeSuggestion } from '../../common/types/suggestions/user-type-suggestion'; import { login, loginWithOAuth2 } from './actions'; type State = { token: string | null; - isloggedIn: boolean; + isLoggedIn: boolean; + isInProcess: boolean; user: UserTypeSuggestion | null; }; const initialState: State = { token: null, - isloggedIn: false, + isLoggedIn: false, + isInProcess: false, user: null, }; @@ -22,10 +26,15 @@ const authSlice = createSlice({ state.token = null; state.user = null; }) + .addCase(login.pending, (state) => { + state.isInProcess = !state.isInProcess; + }) .addCase(login.fulfilled, (state, { payload }) => { + state.isLoggedIn = !state.isLoggedIn; + state.isInProcess = !state.isInProcess; state.token = payload.token; - state.isloggedIn = true; - // state.user = payload.user; + storage.setItem(StorageKey.TOKEN, payload.token); + storage.setItem(StorageKey.USER, JSON.stringify(payload.user)); }) .addCase(loginWithOAuth2.rejected, (state) => { state.token = null; @@ -33,8 +42,7 @@ const authSlice = createSlice({ }) .addCase(loginWithOAuth2.fulfilled, (state, { payload }) => { state.token = payload.token; - state.isloggedIn = true; - // state.user = payload.user; + state.isLoggedIn = true; }); }, initialState, diff --git a/kpoint-react/src/store/profile/reducer.ts b/kpoint-react/src/store/profile/reducer.ts index f34ce250..0919622a 100644 --- a/kpoint-react/src/store/profile/reducer.ts +++ b/kpoint-react/src/store/profile/reducer.ts @@ -53,6 +53,7 @@ const profileSlice = createSlice({ }) .addCase(updateMyProfile.fulfilled, (state, { payload }) => { state.profile = payload; + state.status = 'updated'; }) .addCase(changePassword.rejected, (state) => { state.status = 'error'; diff --git a/kpoint-react/src/store/projects/actions.ts b/kpoint-react/src/store/projects/actions.ts index b292a424..fb7b59f6 100644 --- a/kpoint-react/src/store/projects/actions.ts +++ b/kpoint-react/src/store/projects/actions.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { createAsyncThunk } from '@reduxjs/toolkit'; import { AsyncThunkConfig } from 'common/types/app/async-thunk-config.type'; -import { TestRequest } from 'common/types/projects/testRequest'; +import { PostProject } from 'common/types/projects/testRequest'; import { ProjectType } from '../../common/types/projects/project.type'; import { ProjectsPageType } from '../../common/types/projects/projects-page.type'; @@ -41,12 +41,12 @@ const getAllProjectsAddMore = createAsyncThunk< const createNew = createAsyncThunk< ProjectType, - { testData: TestRequest }, + { bodyData: PostProject }, AsyncThunkConfig >(ActionType.POST_NEW, async (payload, { extra }) => { const { projectApi } = extra; - return projectApi.createNew(payload.testData); + return projectApi.createNew(payload.bodyData); }); const subscribeToProject = createAsyncThunk< @@ -70,7 +70,7 @@ const unSubscribe = createAsyncThunk< }); const editProject = createAsyncThunk< - any, + ProjectType, { id: string; bodyData: any }, AsyncThunkConfig >(ActionType.EDIT, async (payload, { extra }) => { diff --git a/kpoint-react/src/store/projects/reducer.ts b/kpoint-react/src/store/projects/reducer.ts index 565053b4..881ae1f2 100644 --- a/kpoint-react/src/store/projects/reducer.ts +++ b/kpoint-react/src/store/projects/reducer.ts @@ -1,4 +1,4 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { createSlice } from '@reduxjs/toolkit'; import { ProjectsEditType, ProjectsPageType } from 'common/types/types'; import { ProjectType } from '../../common/types/projects/project.type'; @@ -6,6 +6,7 @@ import { SubscriptionRequestType } from '../../common/types/projects/subscriptio import { createNew, editLogo, + editProject, getAllProjectsAddMore, getAllProjectsDefault, getByUrl, @@ -18,6 +19,7 @@ type State = { projects: ProjectsPageType | null; editProject: ProjectsEditType | null; subscribe: SubscriptionRequestType | null; + isSubscribePending: boolean; error: string; }; @@ -56,6 +58,7 @@ const initialState: State = { projects: null, editProject: null, subscribe: null, + isSubscribePending: false, error: '', }; @@ -63,59 +66,7 @@ const projectSlice = createSlice({ name: 'project', initialState, reducers: { - addTagLocally: (state, action: PayloadAction) => { - state.project.tags.push(action.payload); - }, - deleteTagLocally: (state, action: PayloadAction) => { - state.project.tags = state.project.tags.filter( - (tag) => tag !== action.payload, - ); - }, - editTitleLocally: (state, action) => { - state.project.title = action.payload; - }, - editDescriptionLocally: (state, action) => { - state.project.description = action.payload; - }, - editSummaryLocally: (state, action) => { - state.project.summary = action.payload; - }, - editLogoLocally: (state, action) => { - state.project.logoImgUrl = action.payload; - }, - addContactLocally: (state, action) => { - Object.keys(state.project.networksLinks).forEach((item) => { - if (item !== action.payload.linkName) { - state.project.networksLinks[action.payload.linkName as - keyof typeof state.project.networksLinks] = action.payload.link; - } - }); - }, - deleteContactLocally: (state, action) => { - state.project.networksLinks = action.payload; - }, - subscribeToProjectLocally: (state, action) => { - const content = state.projects?.content; - const proj = content?.filter( - (content) => content.projectId === action.payload, - ); - - if (state.projects) { - state.projects.content = state.projects.content.filter( - (content) => content.projectId !== action.payload, - ); - } - proj?.forEach((p) => (p.isFollowed = true)); - - }, - unsubscribeFromProjectLocally: (state - , action) => { - state.project.isFollowed = action.payload; - }, - subscribeToProjectPage: (state, action) => { - state.project.isFollowed = action.payload; - }, }, extraReducers: (builder) => { builder @@ -150,47 +101,31 @@ const projectSlice = createSlice({ .addCase(createNew.fulfilled, (state, { payload }) => { state.project = payload; }) + .addCase(subscribeToProject.pending, (state) => { + state.isSubscribePending = true; + }) .addCase(subscribeToProject.fulfilled, (state, { payload }) => { state.subscribe = payload; + state.isSubscribePending = false; }) .addCase(subscribeToProject.rejected, (state) => { state.subscribe = null; + state.isSubscribePending = false; }) .addCase(unSubscribe.fulfilled, (state, { payload }) => { state.subscribe = payload; }) .addCase(editLogo.fulfilled, (state, { payload }) => { state.project.logoImgUrl = payload; + }) + .addCase(editProject.fulfilled, (state, { payload }) => { + state.project = { ...state.project, ...payload }; }); }, }); -const { - addTagLocally, - deleteTagLocally, - editTitleLocally, - editDescriptionLocally, - editLogoLocally, - subscribeToProjectLocally, - subscribeToProjectPage, - unsubscribeFromProjectLocally, - editSummaryLocally, - addContactLocally, - deleteContactLocally, -} = projectSlice.actions; const projectReducer = projectSlice.reducer; export { - addContactLocally, - addTagLocally, - deleteContactLocally, - deleteTagLocally, - editDescriptionLocally, - editLogoLocally, - editSummaryLocally, - editTitleLocally, projectReducer, - subscribeToProjectLocally, - subscribeToProjectPage, - unsubscribeFromProjectLocally, }; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..8c3e5347 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "kpoint", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/package.json @@ -0,0 +1 @@ +{}