diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 285f0af7..58c14e19 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -304,6 +304,7 @@ ui: oauth_callback: Processing http_404: HTTP Error 404 http_50X: HTTP Error 500 + http_403: HTTP Error 403 notifications: title: Notifications inbox: Inbox @@ -526,6 +527,7 @@ ui: tip_answer: >- Use comments to reply to other users or notify them of changes. If you are adding new information, edit your post instead of commenting. + tip_vote: It adds something useful to the post edit_answer: title: Edit Answer default_reason: Edit answer @@ -803,6 +805,11 @@ ui: answered: answered closed_in: Closed in show_exist: Show existing question. + useful: Useful + question_useful: It is useful and clear + question_un_useful: It is unclear or not useful + answer_useful: It is useful + answer_un_useful: It is not useful answers: title: Answers score: Score @@ -820,10 +827,19 @@ ui: edit link to refine and improve your existing answer, instead.

empty: Answer cannot be empty. characters: content must be at least 6 characters in length. + tips: + header_1: Thanks for your answer + li1_1: Please be sure to answer the question. Provide details and share your research. + li1_2: Back up any statements you make with references or personal experience. + header_2: But avoid ... + li2_1: Asking for help, seeking clarification, or responding to other answers. + reopen: + confirm_btn: Reopen title: Reopen this post content: Are you sure you want to reopen? success: This post has been reopened + delete: title: Delete this post question: >- @@ -1048,13 +1064,11 @@ ui: votes: votes answers: answers accepted: Accepted - page_404: - http_error: HTTP Error 404 - desc: "Unfortunately, this page doesn't exist." - back_home: Back to homepage - page_50X: - http_error: HTTP Error 500 - desc: The server encountered an error and could not complete your request. + page_error: + http_error: HTTP Error {{ code }} + desc_403: You don’t have permission to access this page. + desc_404: Unfortunately, this page doesn't exist. + desc_50X: The server encountered an error and could not complete your request. back_home: Back to homepage page_maintenance: desc: "We are under maintenance, we'll be back soon." @@ -1468,8 +1482,8 @@ ui: no_data: "We couldn't find anything." users: title: Users - users_with_the_most_reputation: Users with the highest reputation scores - users_with_the_most_vote: Users who voted the most + users_with_the_most_reputation: Users with the highest reputation scores this week + users_with_the_most_vote: Users who voted the most this week staffs: Our community staff reputation: reputation votes: votes diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index a2fed086..314a01d6 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -979,13 +979,11 @@ ui: votes: 个点赞 answers: 个回答 accepted: 已被采纳 - page_404: - http_error: HTTP Error 404 - desc: "很抱歉,此页面不存在。" - back_home: 回到主页 - page_50X: - http_error: HTTP Error 500 - desc: 服务器遇到了一个错误,无法完成你的请求。 + page_error: + http_error: HTTP Error {{ code }} + desc_403: 你无权访问此页面。 + desc_404: 很抱歉,此页面不存在。 + desc_50X: 服务器遇到了一个错误,无法完成你的请求。 back_home: 回到主页 page_maintenance: desc: "我们正在进行维护,我们将很快回来。" @@ -1366,8 +1364,8 @@ ui: no_data: "空空如也" users: title: 用户 - users_with_the_most_reputation: 信誉积分最高的用户 - users_with_the_most_vote: 投票最多的用户 + users_with_the_most_reputation: 本周信誉积分最高的用户 + users_with_the_most_vote: 本周投票最多的用户 staffs: 我们的社区工作人员 reputation: 声望值 votes: 投票 diff --git a/i18n/zh_TW.yaml b/i18n/zh_TW.yaml index 58bb99b5..20bacfc4 100644 --- a/i18n/zh_TW.yaml +++ b/i18n/zh_TW.yaml @@ -977,13 +977,11 @@ ui: votes: 得票 answers: 回答 accepted: 已採納 - page_404: - http_error: HTTP Error 404 - desc: "很抱歉,此頁面不存在。" - back_home: 回到首頁 - page_50X: - http_error: HTTP Error 500 - desc: 伺服器遇到了一個錯誤,無法完成你的請求。 + page_error: + http_error: HTTP Error {{ code }} + desc_403: 你无权访问此頁面。 + desc_404: 很抱歉,此頁面不存在。 + desc_50X: 伺服器遇到了一個錯誤,無法完成你的請求。 back_home: 回到首頁 page_maintenance: desc: "我們正在維護中,很快就會回來。" diff --git a/ui/package.json b/ui/package.json index 8e72060b..57c2e634 100644 --- a/ui/package.json +++ b/ui/package.json @@ -22,9 +22,7 @@ "copy-to-clipboard": "^3.3.2", "dayjs": "^1.11.5", "diff": "^5.1.0", - "dompurify": "^2.4.3", "emoji-regex": "^10.2.1", - "html-react-parser": "^3.0.8", "i18next": "^21.9.0", "katex": "^0.16.2", "lodash": "^4.17.21", @@ -84,7 +82,7 @@ "react-app-rewired": "^2.2.1", "react-scripts": "5.0.1", "sass": "^1.54.4", - "typescript": "^4.8.3", + "typescript": "^4.9.5", "yaml-loader": "^0.8.0" }, "packageManager": "pnpm@7.9.5", diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index 569d1f00..743e1f6e 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -29,7 +29,6 @@ specifiers: customize-cra: ^1.0.0 dayjs: ^1.11.5 diff: ^5.1.0 - dompurify: ^2.4.3 emoji-regex: ^10.2.1 eslint: ^8.0.1 eslint-config-airbnb: ^19.0.4 @@ -43,7 +42,6 @@ specifiers: eslint-plugin-promise: ^6.0.0 eslint-plugin-react: ^7.30.1 eslint-plugin-react-hooks: ^4.6.0 - html-react-parser: ^3.0.8 husky: ^8.0.1 i18next: ^21.9.0 katex: ^0.16.2 @@ -68,14 +66,14 @@ specifiers: sass: ^1.54.4 semver: ^7.3.8 swr: ^1.3.0 - typescript: ^4.8.3 + typescript: ^4.9.5 urlcat: ^3.0.0 yaml-loader: ^0.8.0 zustand: ^4.1.1 dependencies: axios: 0.27.2 - bootstrap: 5.2.1_@popperjs+core@2.11.6 + bootstrap: 5.2.1_@popperjs+core@2.11.7 bootstrap-icons: 1.10.2 classnames: 2.3.2 codemirror: 5.65.0 @@ -83,9 +81,7 @@ dependencies: copy-to-clipboard: 3.3.2 dayjs: 1.11.5 diff: 5.1.0 - dompurify: registry.npmjs.org/dompurify/2.4.3 emoji-regex: 10.2.1 - html-react-parser: registry.npmjs.org/html-react-parser/3.0.8_react@18.2.0 i18next: 21.9.2 katex: 0.16.2 lodash: 4.17.21 @@ -122,14 +118,14 @@ devDependencies: '@types/qs': 6.9.7 '@types/react': 18.0.20 '@types/react-dom': 18.0.6 - '@typescript-eslint/eslint-plugin': 5.38.0_wsb62dxj2oqwgas4kadjymcmry - '@typescript-eslint/parser': 5.38.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/eslint-plugin': 5.38.0_j3kyhwzdxzxnwkyezapk4ib6dm + '@typescript-eslint/parser': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy customize-cra: 1.0.0 eslint: 8.23.1 eslint-config-airbnb: 19.0.4_4zstfqq5uopk5xuvotejlnl36y eslint-config-airbnb-typescript: 17.0.0_j57hrpt2hfp47otngkwtnuyxpa eslint-config-prettier: 8.5.0_eslint@8.23.1 - eslint-config-standard-with-typescript: 22.0.0_fsqc7gnfr7ufpr4slszrtm5abq + eslint-config-standard-with-typescript: 22.0.0_rgg5nvqzvmbqsu6p3s4ukwchpy eslint-plugin-import: 2.26.0_cxqatnnjiq7ozd2bkspxnuicdq eslint-plugin-jsx-a11y: 6.6.1_eslint@8.23.1 eslint-plugin-n: 15.2.5_eslint@8.23.1 @@ -141,11 +137,11 @@ devDependencies: lint-staged: 13.0.3 postcss: 8.4.16 prettier: 2.7.1 - purgecss-webpack-plugin: 4.1.3_webpack@5.75.0 + purgecss-webpack-plugin: 4.1.3_webpack@5.77.0 react-app-rewired: 2.2.1_react-scripts@5.0.1 - react-scripts: 5.0.1_mml7drqgt2b2zrp2ma74zmeoqy + react-scripts: 5.0.1_z72bcl2gkg6v3fmxqtnfgirxda sass: 1.54.9 - typescript: 4.8.3 + typescript: 4.9.5 yaml-loader: 0.8.0 packages: @@ -174,12 +170,18 @@ packages: dependencies: '@babel/highlight': 7.18.6 + /@babel/code-frame/7.21.4: + resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.18.6 + /@babel/compat-data/7.19.1: resolution: {integrity: sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==} engines: {node: '>=6.9.0'} - /@babel/compat-data/7.20.14: - resolution: {integrity: sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==} + /@babel/compat-data/7.21.4: + resolution: {integrity: sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==} engines: {node: '>=6.9.0'} /@babel/core/7.19.1: @@ -204,20 +206,20 @@ packages: transitivePeerDependencies: - supports-color - /@babel/core/7.20.12: - resolution: {integrity: sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==} + /@babel/core/7.21.4: + resolution: {integrity: sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.0 - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.14 - '@babel/helper-compilation-targets': 7.20.7_@babel+core@7.20.12 - '@babel/helper-module-transforms': 7.20.11 - '@babel/helpers': 7.20.13 - '@babel/parser': 7.20.15 + '@babel/code-frame': 7.21.4 + '@babel/generator': 7.21.4 + '@babel/helper-compilation-targets': 7.21.4_@babel+core@7.21.4 + '@babel/helper-module-transforms': 7.21.2 + '@babel/helpers': 7.21.0 + '@babel/parser': 7.21.4 '@babel/template': 7.20.7 - '@babel/traverse': 7.20.13 - '@babel/types': 7.20.7 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 convert-source-map: 1.9.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -247,12 +249,13 @@ packages: '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 - /@babel/generator/7.20.14: - resolution: {integrity: sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==} + /@babel/generator/7.21.4: + resolution: {integrity: sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.7 + '@babel/types': 7.21.4 '@jridgewell/gen-mapping': 0.3.2 + '@jridgewell/trace-mapping': 0.3.17 jsesc: 2.5.2 /@babel/helper-annotate-as-pure/7.18.6: @@ -280,15 +283,15 @@ packages: browserslist: 4.21.4 semver: 6.3.0 - /@babel/helper-compilation-targets/7.20.7_@babel+core@7.20.12: - resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==} + /@babel/helper-compilation-targets/7.21.4_@babel+core@7.21.4: + resolution: {integrity: sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.20.14 - '@babel/core': 7.20.12 - '@babel/helper-validator-option': 7.18.6 + '@babel/compat-data': 7.21.4 + '@babel/core': 7.21.4 + '@babel/helper-validator-option': 7.21.0 browserslist: 4.21.5 lru-cache: 5.1.1 semver: 6.3.0 @@ -352,6 +355,13 @@ packages: '@babel/template': 7.18.10 '@babel/types': 7.19.0 + /@babel/helper-function-name/7.21.0: + resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.20.7 + '@babel/types': 7.21.4 + /@babel/helper-hoist-variables/7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} @@ -370,6 +380,12 @@ packages: dependencies: '@babel/types': 7.19.0 + /@babel/helper-module-imports/7.21.4: + resolution: {integrity: sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.21.4 + /@babel/helper-module-transforms/7.19.0: resolution: {integrity: sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==} engines: {node: '>=6.9.0'} @@ -385,18 +401,18 @@ packages: transitivePeerDependencies: - supports-color - /@babel/helper-module-transforms/7.20.11: - resolution: {integrity: sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==} + /@babel/helper-module-transforms/7.21.2: + resolution: {integrity: sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-module-imports': 7.18.6 + '@babel/helper-module-imports': 7.21.4 '@babel/helper-simple-access': 7.20.2 '@babel/helper-split-export-declaration': 7.18.6 '@babel/helper-validator-identifier': 7.19.1 '@babel/template': 7.20.7 - '@babel/traverse': 7.20.13 - '@babel/types': 7.20.7 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 transitivePeerDependencies: - supports-color @@ -450,7 +466,7 @@ packages: resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.7 + '@babel/types': 7.21.4 /@babel/helper-skip-transparent-expression-wrappers/7.18.9: resolution: {integrity: sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==} @@ -480,6 +496,10 @@ packages: resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} engines: {node: '>=6.9.0'} + /@babel/helper-validator-option/7.21.0: + resolution: {integrity: sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==} + engines: {node: '>=6.9.0'} + /@babel/helper-wrap-function/7.19.0: resolution: {integrity: sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==} engines: {node: '>=6.9.0'} @@ -501,13 +521,13 @@ packages: transitivePeerDependencies: - supports-color - /@babel/helpers/7.20.13: - resolution: {integrity: sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==} + /@babel/helpers/7.21.0: + resolution: {integrity: sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.20.7 - '@babel/traverse': 7.20.13 - '@babel/types': 7.20.7 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 transitivePeerDependencies: - supports-color @@ -526,12 +546,12 @@ packages: dependencies: '@babel/types': 7.19.0 - /@babel/parser/7.20.15: - resolution: {integrity: sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==} + /@babel/parser/7.21.4: + resolution: {integrity: sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.20.7 + '@babel/types': 7.21.4 /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/7.18.6_@babel+core@7.19.1: resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} @@ -804,14 +824,14 @@ packages: '@babel/core': 7.19.1 '@babel/helper-plugin-utils': 7.19.0 - /@babel/plugin-syntax-flow/7.18.6_@babel+core@7.20.12: - resolution: {integrity: sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==} + /@babel/plugin-syntax-flow/7.21.4_@babel+core@7.21.4: + resolution: {integrity: sha512-l9xd3N+XG4fZRxEP3vXdK6RW7vN1Uf5dxzRC/09wV86wqZ/YYQooBIGNsiRdfNR3/q2/5pPzV4B54J/9ctX5jw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.12 - '@babel/helper-plugin-utils': 7.19.0 + '@babel/core': 7.21.4 + '@babel/helper-plugin-utils': 7.20.2 /@babel/plugin-syntax-import-assertions/7.18.6_@babel+core@7.19.1: resolution: {integrity: sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==} @@ -847,14 +867,14 @@ packages: '@babel/core': 7.19.1 '@babel/helper-plugin-utils': 7.19.0 - /@babel/plugin-syntax-jsx/7.18.6_@babel+core@7.20.12: - resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==} + /@babel/plugin-syntax-jsx/7.21.4_@babel+core@7.21.4: + resolution: {integrity: sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.12 - '@babel/helper-plugin-utils': 7.19.0 + '@babel/core': 7.21.4 + '@babel/helper-plugin-utils': 7.20.2 /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.19.1: resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} @@ -1228,18 +1248,18 @@ packages: '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.19.1 '@babel/types': 7.19.0 - /@babel/plugin-transform-react-jsx/7.20.13_@babel+core@7.20.12: - resolution: {integrity: sha512-MmTZx/bkUrfJhhYAYt3Urjm+h8DQGrPrnKQ94jLo7NLuOU+T89a7IByhKmrb8SKhrIYIQ0FN0CHMbnFRen4qNw==} + /@babel/plugin-transform-react-jsx/7.21.0_@babel+core@7.21.4: + resolution: {integrity: sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.12 + '@babel/core': 7.21.4 '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-module-imports': 7.18.6 + '@babel/helper-module-imports': 7.21.4 '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.20.12 - '@babel/types': 7.20.7 + '@babel/plugin-syntax-jsx': 7.21.4_@babel+core@7.21.4 + '@babel/types': 7.21.4 /@babel/plugin-transform-react-pure-annotations/7.18.6_@babel+core@7.19.1: resolution: {integrity: sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==} @@ -1513,9 +1533,9 @@ packages: resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.18.6 - '@babel/parser': 7.20.15 - '@babel/types': 7.20.7 + '@babel/code-frame': 7.21.4 + '@babel/parser': 7.21.4 + '@babel/types': 7.21.4 /@babel/traverse/7.19.1: resolution: {integrity: sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==} @@ -1534,18 +1554,18 @@ packages: transitivePeerDependencies: - supports-color - /@babel/traverse/7.20.13: - resolution: {integrity: sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==} + /@babel/traverse/7.21.4: + resolution: {integrity: sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.14 + '@babel/code-frame': 7.21.4 + '@babel/generator': 7.21.4 '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.19.0 + '@babel/helper-function-name': 7.21.0 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.20.15 - '@babel/types': 7.20.7 + '@babel/parser': 7.21.4 + '@babel/types': 7.21.4 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: @@ -1559,8 +1579,8 @@ packages: '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 - /@babel/types/7.20.7: - resolution: {integrity: sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==} + /@babel/types/7.21.4: + resolution: {integrity: sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.19.4 @@ -1659,11 +1679,11 @@ packages: '@types/node': 14.18.29 chalk: 4.1.2 cosmiconfig: 7.0.1 - cosmiconfig-typescript-loader: 4.1.0_3owiowz3ujipd4k6pbqn3n7oui + cosmiconfig-typescript-loader: 4.1.0_2uclxasecupgvdn72amnhmyg7y lodash: 4.17.21 resolve-from: 5.0.0 - ts-node: 10.9.1_ao52im6kiihokc7tdj7weudhra - typescript: 4.8.3 + ts-node: 10.9.1_5bkdw6noa5sa7givrguqy7ejvm + typescript: 4.9.5 transitivePeerDependencies: - '@swc/core' - '@swc/wasm' @@ -2208,6 +2228,12 @@ packages: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 + /@jridgewell/trace-mapping/0.3.17: + resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + /@jridgewell/trace-mapping/0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: @@ -2283,6 +2309,10 @@ packages: resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==} dev: false + /@popperjs/core/2.11.7: + resolution: {integrity: sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==} + dev: false + /@react-aria/ssr/3.3.0_react@18.2.0: resolution: {integrity: sha512-yNqUDuOVZIUGP81R87BJVi/ZUZp/nYOBXbPsRe7oltJOfErQZD+UezMpw4vM2KRz18cURffvmC8tJ6JTeyDtaQ==} peerDependencies: @@ -2821,7 +2851,7 @@ packages: dependencies: '@types/yargs-parser': 21.0.0 - /@typescript-eslint/eslint-plugin/5.38.0_wsb62dxj2oqwgas4kadjymcmry: + /@typescript-eslint/eslint-plugin/5.38.0_j3kyhwzdxzxnwkyezapk4ib6dm: resolution: {integrity: sha512-GgHi/GNuUbTOeoJiEANi0oI6fF3gBQc3bGFYj40nnAPCbhrtEDf2rjBmefFadweBmO1Du1YovHeDP2h5JLhtTQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -2832,33 +2862,33 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.38.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/parser': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy '@typescript-eslint/scope-manager': 5.38.0 - '@typescript-eslint/type-utils': 5.38.0_irgkl5vooow2ydyo6aokmferha - '@typescript-eslint/utils': 5.38.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/type-utils': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy + '@typescript-eslint/utils': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy debug: 4.3.4 eslint: 8.23.1 ignore: 5.2.0 regexpp: 3.2.0 semver: 7.3.8 - tsutils: 3.21.0_typescript@4.8.3 - typescript: 4.8.3 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 transitivePeerDependencies: - supports-color - /@typescript-eslint/experimental-utils/5.38.0_irgkl5vooow2ydyo6aokmferha: + /@typescript-eslint/experimental-utils/5.38.0_4dcepvmun56gjdctx7q2wwbdvy: resolution: {integrity: sha512-kzXBRfvGlicgGk4CYuRUqKvwc2s3wHXNssUWWJU18bhMRxriFm3BZWyQ6vEHBRpEIMKB6b7MIQHO+9lYlts19w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.38.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/utils': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy eslint: 8.23.1 transitivePeerDependencies: - supports-color - typescript - /@typescript-eslint/parser/5.38.0_irgkl5vooow2ydyo6aokmferha: + /@typescript-eslint/parser/5.38.0_4dcepvmun56gjdctx7q2wwbdvy: resolution: {integrity: sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -2870,10 +2900,10 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.38.0 '@typescript-eslint/types': 5.38.0 - '@typescript-eslint/typescript-estree': 5.38.0_typescript@4.8.3 + '@typescript-eslint/typescript-estree': 5.38.0_typescript@4.9.5 debug: 4.3.4 eslint: 8.23.1 - typescript: 4.8.3 + typescript: 4.9.5 transitivePeerDependencies: - supports-color @@ -2884,7 +2914,7 @@ packages: '@typescript-eslint/types': 5.38.0 '@typescript-eslint/visitor-keys': 5.38.0 - /@typescript-eslint/type-utils/5.38.0_irgkl5vooow2ydyo6aokmferha: + /@typescript-eslint/type-utils/5.38.0_4dcepvmun56gjdctx7q2wwbdvy: resolution: {integrity: sha512-iZq5USgybUcj/lfnbuelJ0j3K9dbs1I3RICAJY9NZZpDgBYXmuUlYQGzftpQA9wC8cKgtS6DASTvF3HrXwwozA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -2894,12 +2924,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.38.0_typescript@4.8.3 - '@typescript-eslint/utils': 5.38.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/typescript-estree': 5.38.0_typescript@4.9.5 + '@typescript-eslint/utils': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy debug: 4.3.4 eslint: 8.23.1 - tsutils: 3.21.0_typescript@4.8.3 - typescript: 4.8.3 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 transitivePeerDependencies: - supports-color @@ -2907,7 +2937,7 @@ packages: resolution: {integrity: sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - /@typescript-eslint/typescript-estree/5.38.0_typescript@4.8.3: + /@typescript-eslint/typescript-estree/5.38.0_typescript@4.9.5: resolution: {integrity: sha512-6P0RuphkR+UuV7Avv7MU3hFoWaGcrgOdi8eTe1NwhMp2/GjUJoODBTRWzlHpZh6lFOaPmSvgxGlROa0Sg5Zbyg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -2922,12 +2952,12 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.3.8 - tsutils: 3.21.0_typescript@4.8.3 - typescript: 4.8.3 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 transitivePeerDependencies: - supports-color - /@typescript-eslint/utils/5.38.0_irgkl5vooow2ydyo6aokmferha: + /@typescript-eslint/utils/5.38.0_4dcepvmun56gjdctx7q2wwbdvy: resolution: {integrity: sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -2936,7 +2966,7 @@ packages: '@types/json-schema': 7.0.11 '@typescript-eslint/scope-manager': 5.38.0 '@typescript-eslint/types': 5.38.0 - '@typescript-eslint/typescript-estree': 5.38.0_typescript@4.8.3 + '@typescript-eslint/typescript-estree': 5.38.0_typescript@4.9.5 eslint: 8.23.1 eslint-scope: 5.1.1 eslint-utils: 3.0.0_eslint@8.23.1 @@ -3606,12 +3636,12 @@ packages: resolution: {integrity: sha512-PTPYadRn1AMGr+QTSxe4ZCc+Wzv9DGZxbi3lNse/dajqV31n2/wl/7NX78ZpkvFgRNmH4ogdIQPQmxAfhEV6nA==} dev: false - /bootstrap/5.2.1_@popperjs+core@2.11.6: + /bootstrap/5.2.1_@popperjs+core@2.11.7: resolution: {integrity: sha512-UQi3v2NpVPEi1n35dmRRzBJFlgvWHYwyem6yHhuT6afYF+sziEt46McRbT//kVXZ7b1YUYEVGdXEH74Nx3xzGA==} peerDependencies: '@popperjs/core': ^2.11.6 dependencies: - '@popperjs/core': 2.11.6 + '@popperjs/core': 2.11.7 dev: false /brace-expansion/1.1.11: @@ -3649,8 +3679,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001452 - electron-to-chromium: 1.4.295 + caniuse-lite: 1.0.30001474 + electron-to-chromium: 1.4.350 node-releases: 2.0.10 update-browserslist-db: 1.0.10_browserslist@4.21.5 @@ -3728,8 +3758,8 @@ packages: /caniuse-lite/1.0.30001408: resolution: {integrity: sha512-DdUCktgMSM+1ndk9EFMZcavsGszV7zxV9O7MtOHniTa/iyAIwJCF0dFVBdU9SijJbfh29hC9bCs07wu8pjnGJQ==} - /caniuse-lite/1.0.30001452: - resolution: {integrity: sha512-Lkp0vFjMkBB3GTpLR8zk4NwW5EdRdnitwYJHDOOKIU85x4ckYCPQ+9WlVvSVClHxVReefkUMtWZH2l9KGlD51w==} + /caniuse-lite/1.0.30001474: + resolution: {integrity: sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q==} /case-sensitive-paths-webpack-plugin/2.4.0: resolution: {integrity: sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==} @@ -4037,7 +4067,7 @@ packages: /core-util-is/1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - /cosmiconfig-typescript-loader/4.1.0_3owiowz3ujipd4k6pbqn3n7oui: + /cosmiconfig-typescript-loader/4.1.0_2uclxasecupgvdn72amnhmyg7y: resolution: {integrity: sha512-HbWIuR5O+XO5Oj9SZ5bzgrD4nN+rfhrm2PMb0FVx+t+XIvC45n8F0oTNnztXtspWGw0i2IzHaUWFD5LzV1JB4A==} engines: {node: '>=12', npm: '>=6'} peerDependencies: @@ -4048,8 +4078,8 @@ packages: dependencies: '@types/node': 14.18.29 cosmiconfig: 7.0.1 - ts-node: 10.9.1_ao52im6kiihokc7tdj7weudhra - typescript: 4.8.3 + ts-node: 10.9.1_5bkdw6noa5sa7givrguqy7ejvm + typescript: 4.9.5 dev: true /cosmiconfig/6.0.0: @@ -5066,8 +5096,8 @@ packages: /electron-to-chromium/1.4.256: resolution: {integrity: sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw==} - /electron-to-chromium/1.4.295: - resolution: {integrity: sha512-lEO94zqf1bDA3aepxwnWoHUjA8sZ+2owgcSZjYQy0+uOSEclJX0VieZC+r+wLpSxUHRd6gG32znTWmr+5iGzFw==} + /electron-to-chromium/1.4.350: + resolution: {integrity: sha512-XnXcWpVnOfHZ4C3NPiL+SubeoGV8zc/pg8GEubRtc1dPA/9jKS2vsOPmtClJHhWxUb2RSGC1OBLCbgNUJMtZPw==} /emittery/0.10.2: resolution: {integrity: sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==} @@ -5106,7 +5136,7 @@ packages: resolution: {integrity: sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==} engines: {node: '>=10.13.0'} dependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 tapable: 2.2.1 dev: true @@ -5221,8 +5251,8 @@ packages: eslint: ^7.32.0 || ^8.2.0 eslint-plugin-import: ^2.25.3 dependencies: - '@typescript-eslint/eslint-plugin': 5.38.0_wsb62dxj2oqwgas4kadjymcmry - '@typescript-eslint/parser': 5.38.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/eslint-plugin': 5.38.0_j3kyhwzdxzxnwkyezapk4ib6dm + '@typescript-eslint/parser': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy eslint: 8.23.1 eslint-config-airbnb-base: 15.0.0_hdzsmr7kawaomymueo2tso6fjq eslint-plugin-import: 2.26.0_cxqatnnjiq7ozd2bkspxnuicdq @@ -5257,7 +5287,7 @@ packages: eslint: 8.23.1 dev: true - /eslint-config-react-app/7.0.1_n6qatnnbpoccspltxi3idzpmam: + /eslint-config-react-app/7.0.1_3wjbtgciw64wc2xmhxyprqr3jm: resolution: {integrity: sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -5270,19 +5300,19 @@ packages: '@babel/core': 7.19.1 '@babel/eslint-parser': 7.19.1_zdglor7vg7osicr5spasq6cc5a '@rushstack/eslint-patch': 1.2.0 - '@typescript-eslint/eslint-plugin': 5.38.0_wsb62dxj2oqwgas4kadjymcmry - '@typescript-eslint/parser': 5.38.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/eslint-plugin': 5.38.0_j3kyhwzdxzxnwkyezapk4ib6dm + '@typescript-eslint/parser': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy babel-preset-react-app: 10.0.1 confusing-browser-globals: 1.0.11 eslint: 8.23.1 - eslint-plugin-flowtype: 8.0.3_kpcs5p4zm4a4w6zxhbzwfayc7m + eslint-plugin-flowtype: 8.0.3_is75u4gug36f5e4hn2ov7dma7i eslint-plugin-import: 2.26.0_cxqatnnjiq7ozd2bkspxnuicdq - eslint-plugin-jest: 25.7.0_hpujes4m5fznz335nz2hgbshme + eslint-plugin-jest: 25.7.0_ysljusnkykxn4g7zog7cbtn2c4 eslint-plugin-jsx-a11y: 6.6.1_eslint@8.23.1 eslint-plugin-react: 7.31.8_eslint@8.23.1 eslint-plugin-react-hooks: 4.6.0_eslint@8.23.1 - eslint-plugin-testing-library: 5.6.4_irgkl5vooow2ydyo6aokmferha - typescript: 4.8.3 + eslint-plugin-testing-library: 5.6.4_4dcepvmun56gjdctx7q2wwbdvy + typescript: 4.9.5 transitivePeerDependencies: - '@babel/plugin-syntax-flow' - '@babel/plugin-transform-react-jsx' @@ -5291,7 +5321,7 @@ packages: - jest - supports-color - /eslint-config-standard-with-typescript/22.0.0_fsqc7gnfr7ufpr4slszrtm5abq: + /eslint-config-standard-with-typescript/22.0.0_rgg5nvqzvmbqsu6p3s4ukwchpy: resolution: {integrity: sha512-VA36U7UlFpwULvkdnh6MQj5GAV2Q+tT68ALLAwJP0ZuNXU2m0wX07uxX4qyLRdHgSzH4QJ73CveKBuSOYvh7vQ==} peerDependencies: '@typescript-eslint/eslint-plugin': ^5.0.0 @@ -5301,14 +5331,14 @@ packages: eslint-plugin-promise: ^6.0.0 typescript: '*' dependencies: - '@typescript-eslint/eslint-plugin': 5.38.0_wsb62dxj2oqwgas4kadjymcmry - '@typescript-eslint/parser': 5.38.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/eslint-plugin': 5.38.0_j3kyhwzdxzxnwkyezapk4ib6dm + '@typescript-eslint/parser': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy eslint: 8.23.1 eslint-config-standard: 17.0.0_4nulviyjkaspo7v2xlghuwxbf4 eslint-plugin-import: 2.26.0_cxqatnnjiq7ozd2bkspxnuicdq eslint-plugin-n: 15.2.5_eslint@8.23.1 eslint-plugin-promise: 6.0.1_eslint@8.23.1 - typescript: 4.8.3 + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true @@ -5356,7 +5386,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.38.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/parser': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy debug: 3.2.7 eslint: 8.23.1 eslint-import-resolver-node: 0.3.6 @@ -5374,7 +5404,7 @@ packages: regexpp: 3.2.0 dev: true - /eslint-plugin-flowtype/8.0.3_kpcs5p4zm4a4w6zxhbzwfayc7m: + /eslint-plugin-flowtype/8.0.3_is75u4gug36f5e4hn2ov7dma7i: resolution: {integrity: sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==} engines: {node: '>=12.0.0'} peerDependencies: @@ -5382,8 +5412,8 @@ packages: '@babel/plugin-transform-react-jsx': ^7.14.9 eslint: ^8.1.0 dependencies: - '@babel/plugin-syntax-flow': 7.18.6_@babel+core@7.20.12 - '@babel/plugin-transform-react-jsx': 7.20.13_@babel+core@7.20.12 + '@babel/plugin-syntax-flow': 7.21.4_@babel+core@7.21.4 + '@babel/plugin-transform-react-jsx': 7.21.0_@babel+core@7.21.4 eslint: 8.23.1 lodash: 4.17.21 string-natural-compare: 3.0.1 @@ -5398,7 +5428,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.38.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/parser': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy array-includes: 3.1.5 array.prototype.flat: 1.3.0 debug: 2.6.9 @@ -5418,7 +5448,7 @@ packages: - eslint-import-resolver-webpack - supports-color - /eslint-plugin-jest/25.7.0_hpujes4m5fznz335nz2hgbshme: + /eslint-plugin-jest/25.7.0_ysljusnkykxn4g7zog7cbtn2c4: resolution: {integrity: sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} peerDependencies: @@ -5431,8 +5461,8 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 5.38.0_wsb62dxj2oqwgas4kadjymcmry - '@typescript-eslint/experimental-utils': 5.38.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/eslint-plugin': 5.38.0_j3kyhwzdxzxnwkyezapk4ib6dm + '@typescript-eslint/experimental-utils': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy eslint: 8.23.1 jest: 27.5.1_ts-node@10.9.1 transitivePeerDependencies: @@ -5533,13 +5563,13 @@ packages: semver: 6.3.0 string.prototype.matchall: 4.0.7 - /eslint-plugin-testing-library/5.6.4_irgkl5vooow2ydyo6aokmferha: + /eslint-plugin-testing-library/5.6.4_4dcepvmun56gjdctx7q2wwbdvy: resolution: {integrity: sha512-0oW3tC5NNT2WexmJ3848a/utawOymw4ibl3/NkwywndVAz2hT9+ab70imA7ccg3RaScQgMvJT60OL00hpmJvrg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6'} peerDependencies: eslint: ^7.5.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.38.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/utils': 5.38.0_4dcepvmun56gjdctx7q2wwbdvy eslint: 8.23.1 transitivePeerDependencies: - supports-color @@ -5912,7 +5942,7 @@ packages: debug: optional: true - /fork-ts-checker-webpack-plugin/6.5.2_npfwkgbcmgrbevrxnqgustqabe: + /fork-ts-checker-webpack-plugin/6.5.2_h33pxmj7ihkiaxhnzwyj3mdwbi: resolution: {integrity: sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==} engines: {node: '>=10', yarn: '>=1.0.0'} peerDependencies: @@ -5940,7 +5970,7 @@ packages: schema-utils: 2.7.0 semver: 7.3.8 tapable: 1.1.3 - typescript: 4.8.3 + typescript: 4.9.5 webpack: 5.74.0 /form-data/3.0.1: @@ -6131,6 +6161,10 @@ packages: /graceful-fs/4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + /graceful-fs/4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true + /grapheme-splitter/1.0.4: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} @@ -6787,7 +6821,7 @@ packages: pretty-format: 27.5.1 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.1_ao52im6kiihokc7tdj7weudhra + ts-node: 10.9.1_5bkdw6noa5sa7givrguqy7ejvm transitivePeerDependencies: - bufferutil - canvas @@ -7787,7 +7821,7 @@ packages: jsonp: 0.2.1 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - react-scripts: 5.0.1_mml7drqgt2b2zrp2ma74zmeoqy + react-scripts: 5.0.1_z72bcl2gkg6v3fmxqtnfgirxda transitivePeerDependencies: - supports-color dev: false @@ -8417,7 +8451,7 @@ packages: dependencies: lilconfig: 2.0.6 postcss: 8.4.16 - ts-node: 10.9.1_ao52im6kiihokc7tdj7weudhra + ts-node: 10.9.1_5bkdw6noa5sa7givrguqy7ejvm yaml: 1.10.2 /postcss-loader/6.2.1_qjv4cptcpse3y5hrjkrbb7drda: @@ -8950,13 +8984,13 @@ packages: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} - /purgecss-webpack-plugin/4.1.3_webpack@5.75.0: + /purgecss-webpack-plugin/4.1.3_webpack@5.77.0: resolution: {integrity: sha512-1OHS0WE935w66FjaFSlV06ycmn3/A8a6Q+iVUmmCYAujQ1HPdX+psMXUhASEW0uF1PYEpOlhMc5ApigVqYK08g==} peerDependencies: webpack: '*' dependencies: purgecss: 4.1.3 - webpack: 5.75.0 + webpack: 5.77.0 webpack-sources: 3.2.3 dev: true @@ -9042,7 +9076,7 @@ packages: peerDependencies: react-scripts: '>=2.1.3' dependencies: - react-scripts: 5.0.1_mml7drqgt2b2zrp2ma74zmeoqy + react-scripts: 5.0.1_z72bcl2gkg6v3fmxqtnfgirxda semver: 5.7.1 dev: true @@ -9073,7 +9107,7 @@ packages: warning: 4.0.3 dev: false - /react-dev-utils/12.0.1_npfwkgbcmgrbevrxnqgustqabe: + /react-dev-utils/12.0.1_h33pxmj7ihkiaxhnzwyj3mdwbi: resolution: {integrity: sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==} engines: {node: '>=14'} peerDependencies: @@ -9092,7 +9126,7 @@ packages: escape-string-regexp: 4.0.0 filesize: 8.0.7 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.2_npfwkgbcmgrbevrxnqgustqabe + fork-ts-checker-webpack-plugin: 6.5.2_h33pxmj7ihkiaxhnzwyj3mdwbi global-modules: 2.0.0 globby: 11.1.0 gzip-size: 6.0.0 @@ -9107,7 +9141,7 @@ packages: shell-quote: 1.7.3 strip-ansi: 6.0.1 text-table: 0.2.0 - typescript: 4.8.3 + typescript: 4.9.5 webpack: 5.74.0 transitivePeerDependencies: - eslint @@ -9205,7 +9239,7 @@ packages: react: 18.2.0 dev: false - /react-scripts/5.0.1_mml7drqgt2b2zrp2ma74zmeoqy: + /react-scripts/5.0.1_z72bcl2gkg6v3fmxqtnfgirxda: resolution: {integrity: sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==} engines: {node: '>=14.0.0'} hasBin: true @@ -9233,7 +9267,7 @@ packages: dotenv: 10.0.0 dotenv-expand: 5.1.0 eslint: 8.23.1 - eslint-config-react-app: 7.0.1_n6qatnnbpoccspltxi3idzpmam + eslint-config-react-app: 7.0.1_3wjbtgciw64wc2xmhxyprqr3jm eslint-webpack-plugin: 3.2.0_cnsurwdbw57xgwxuf5k544xt5e file-loader: 6.2.0_webpack@5.74.0 fs-extra: 10.1.0 @@ -9251,7 +9285,7 @@ packages: prompts: 2.4.2 react: 18.2.0 react-app-polyfill: 3.0.0 - react-dev-utils: 12.0.1_npfwkgbcmgrbevrxnqgustqabe + react-dev-utils: 12.0.1_h33pxmj7ihkiaxhnzwyj3mdwbi react-refresh: 0.11.0 resolve: 1.22.1 resolve-url-loader: 4.0.0 @@ -9261,7 +9295,7 @@ packages: style-loader: 3.3.1_webpack@5.74.0 tailwindcss: 3.1.8_57znarxsqwmnneadci5z5fd5gu terser-webpack-plugin: 5.3.6_webpack@5.74.0 - typescript: 4.8.3 + typescript: 4.9.5 webpack: 5.74.0 webpack-dev-server: 4.11.1_webpack@5.74.0 webpack-manifest-plugin: 4.1.1_webpack@5.74.0 @@ -9742,6 +9776,12 @@ packages: dependencies: randombytes: 2.1.0 + /serialize-javascript/6.0.1: + resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==} + dependencies: + randombytes: 2.1.0 + dev: true + /serve-index/1.9.1: resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} engines: {node: '>= 0.8.0'} @@ -10291,8 +10331,8 @@ packages: terser: 5.15.0 webpack: 5.74.0 - /terser-webpack-plugin/5.3.6_webpack@5.75.0: - resolution: {integrity: sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==} + /terser-webpack-plugin/5.3.7_webpack@5.77.0: + resolution: {integrity: sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==} engines: {node: '>= 10.13.0'} peerDependencies: '@swc/core': '*' @@ -10307,12 +10347,12 @@ packages: uglify-js: optional: true dependencies: - '@jridgewell/trace-mapping': 0.3.15 + '@jridgewell/trace-mapping': 0.3.17 jest-worker: 27.5.1 schema-utils: 3.1.1 - serialize-javascript: 6.0.0 - terser: 5.15.0 - webpack: 5.75.0 + serialize-javascript: 6.0.1 + terser: 5.16.8 + webpack: 5.77.0 dev: true /terser/5.15.0: @@ -10325,6 +10365,17 @@ packages: commander: 2.20.3 source-map-support: 0.5.21 + /terser/5.16.8: + resolution: {integrity: sha512-QI5g1E/ef7d+PsDifb+a6nnVgC4F22Bg6T0xrBrz6iloVB4PUkkunp6V8nzoOOZJIzjWVdAGqCdlKlhLq/TbIA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.2 + acorn: 8.8.2 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: true + /test-exclude/6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} @@ -10406,7 +10457,7 @@ packages: /tryer/1.0.1: resolution: {integrity: sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==} - /ts-node/10.9.1_ao52im6kiihokc7tdj7weudhra: + /ts-node/10.9.1_5bkdw6noa5sa7givrguqy7ejvm: resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -10432,7 +10483,7 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.8.3 + typescript: 4.9.5 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 @@ -10450,14 +10501,14 @@ packages: /tslib/2.4.0: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} - /tsutils/3.21.0_typescript@4.8.3: + /tsutils/3.21.0_typescript@4.9.5: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.8.3 + typescript: 4.9.5 /type-check/0.3.2: resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} @@ -10514,8 +10565,8 @@ packages: dependencies: is-typedarray: 1.0.0 - /typescript/4.8.3: - resolution: {integrity: sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==} + /typescript/4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} engines: {node: '>=4.2.0'} hasBin: true @@ -10853,8 +10904,8 @@ packages: - esbuild - uglify-js - /webpack/5.75.0: - resolution: {integrity: sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==} + /webpack/5.77.0: + resolution: {integrity: sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -10877,14 +10928,14 @@ packages: eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 json-parse-even-better-errors: 2.3.1 loader-runner: 4.3.0 mime-types: 2.1.35 neo-async: 2.6.2 schema-utils: 3.1.1 tapable: 2.2.1 - terser-webpack-plugin: 5.3.6_webpack@5.75.0 + terser-webpack-plugin: 5.3.7_webpack@5.77.0 watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -11303,16 +11354,6 @@ packages: domhandler: registry.npmjs.org/domhandler/4.3.1 entities: registry.npmjs.org/entities/2.2.0 - registry.npmjs.org/dom-serializer/2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz} - name: dom-serializer - version: 2.0.0 - dependencies: - domelementtype: registry.npmjs.org/domelementtype/2.3.0 - domhandler: registry.npmjs.org/domhandler/5.0.3 - entities: registry.npmjs.org/entities/4.4.0 - dev: false - registry.npmjs.org/domelementtype/1.3.1: resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz} name: domelementtype @@ -11331,27 +11372,12 @@ packages: dependencies: domelementtype: registry.npmjs.org/domelementtype/2.3.0 - registry.npmjs.org/domhandler/5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz} - name: domhandler - version: 5.0.3 - engines: {node: '>= 4'} - dependencies: - domelementtype: registry.npmjs.org/domelementtype/2.3.0 - dev: false - registry.npmjs.org/dompurify/2.4.0: resolution: {integrity: sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/dompurify/-/dompurify-2.4.0.tgz} name: dompurify version: 2.4.0 dev: false - registry.npmjs.org/dompurify/2.4.3: - resolution: {integrity: sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz} - name: dompurify - version: 2.4.3 - dev: false - registry.npmjs.org/domutils/1.7.0: resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz} name: domutils @@ -11369,52 +11395,11 @@ packages: domelementtype: registry.npmjs.org/domelementtype/2.3.0 domhandler: registry.npmjs.org/domhandler/4.3.1 - registry.npmjs.org/domutils/3.0.1: - resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz} - name: domutils - version: 3.0.1 - dependencies: - dom-serializer: registry.npmjs.org/dom-serializer/2.0.0 - domelementtype: registry.npmjs.org/domelementtype/2.3.0 - domhandler: registry.npmjs.org/domhandler/5.0.3 - dev: false - registry.npmjs.org/entities/2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/entities/-/entities-2.2.0.tgz} name: entities version: 2.2.0 - registry.npmjs.org/entities/4.4.0: - resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/entities/-/entities-4.4.0.tgz} - name: entities - version: 4.4.0 - engines: {node: '>=0.12'} - dev: false - - registry.npmjs.org/html-dom-parser/3.1.3: - resolution: {integrity: sha512-fI0yyNlIeSboxU+jnrA4v8qj4+M8SI9/q6AKYdwCY2qki22UtKCDTxvagHniECu7sa5/o2zFRdLleA67035lsA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/html-dom-parser/-/html-dom-parser-3.1.3.tgz} - name: html-dom-parser - version: 3.1.3 - dependencies: - domhandler: registry.npmjs.org/domhandler/5.0.3 - htmlparser2: registry.npmjs.org/htmlparser2/8.0.1 - dev: false - - registry.npmjs.org/html-react-parser/3.0.8_react@18.2.0: - resolution: {integrity: sha512-eIxPq/3Ja3+nZkx6X/BNpFy0lNuW+v3V4nzABzuL8KkRVdYY/2KyXO42epKonsEVVRSBxm2zsxWcOkT6fYL+iQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/html-react-parser/-/html-react-parser-3.0.8.tgz} - id: registry.npmjs.org/html-react-parser/3.0.8 - name: html-react-parser - version: 3.0.8 - peerDependencies: - react: 0.14 || 15 || 16 || 17 || 18 - dependencies: - domhandler: registry.npmjs.org/domhandler/5.0.3 - html-dom-parser: registry.npmjs.org/html-dom-parser/3.1.3 - react: 18.2.0 - react-property: registry.npmjs.org/react-property/2.0.0 - style-to-js: registry.npmjs.org/style-to-js/1.1.3 - dev: false - registry.npmjs.org/htmlparser2/6.1.0: resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz} name: htmlparser2 @@ -11424,42 +11409,3 @@ packages: domhandler: registry.npmjs.org/domhandler/4.3.1 domutils: registry.npmjs.org/domutils/2.8.0 entities: registry.npmjs.org/entities/2.2.0 - - registry.npmjs.org/htmlparser2/8.0.1: - resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz} - name: htmlparser2 - version: 8.0.1 - dependencies: - domelementtype: registry.npmjs.org/domelementtype/2.3.0 - domhandler: registry.npmjs.org/domhandler/5.0.3 - domutils: registry.npmjs.org/domutils/3.0.1 - entities: registry.npmjs.org/entities/4.4.0 - dev: false - - registry.npmjs.org/inline-style-parser/0.1.1: - resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz} - name: inline-style-parser - version: 0.1.1 - dev: false - - registry.npmjs.org/react-property/2.0.0: - resolution: {integrity: sha512-kzmNjIgU32mO4mmH5+iUyrqlpFQhF8K2k7eZ4fdLSOPFrD1XgEuSBv9LDEgxRXTMBqMd8ppT0x6TIzqE5pdGdw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/react-property/-/react-property-2.0.0.tgz} - name: react-property - version: 2.0.0 - dev: false - - registry.npmjs.org/style-to-js/1.1.3: - resolution: {integrity: sha512-zKI5gN/zb7LS/Vm0eUwjmjrXWw8IMtyA8aPBJZdYiQTXj4+wQ3IucOLIOnF7zCHxvW8UhIGh/uZh/t9zEHXNTQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.3.tgz} - name: style-to-js - version: 1.1.3 - dependencies: - style-to-object: registry.npmjs.org/style-to-object/0.4.1 - dev: false - - registry.npmjs.org/style-to-object/0.4.1: - resolution: {integrity: sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.1.tgz} - name: style-to-object - version: 0.4.1 - dependencies: - inline-style-parser: registry.npmjs.org/inline-style-parser/0.1.1 - dev: false diff --git a/ui/public/index.html b/ui/public/index.html index 3e1eddd8..cb72d38a 100644 --- a/ui/public/index.html +++ b/ui/public/index.html @@ -86,6 +86,9 @@ { name: 'Safari', version: '15' + }, + { + name: 'IE', } ]; function getBrowerTypeAndVersion(){ @@ -95,6 +98,7 @@ }; var ua = navigator.userAgent.toLowerCase(); var s; + ((ua.indexOf("compatible") > -1 && ua.indexOf("MSIE") > -1) || (ua.indexOf('Trident') > -1 && ua.indexOf("rv:11.0") > -1)) ? brower = { name: 'IE', version: '' } : (s = ua.match(/edge\/([\d\.]+)/)) ? brower = { name: 'Edge', version: s[1] } : (s = ua.match(/firefox\/([\d\.]+)/)) ? brower = { name: 'Firefox', version: s[1] } : (s = ua.match(/chrome\/([\d\.]+)/)) ? brower = { name: 'Chrome', version: s[1] } : @@ -126,16 +130,24 @@ } const browerInfo = getBrowerTypeAndVersion(); - const notSupport = defaultList.some(item => { - if (item.name === browerInfo.name) { - return compareVersion(browerInfo.version, item.version) === -1; - } - return false; - }); - if (notSupport) { + + if (browerInfo.name === 'IE') { const div = document.getElementById('protect-brower'); - div.innerText = 'The current browser version is too low, in order not to affect the normal use of the function, please upgrade the browser to the latest version.' + div.innerText = 'Sorry, this site does not support Internet Explorer. In order to avoid affecting the normal use of our features, please use a more modern browser such as Edge, Firefox, Chrome, or Safari.' + } else { + const notSupport = defaultList.some(item => { + if (item.name === browerInfo.name) { + return compareVersion(browerInfo.version, item.version) === -1; + } + return false; + }); + if (notSupport) { + const div = document.getElementById('protect-brower'); + div.innerText = 'The current browser version is too low, in order not to affect the normal use of the function, please upgrade the browser to the latest version.' + } } + + diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts index d352573b..84728efe 100644 --- a/ui/src/common/interface.ts +++ b/ui/src/common/interface.ts @@ -58,10 +58,13 @@ export interface QuestionParams { title: string; url_title?: string; content: string; - html?: string; tags: Tag[]; } +export interface QuestionWithAnswer extends QuestionParams { + answer_content: string; +} + export interface ListResult { count: number; list: T[]; diff --git a/ui/src/components/Actions/index.tsx b/ui/src/components/Actions/index.tsx index 8ba6a1d4..268ff9d1 100644 --- a/ui/src/components/Actions/index.tsx +++ b/ui/src/components/Actions/index.tsx @@ -12,6 +12,7 @@ import { bookmark, postVote } from '@/services'; interface Props { className?: string; + source: 'question' | 'answer'; data: { id: string; votesCount: number; @@ -24,7 +25,7 @@ interface Props { }; } -const Index: FC = ({ className, data }) => { +const Index: FC = ({ className, data, source }) => { const [votes, setVotes] = useState(0); const [like, setLike] = useState(false); const [hate, setHated] = useState(false); @@ -102,6 +103,11 @@ const Index: FC = ({ className, data }) => {
-
- - ); -}; - -export default Index; diff --git a/ui/src/pages/404/index.tsx b/ui/src/pages/404/index.tsx new file mode 100644 index 00000000..e6d800ab --- /dev/null +++ b/ui/src/pages/404/index.tsx @@ -0,0 +1,7 @@ +import { HttpErrorContent } from '@/components'; + +const Index = () => { + return ; +}; + +export default Index; diff --git a/ui/src/pages/50X/index.jsx b/ui/src/pages/50X/index.jsx deleted file mode 100644 index 33a8a693..00000000 --- a/ui/src/pages/50X/index.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import { useEffect } from 'react'; -import { Container, Button } from 'react-bootstrap'; -import { Link } from 'react-router-dom'; -import { useTranslation } from 'react-i18next'; - -// eslint-disable-next-line import/no-unresolved -import { usePageTags } from '@/hooks'; - -const Index = () => { - const { t } = useTranslation('translation', { keyPrefix: 'page_50X' }); - useEffect(() => { - // auto height of container - const pageWrap = document.querySelector('.page-wrap'); - pageWrap.style.display = 'contents'; - - return () => { - pageWrap.style.display = 'block'; - }; - }, []); - - usePageTags({ - title: t('http_50X', { keyPrefix: 'page_title' }), - }); - return ( - -
- (=T^T=) -
- -

{t('http_error')}

-
{t('desc')}
-
- -
-
- ); -}; - -export default Index; diff --git a/ui/src/pages/50X/index.tsx b/ui/src/pages/50X/index.tsx new file mode 100644 index 00000000..0dcc49f9 --- /dev/null +++ b/ui/src/pages/50X/index.tsx @@ -0,0 +1,7 @@ +import { HttpErrorContent } from '@/components'; + +const Index = () => { + return ; +}; + +export default Index; diff --git a/ui/src/pages/Admin/Answers/index.tsx b/ui/src/pages/Admin/Answers/index.tsx index cf53e269..39a7946f 100644 --- a/ui/src/pages/Admin/Answers/index.tsx +++ b/ui/src/pages/Admin/Answers/index.tsx @@ -58,7 +58,7 @@ const Answers: FC = () => { content: item.accepted === 2 ? t('answer_accepted', { keyPrefix: 'delete' }) - : `

${t('other', { keyPrefix: 'delete' })}

`, + : t('other', { keyPrefix: 'delete' }), cancelBtnVariant: 'link', confirmBtnVariant: 'danger', confirmText: t('delete', { keyPrefix: 'btns' }), diff --git a/ui/src/pages/Admin/Questions/index.tsx b/ui/src/pages/Admin/Questions/index.tsx index 124fd307..d11043b2 100644 --- a/ui/src/pages/Admin/Questions/index.tsx +++ b/ui/src/pages/Admin/Questions/index.tsx @@ -67,8 +67,8 @@ const Questions: FC = () => { title: t('title', { keyPrefix: 'delete' }), content: item.answer_count > 0 - ? `

${t('question', { keyPrefix: 'delete' })}

` - : `

${t('other', { keyPrefix: 'delete' })}

`, + ? t('question', { keyPrefix: 'delete' }) + : t('other', { keyPrefix: 'delete' }), cancelBtnVariant: 'link', confirmBtnVariant: 'danger', confirmText: t('delete', { keyPrefix: 'btns' }), diff --git a/ui/src/pages/Admin/Seo/index.tsx b/ui/src/pages/Admin/Seo/index.tsx index ffabb59b..6c979dc0 100644 --- a/ui/src/pages/Admin/Seo/index.tsx +++ b/ui/src/pages/Admin/Seo/index.tsx @@ -19,14 +19,14 @@ const Index: FC = () => { type: 'number', title: t('permalink.label'), description: t('permalink.text'), - enum: [1, 2, 3, 4], + enum: [4, 3, 2, 1], enumNames: [ - '/questions/10010000000000001/post-title', - '/questions/10010000000000001', - '/questions/D1D1/post-title', '/questions/D1D1', + '/questions/D1D1/post-title', + '/questions/10010000000000001', + '/questions/10010000000000001/post-title', ], - default: 1, + default: 4, }, robots: { type: 'string', diff --git a/ui/src/pages/Layout/index.tsx b/ui/src/pages/Layout/index.tsx index a09bf113..97a682f2 100644 --- a/ui/src/pages/Layout/index.tsx +++ b/ui/src/pages/Layout/index.tsx @@ -4,7 +4,7 @@ import { HelmetProvider } from 'react-helmet-async'; import { SWRConfig } from 'swr'; -import { toastStore, loginToContinueStore, errorCode } from '@/stores'; +import { toastStore, loginToContinueStore, errorCodeStore } from '@/stores'; import { Header, Footer, @@ -12,11 +12,10 @@ import { Customize, CustomizeTheme, PageTags, + HttpErrorContent, } from '@/components'; import { LoginToContinueModal } from '@/components/Modal'; import { useImgViewer } from '@/hooks'; -import Component404 from '@/pages/404'; -import Component50X from '@/pages/50X'; const Layout: FC = () => { const location = useLocation(); @@ -24,8 +23,7 @@ const Layout: FC = () => { const closeToast = () => { toastClear(); }; - const { code: httpStatusCode, reset: httpStatusReset } = errorCode(); - + const { code: httpStatusCode, reset: httpStatusReset } = errorCodeStore(); const imgViewer = useImgViewer(); const { show: showLoginToContinueModal } = loginToContinueStore(); @@ -45,10 +43,8 @@ const Layout: FC = () => {
- {httpStatusCode === '404' ? ( - - ) : httpStatusCode === '50X' ? ( - + {httpStatusCode ? ( + ) : ( )} diff --git a/ui/src/pages/Legal/Privacy/index.tsx b/ui/src/pages/Legal/Privacy/index.tsx index f8fc2ace..3cd251a6 100644 --- a/ui/src/pages/Legal/Privacy/index.tsx +++ b/ui/src/pages/Legal/Privacy/index.tsx @@ -1,8 +1,9 @@ -import { FC } from 'react'; +import { FC, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { usePageTags } from '@/hooks'; import { useLegalPrivacy } from '@/services'; +import { htmlRender } from '@/components'; const Index: FC = () => { const { t } = useTranslation('translation', { keyPrefix: 'nav_menus' }); @@ -12,6 +13,15 @@ const Index: FC = () => { const { data: privacy } = useLegalPrivacy(); const contentText = privacy?.privacy_policy_original_text; let matchUrl: URL | undefined; + + useEffect(() => { + const fmt = document.querySelector('.fmt') as HTMLElement; + if (!fmt) { + return; + } + htmlRender(fmt); + }, [privacy?.privacy_policy_parsed_text]); + try { if (contentText) { matchUrl = new URL(contentText); diff --git a/ui/src/pages/Legal/Tos/index.tsx b/ui/src/pages/Legal/Tos/index.tsx index bbac2b50..32aeb11d 100644 --- a/ui/src/pages/Legal/Tos/index.tsx +++ b/ui/src/pages/Legal/Tos/index.tsx @@ -1,8 +1,9 @@ -import { FC } from 'react'; +import { FC, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { usePageTags } from '@/hooks'; import { useLegalTos } from '@/services'; +import { htmlRender } from '@/components'; const Index: FC = () => { const { t } = useTranslation('translation', { keyPrefix: 'nav_menus' }); @@ -12,6 +13,15 @@ const Index: FC = () => { const { data: tos } = useLegalTos(); const contentText = tos?.terms_of_service_original_text; let matchUrl: URL | undefined; + + useEffect(() => { + const fmt = document.querySelector('.fmt') as HTMLElement; + if (!fmt) { + return; + } + htmlRender(fmt); + }, [tos?.terms_of_service_parsed_text]); + try { if (contentText) { matchUrl = new URL(contentText); @@ -22,8 +32,9 @@ const Index: FC = () => { window.location.replace(matchUrl.toString()); return null; } + return ( - <> +

{t('tos')}

{ __html: tos?.terms_of_service_parsed_text || '', }} /> - +
); }; diff --git a/ui/src/pages/Questions/Ask/index.tsx b/ui/src/pages/Questions/Ask/index.tsx index 533b59f7..8d580da0 100644 --- a/ui/src/pages/Questions/Ask/index.tsx +++ b/ui/src/pages/Questions/Ask/index.tsx @@ -16,9 +16,10 @@ import { questionDetail, modifyQuestion, useQueryRevisions, - postAnswer, + // postAnswer, useQueryQuestionByTitle, getTagsBySlugName, + saveQuestionWidthAnaser, } from '@/services'; import { handleFormError, SaveDraft, storageExpires } from '@/utils'; import { pathFactory } from '@/router/pathFactory'; @@ -29,7 +30,7 @@ interface FormDataItem { title: Type.FormValue; tags: Type.FormValue; content: Type.FormValue; - answer: Type.FormValue; + answer_content: Type.FormValue; edit_summary: Type.FormValue; } @@ -52,7 +53,7 @@ const Ask = () => { isInvalid: false, errorMsg: '', }, - answer: { + answer_content: { value: '', isInvalid: false, errorMsg: '', @@ -92,7 +93,7 @@ const Ask = () => { return; } getTagsBySlugName(queryTags).then((tags) => { - // eslint-disable-next-line @typescript-eslint/no-use-before-define + // eslint-disable-next-line handleTagsChange(tags); }); }; @@ -116,8 +117,8 @@ const Ask = () => { formData.title.value = draft.title; formData.content.value = draft.content; formData.tags.value = draft.tags; - formData.answer.value = draft.answer; - setCheckState(Boolean(draft.answer)); + formData.answer_content.value = draft.answer_content; + setCheckState(Boolean(draft.answer_content)); setHasDraft(true); setFormData({ ...formData }); } else { @@ -131,7 +132,7 @@ const Ask = () => { }, [qid]); useEffect(() => { - const { title, tags, content, answer } = formData; + const { title, tags, content, answer_content } = formData; const { title: editTitle, tags: editTags, content: editContent } = immData; // edited @@ -151,14 +152,19 @@ const Ask = () => { return; } // write - if (title.value || tags.value.length > 0 || content.value || answer.value) { + if ( + title.value || + tags.value.length > 0 || + content.value || + answer_content.value + ) { // save draft saveDraft.save({ params: { title: title.value, tags: tags.value, content: content.value, - answer: answer.value, + answer_content: answer_content.value, }, callback: () => setHasDraft(true), }); @@ -215,7 +221,7 @@ const Ask = () => { const handleAnswerChange = (value: string) => setFormData({ ...formData, - answer: { ...formData.answer, value, errorMsg: '' }, + answer_content: { ...formData.answer_content, value, errorMsg: '' }, }); const handleSummaryChange = (evt: React.ChangeEvent) => @@ -263,31 +269,30 @@ const Ask = () => { } }); } else { - const res = await saveQuestion(params).catch((err) => { - if (err.isError) { - const data = handleFormError(err, formData); - setFormData({ ...data }); - } - }); + let res; + if (checked) { + res = await saveQuestionWidthAnaser({ + ...params, + answer_content: formData.answer_content.value, + }).catch((err) => { + if (err.isError) { + const data = handleFormError(err, formData); + setFormData({ ...data }); + } + }); + } else { + res = await saveQuestion(params).catch((err) => { + if (err.isError) { + const data = handleFormError(err, formData); + setFormData({ ...data }); + } + }); + } - const id = res?.id; + const id = res?.id || res?.question?.id; if (id) { if (checked) { - postAnswer({ - question_id: id, - content: formData.answer.value, - }) - .then(() => { - navigate(pathFactory.questionLanding(id, params.url_title)); - }) - .catch((err) => { - if (err.isError) { - const data = handleFormError(err, formData, [ - { from: 'content', to: 'answer' }, - ]); - setFormData({ ...data }); - } - }); + navigate(pathFactory.questionLanding(id, res?.question?.url_title)); } else { navigate(pathFactory.questionLanding(id)); } @@ -448,7 +453,7 @@ const Ask = () => { {t('form.fields.answer.label')} { /> )} diff --git a/ui/src/pages/Questions/Detail/components/Answer/index.tsx b/ui/src/pages/Questions/Detail/components/Answer/index.tsx index 7da9f028..89be1784 100644 --- a/ui/src/pages/Questions/Detail/components/Answer/index.tsx +++ b/ui/src/pages/Questions/Detail/components/Answer/index.tsx @@ -1,5 +1,5 @@ import { memo, FC, useEffect, useRef } from 'react'; -import { Button, Alert } from 'react-bootstrap'; +import { Button, Alert, Badge } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; import { Link, useSearchParams } from 'react-router-dom'; @@ -20,8 +20,7 @@ interface Props { data: AnswerItem; /** router answer id */ aid?: string; - /** is author */ - isAuthor: boolean; + canAccept: boolean; questionTitle: string; slugTitle: string; isLogged: boolean; @@ -30,11 +29,11 @@ interface Props { const Index: FC = ({ aid, data, - isAuthor, isLogged, questionTitle = '', slugTitle, callback, + canAccept = false, }) => { const { t } = useTranslation('translation', { keyPrefix: 'question_detail', @@ -77,12 +76,21 @@ const Index: FC = ({ {t('post_deleted', { keyPrefix: 'messages' })} )} + {data?.accepted === 2 && ( +
+ + + Best answer + +
+ )}
= ({ }} /> - {data?.accepted === 2 && ( + {canAccept && ( - )} - - {isAuthor && data.accepted === 1 && ( - )}
diff --git a/ui/src/pages/Questions/Detail/components/Question/index.tsx b/ui/src/pages/Questions/Detail/components/Question/index.tsx index 9eeb66e1..94a42981 100644 --- a/ui/src/pages/Questions/Detail/components/Question/index.tsx +++ b/ui/src/pages/Questions/Detail/components/Question/index.tsx @@ -108,12 +108,13 @@ const Index: FC = ({ data, initPage, hasAnswer, isLogged }) => {
void; } @@ -39,6 +40,7 @@ const Index: FC = ({ visible = false, data, callback }) => { const [focusType, setFocusType] = useState(''); const [editorFocusState, setEditorFocusState] = useState(false); const [hasDraft, setHasDraft] = useState(false); + const [showTips, setShowTips] = useState(data.loggedUserRank < 100); usePromptWithUnload({ when: Boolean(formData.content.value), @@ -212,29 +214,58 @@ const Index: FC = ({ visible = false, data, callback }) => {
)} {showEditor && ( - { - setFormData({ - content: { - value: val, - isInvalid: false, - errorMsg: '', - }, - }); - }} - onFocus={() => { - setFocusType('answer'); - }} - onBlur={() => { - setFocusType(''); - }} - /> + <> + { + setFormData({ + content: { + value: val, + isInvalid: false, + errorMsg: '', + }, + }); + }} + onFocus={() => { + setFocusType('answer'); + }} + onBlur={() => { + setFocusType(''); + }} + /> + + setShowTips(false)} + dismissible + className="mt-3"> +

{t('tips.header_1')}

+
    +
  • + }} + /> +
  • +
  • {t('tips.li1_2')}
  • +
+

+ }} + /> +

+
    +
  • {t('tips.li2_1')}
  • +
+
+ )} diff --git a/ui/src/pages/Questions/Detail/index.tsx b/ui/src/pages/Questions/Detail/index.tsx index b2e16812..67686258 100644 --- a/ui/src/pages/Questions/Detail/index.tsx +++ b/ui/src/pages/Questions/Detail/index.tsx @@ -56,7 +56,9 @@ const Index = () => { const userInfo = loggedUserInfoStore((state) => state.user); const isAuthor = userInfo?.username === question?.user_info?.username; const isAdmin = userInfo?.role_id === 2; + const isModerator = userInfo?.role_id === 3; const isLogged = Boolean(userInfo?.access_token); + const loggedUserRank = userInfo?.rank; const { state: locationState } = useLocation(); useEffect(() => { @@ -221,7 +223,7 @@ const Index = () => { data={item} questionTitle={question?.title || ''} slugTitle={question?.url_title} - isAuthor={isAuthor} + canAccept={isAuthor || isAdmin || isModerator} callback={initPage} isLogged={isLogged} /> @@ -247,6 +249,7 @@ const Index = () => { data={{ qid, answered: question?.answered, + loggedUserRank, }} callback={writeAnswerCallback} /> diff --git a/ui/src/pages/Questions/EditAnswer/index.tsx b/ui/src/pages/Questions/EditAnswer/index.tsx index 680547f0..9875af96 100644 --- a/ui/src/pages/Questions/EditAnswer/index.tsx +++ b/ui/src/pages/Questions/EditAnswer/index.tsx @@ -1,4 +1,4 @@ -import React, { useState, useRef, useEffect } from 'react'; +import React, { useState, useRef, useEffect, useLayoutEffect } from 'react'; import { Container, Row, Col, Form, Button, Card } from 'react-bootstrap'; import { useParams, useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; @@ -6,10 +6,10 @@ import { useTranslation } from 'react-i18next'; import dayjs from 'dayjs'; import classNames from 'classnames'; -import { handleFormError } from '@/utils'; +import { handleFormError, scrollToDocTop } from '@/utils'; import { usePageTags, usePromptWithUnload } from '@/hooks'; import { pathFactory } from '@/router/pathFactory'; -import { Editor, EditorRef, Icon } from '@/components'; +import { Editor, EditorRef, Icon, htmlRender } from '@/components'; import type * as Type from '@/common/interface'; import { useQueryAnswerInfo, @@ -23,31 +23,47 @@ interface FormDataItem { content: Type.FormValue; description: Type.FormValue; } -const initFormData = { - content: { - value: '', - isInvalid: false, - errorMsg: '', - }, - description: { - value: '', - isInvalid: false, - errorMsg: '', - }, -}; + const Index = () => { const { aid = '', qid = '' } = useParams(); const [focusType, setForceType] = useState(''); + useLayoutEffect(() => { + scrollToDocTop(); + }, []); const { t } = useTranslation('translation', { keyPrefix: 'edit_answer' }); const navigate = useNavigate(); + const initFormData = { + content: { + value: '', + isInvalid: false, + errorMsg: '', + }, + description: { + value: '', + isInvalid: false, + errorMsg: '', + }, + }; + const { data } = useQueryAnswerInfo(aid); const [formData, setFormData] = useState(initFormData); const [immData, setImmData] = useState(initFormData); const [contentChanged, setContentChanged] = useState(false); - initFormData.content.value = data?.info.content || ''; + useLayoutEffect(() => { + if (data?.info?.content) { + setFormData({ + ...formData, + content: { + value: data.info.content, + isInvalid: false, + errorMsg: '', + }, + }); + } + }, [data?.info?.content]); const { data: revisions = [] } = useQueryRevisions(aid); @@ -57,6 +73,13 @@ const Index = () => { const questionContentRef = useRef(null); + useEffect(() => { + if (!questionContentRef?.current) { + return; + } + htmlRender(questionContentRef.current); + }, [questionContentRef]); + usePromptWithUnload({ when: contentChanged, }); @@ -147,9 +170,11 @@ const Index = () => { const handleSelectedRevision = (e) => { const index = e.target.value; const revision = revisions[index]; - formData.content.value = revision.content.content; - setImmData({ ...formData }); - setFormData({ ...formData }); + if (revision?.content) { + formData.content.value = revision.content.content; + setImmData({ ...formData }); + setFormData({ ...formData }); + } }; const backPage = () => { @@ -192,7 +217,7 @@ const Index = () => {
{t('form.fields.revision.label')} - + {revisions.map(({ create_at, reason, user_info }, index) => { const date = dayjs(create_at * 1000) .tz() diff --git a/ui/src/pages/Questions/index.tsx b/ui/src/pages/Questions/index.tsx index be432871..77dbd99c 100644 --- a/ui/src/pages/Questions/index.tsx +++ b/ui/src/pages/Questions/index.tsx @@ -16,7 +16,7 @@ const Questions: FC = () => { const { user: loggedUser } = loggedUserInfoStore((_) => _); const [urlSearchParams] = useSearchParams(); const curPage = Number(urlSearchParams.get('page')) || 1; - const curOrder = urlSearchParams.get('order') || 'newest'; + const curOrder = urlSearchParams.get('order') || 'active'; const reqParams: Type.QueryQuestionsReq = { page_size: 20, page: curPage, diff --git a/ui/src/pages/Search/components/SearchHead/index.tsx b/ui/src/pages/Search/components/SearchHead/index.tsx index 3dbada0f..9902603a 100644 --- a/ui/src/pages/Search/components/SearchHead/index.tsx +++ b/ui/src/pages/Search/components/SearchHead/index.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import { QueryGroup } from '@/components'; -const sortBtns = ['relevance', 'newest', 'active', 'score']; +const sortBtns = ['active', 'newest', 'relevance', 'score']; interface Props { count: number; diff --git a/ui/src/pages/Search/index.tsx b/ui/src/pages/Search/index.tsx index 3d51021e..e911f941 100644 --- a/ui/src/pages/Search/index.tsx +++ b/ui/src/pages/Search/index.tsx @@ -21,7 +21,7 @@ const Index = () => { const [searchParams] = useSearchParams(); const page = searchParams.get('page') || 1; const q = searchParams.get('q') || ''; - const order = searchParams.get('order') || 'relevance'; + const order = searchParams.get('order') || 'active'; const { data, isLoading } = useSearch({ q, diff --git a/ui/src/pages/Tags/Detail/index.tsx b/ui/src/pages/Tags/Detail/index.tsx index 8e5ffc0a..84bd7fe2 100644 --- a/ui/src/pages/Tags/Detail/index.tsx +++ b/ui/src/pages/Tags/Detail/index.tsx @@ -28,7 +28,7 @@ const Questions: FC = () => { const routeParams = useParams(); const curTagName = routeParams.tagName || ''; const [urlSearchParams] = useSearchParams(); - const curOrder = urlSearchParams.get('order') || 'newest'; + const curOrder = urlSearchParams.get('order') || 'active'; const curPage = Number(urlSearchParams.get('page')) || 1; const reqParams: Type.QueryQuestionsReq = { page_size: 20, diff --git a/ui/src/pages/Tags/Info/index.tsx b/ui/src/pages/Tags/Info/index.tsx index 7a1e2d4c..3f747f49 100644 --- a/ui/src/pages/Tags/Info/index.tsx +++ b/ui/src/pages/Tags/Info/index.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'; import classNames from 'classnames'; import { usePageTags } from '@/hooks'; -import { Tag, TagSelector, FormatTime, Modal } from '@/components'; +import { Tag, TagSelector, FormatTime, Modal, htmlRender } from '@/components'; import { useTagInfo, useQuerySynonymsTags, @@ -44,6 +44,15 @@ const TagIntroduction = () => { }); } }, [locationState]); + + useEffect(() => { + const fmt = document.querySelector('.content.fmt') as HTMLElement; + if (!fmt) { + return; + } + htmlRender(fmt); + }, [tagInfo?.parsed_text]); + if (!tagInfo) { return null; } @@ -108,7 +117,9 @@ const TagIntroduction = () => { confirmText: t('delete', { keyPrefix: 'btns' }), confirmBtnVariant: 'danger', onConfirm: () => { - deleteTag(tagInfo.tag_id); + deleteTag(tagInfo.tag_id).then(() => { + navigate('/tags', { replace: true }); + }); }, }); }; @@ -143,7 +154,7 @@ const TagIntroduction = () => {
@@ -204,7 +215,8 @@ const TagIntroduction = () => { data={{ slug_name: tagName || '', main_tag_slug_name: '', - display_name: '', + display_name: + tagInfo?.display_name || tagInfo?.slug_name || '', recommend: false, reserved: false, }} diff --git a/ui/src/pages/Tags/index.tsx b/ui/src/pages/Tags/index.tsx index d20b4b0b..b8779364 100644 --- a/ui/src/pages/Tags/index.tsx +++ b/ui/src/pages/Tags/index.tsx @@ -27,7 +27,7 @@ const Tags = () => { const { role_id } = loggedUserInfoStore((_) => _.user); const page = Number(urlSearch.get('page')) || 1; - const sort = urlSearch.get('sort'); + const sort = urlSearch.get('sort') || sortBtns[0]; const pageSize = 20; const { diff --git a/ui/src/pages/Users/ConfirmNewEmail/index.tsx b/ui/src/pages/Users/ConfirmNewEmail/index.tsx index 16d09c9c..c99620db 100644 --- a/ui/src/pages/Users/ConfirmNewEmail/index.tsx +++ b/ui/src/pages/Users/ConfirmNewEmail/index.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'; import { usePageTags } from '@/hooks'; import { loggedUserInfoStore, siteInfoStore } from '@/stores'; -import { changeEmailVerify, getLoggedUserInfo } from '@/services'; +import { changeEmailVerify } from '@/services'; const Index: FC = () => { const { t } = useTranslation('translation', { keyPrefix: 'account_result' }); @@ -20,12 +20,12 @@ const Index: FC = () => { if (code) { // do changeEmailVerify({ code }) - .then(() => { + .then((res) => { setStep('success'); - getLoggedUserInfo().then((res) => { + if (res?.access_token) { // update user info updateUser(res); - }); + } }) .catch(() => { setStep('invalid'); diff --git a/ui/src/router/RouteErrorBoundary.tsx b/ui/src/router/RouteErrorBoundary.tsx index d70683e3..2fe5b1fa 100644 --- a/ui/src/router/RouteErrorBoundary.tsx +++ b/ui/src/router/RouteErrorBoundary.tsx @@ -1,8 +1,7 @@ -import Error50X from '@/pages/50X'; -// import Page404 from '@/pages/404'; +import { HttpErrorContent } from '@/components'; -const Index = () => { - return ; +const Index = ({ errCode = '50X', errMsg = '' }) => { + return ; }; export default Index; diff --git a/ui/src/router/RouteGuard.tsx b/ui/src/router/RouteGuard.tsx index 78fc19f2..3000ab9a 100644 --- a/ui/src/router/RouteGuard.tsx +++ b/ui/src/router/RouteGuard.tsx @@ -1,42 +1,54 @@ import { FC, ReactNode, useEffect } from 'react'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { useLocation, useNavigate, useLoaderData } from 'react-router-dom'; import { floppyNavigation } from '@/utils'; import { TGuardFunc } from '@/utils/guard'; -const Index: FC<{ +import RouteErrorBoundary from './RouteErrorBoundary'; + +const RouteGuard: FC<{ children: ReactNode; - onEnter?: TGuardFunc; + onEnter: TGuardFunc; path?: string; -}> = ({ - children, - onEnter, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - path, -}) => { + page?: string; +}> = ({ children, onEnter, path, page }) => { const navigate = useNavigate(); const location = useLocation(); - const callGuards = () => { - if (onEnter) { - const gr = onEnter(); - const redirectUrl = gr.redirect; - if (redirectUrl) { - floppyNavigation.navigate(redirectUrl, { - handler: navigate, - options: { replace: true }, - }); - } + const loaderData = useLoaderData(); + const gr = onEnter({ + loaderData, + path, + page, + }); + + let guardError; + const errCode = gr.error?.code; + if (errCode === '403' || errCode === '404' || errCode === '50X') { + guardError = { + code: errCode, + msg: gr.error?.msg, + }; + } + const handleGuardRedirect = () => { + const redirectUrl = gr.redirect; + if (redirectUrl) { + floppyNavigation.navigate(redirectUrl, { + handler: navigate, + options: { replace: true }, + }); } }; useEffect(() => { - callGuards(); + handleGuardRedirect(); }, [location]); return ( <> - {/* Route Guard */} - {children} + {gr.ok ? children : null} + {!gr.ok && guardError ? ( + + ) : null} ); }; -export default Index; +export default RouteGuard; diff --git a/ui/src/router/index.tsx b/ui/src/router/index.tsx index 2e30ce75..50b6d2ef 100644 --- a/ui/src/router/index.tsx +++ b/ui/src/router/index.tsx @@ -13,7 +13,7 @@ const routeWrapper = (routeNodes: RouteNode[], root: RouteNode[]) => { routeNodes.forEach((rn) => { if (rn.page === 'pages/Layout') { rn.element = rn.guard ? ( - + ) : ( @@ -30,7 +30,7 @@ const routeWrapper = (routeNodes: RouteNode[], root: RouteNode[]) => { rn.element = ( {rn.guard ? ( - + ) : ( diff --git a/ui/src/router/pathFactory.ts b/ui/src/router/pathFactory.ts index fbf4e0ca..acf6b690 100644 --- a/ui/src/router/pathFactory.ts +++ b/ui/src/router/pathFactory.ts @@ -19,6 +19,9 @@ const tagEdit = (tagId: string) => { }; const questionLanding = (questionId: string, slugTitle: string = '') => { const { seo } = seoSettingStore.getState(); + if (!questionId) { + return slugTitle ? `/questions/null/${slugTitle}` : '/questions/null'; + } // @ts-ignore if (/[13]/.test(seo.permalink) && slugTitle) { return urlcat('/questions/:questionId/:slugPermalink', { diff --git a/ui/src/router/routes.ts b/ui/src/router/routes.ts index 195c5fe7..b776359f 100644 --- a/ui/src/router/routes.ts +++ b/ui/src/router/routes.ts @@ -2,6 +2,8 @@ import type { IndexRouteObject, NonIndexRouteObject } from 'react-router-dom'; import { guard } from '@/utils'; import type { TGuardFunc } from '@/utils/guard'; +import { editCheck } from '@/services'; +import { isEditable } from '@/utils/guard'; type IndexRouteNode = Omit; type NonIndexRouteNode = Omit; @@ -74,6 +76,13 @@ const routes: RouteNode[] = [ { path: 'posts/:qid/:aid/edit', page: 'pages/Questions/EditAnswer', + loader: async ({ params }) => { + const ret = await editCheck(params.aid as string, true); + return ret; + }, + guard: (args) => { + return isEditable(args); + }, }, { path: '/search', diff --git a/ui/src/services/client/notification.ts b/ui/src/services/client/notification.ts index b499bbda..cc2f32b0 100644 --- a/ui/src/services/client/notification.ts +++ b/ui/src/services/client/notification.ts @@ -34,7 +34,7 @@ export const useQueryNotificationStatus = () => { return useSWR( tryLoggedAndActivated().ok ? apiUrl : null, - request.instance.get, + (url) => request.get(url, { ignoreError: '50X' }), { refreshInterval: 3000, }, diff --git a/ui/src/services/client/revision.ts b/ui/src/services/client/revision.ts index 06b5ce49..41201cb3 100644 --- a/ui/src/services/client/revision.ts +++ b/ui/src/services/client/revision.ts @@ -1,9 +1,11 @@ import request from '@/utils/request'; import * as Type from '@/common/interface'; -export const editCheck = (id: string) => { +export const editCheck = (id: string, passingError: boolean = false) => { const apiUrl = `/answer/api/v1/revisions/edit/check?id=${id}`; - return request.get(apiUrl); + return request.get(apiUrl, { + passingError, + }); }; export const revisionAudit = (id: string, operation: 'approve' | 'reject') => { diff --git a/ui/src/services/common.ts b/ui/src/services/common.ts index 5701adfa..04580af3 100644 --- a/ui/src/services/common.ts +++ b/ui/src/services/common.ts @@ -275,3 +275,7 @@ export const markdownToHtml = (content: string) => { const apiUrl = '/answer/api/v1/post/render'; return request.post(apiUrl, { content }); }; + +export const saveQuestionWidthAnaser = (params: Type.QuestionWithAnswer) => { + return request.post('/answer/api/v1/question/answer', params); +}; diff --git a/ui/src/stores/errorCode.ts b/ui/src/stores/errorCode.ts index 336a213b..aa2bcea1 100644 --- a/ui/src/stores/errorCode.ts +++ b/ui/src/stores/errorCode.ts @@ -1,25 +1,27 @@ import create from 'zustand'; -type codeType = '404' | '50X' | ''; +type codeType = '403' | '404' | '50X' | ''; -interface NotFoundType { +interface ErrorCodeType { code: codeType; - update: (code: codeType) => void; + msg: string; + update: (code: codeType, msg?: string) => void; reset: () => void; } -const notFound = create((set) => ({ +const Index = create((set) => ({ code: '', - update: (code: codeType) => { + msg: '', + update: (code: codeType, msg: string = '') => { set(() => { - return { code }; + return { code, msg }; }); }, reset: () => { set(() => { - return { code: '' }; + return { code: '', msg: '' }; }); }, })); -export default notFound; +export default Index; diff --git a/ui/src/stores/index.ts b/ui/src/stores/index.ts index a87bbbcb..4740e25f 100644 --- a/ui/src/stores/index.ts +++ b/ui/src/stores/index.ts @@ -10,7 +10,7 @@ import pageTagStore from './pageTags'; import customizeStore from './customize'; import themeSettingStore from './themeSetting'; import loginToContinueStore from './loginToContinue'; -import errorCode from './errorCode'; +import errorCodeStore from './errorCode'; export { toastStore, @@ -24,6 +24,6 @@ export { themeSettingStore, seoSettingStore, loginToContinueStore, - errorCode, + errorCodeStore, userCenterStore, }; diff --git a/ui/src/stores/loggedUserInfo.ts b/ui/src/stores/loggedUserInfo.ts index 2f7a35f4..d08cce44 100644 --- a/ui/src/stores/loggedUserInfo.ts +++ b/ui/src/stores/loggedUserInfo.ts @@ -31,7 +31,7 @@ const initUser: UserInfoRes = { const loggedUserInfo = create((set) => ({ user: initUser, update: (params) => { - if (!params.language) { + if (!params?.language) { params.language = 'Default'; } set(() => { diff --git a/ui/src/stores/seoSetting.ts b/ui/src/stores/seoSetting.ts index 6c15e9cf..c714a8f5 100644 --- a/ui/src/stores/seoSetting.ts +++ b/ui/src/stores/seoSetting.ts @@ -7,7 +7,7 @@ interface IProps { update: (params: AdminSettingsSeo) => void; } -const siteInfo = create((set) => ({ +const Index = create((set) => ({ seo: { robots: '', permalink: 1, @@ -25,4 +25,4 @@ const siteInfo = create((set) => ({ }), })); -export default siteInfo; +export default Index; diff --git a/ui/src/utils/common.ts b/ui/src/utils/common.ts index 2747890b..c9cb3267 100644 --- a/ui/src/utils/common.ts +++ b/ui/src/utils/common.ts @@ -1,6 +1,4 @@ import i18next from 'i18next'; -import parse from 'html-react-parser'; -import * as DOMPurify from 'dompurify'; const Diff = require('diff'); @@ -235,32 +233,6 @@ function diffText(newText: string, oldText?: string): string { return result.join(''); } -function htmlToReact(html: string) { - const cleanedHtml = DOMPurify.sanitize(html, { - USE_PROFILES: { html: true }, - }); - - const ele = document.createElement('div'); - ele.innerHTML = cleanedHtml; - - ele.querySelectorAll('table').forEach((table) => { - if ( - (!table || (table.parentNode as HTMLDivElement))?.classList.contains( - 'table-responsive', - ) - ) { - return; - } - - table.classList.add('table', 'table-bordered'); - const div = document.createElement('div'); - div.className = 'table-responsive'; - table.parentNode?.replaceChild(div, table); - div.appendChild(table); - }); - return parse(ele.innerHTML); -} - function base64ToSvg(base64: string) { // base64 to svg xml const svgxml = atob(base64); @@ -297,6 +269,5 @@ export { labelStyle, handleFormError, diffText, - htmlToReact, base64ToSvg, }; diff --git a/ui/src/utils/guard.ts b/ui/src/utils/guard.ts index 899fe5f4..a66d877f 100644 --- a/ui/src/utils/guard.ts +++ b/ui/src/utils/guard.ts @@ -29,8 +29,16 @@ type TLoginState = { export type TGuardResult = { ok: boolean; redirect?: string; + error?: { + code?: number | string; + msg?: string; + }; }; -export type TGuardFunc = () => TGuardResult; +export type TGuardFunc = (args: { + loaderData?: any; + path?: string; + page?: string; +}) => TGuardResult; export const deriveLoginState = (): TLoginState => { const ls: TLoginState = { @@ -166,7 +174,11 @@ export const admin = () => { const us = deriveLoginState(); if (gr.ok && !us.isAdmin) { gr.ok = false; - gr.redirect = RouteAlias.home; + gr.error = { + code: '403', + msg: '', + }; + gr.redirect = ''; } return gr; }; @@ -176,7 +188,24 @@ export const isAdminOrModerator = () => { const us = deriveLoginState(); if (gr.ok && !us.isAdmin && !us.isModerator) { gr.ok = false; - gr.redirect = RouteAlias.home; + gr.error = { + code: '403', + msg: '', + }; + gr.redirect = ''; + } + return gr; +}; + +export const isEditable = (args) => { + const loaderData = args?.loaderData || {}; + const gr: TGuardResult = { ok: true }; + if (loaderData.code === 400) { + gr.ok = false; + gr.error = { + code: '403', + msg: loaderData.msg, + }; } return gr; }; diff --git a/ui/src/utils/request.ts b/ui/src/utils/request.ts index eb49e076..739d3b1b 100644 --- a/ui/src/utils/request.ts +++ b/ui/src/utils/request.ts @@ -2,7 +2,7 @@ import axios, { AxiosResponse } from 'axios'; import type { AxiosInstance, AxiosRequestConfig, AxiosError } from 'axios'; import { Modal } from '@/components'; -import { loggedUserInfoStore, toastStore, errorCode } from '@/stores'; +import { loggedUserInfoStore, toastStore, errorCodeStore } from '@/stores'; import { LOGGED_TOKEN_STORAGE_KEY, IGNORE_PATH_LIST } from '@/common/constants'; import { RouteAlias } from '@/router/alias'; import { getCurrentLang } from '@/utils/localize'; @@ -16,8 +16,12 @@ const baseConfig = { withCredentials: true, }; -interface APIconfig extends AxiosRequestConfig { - allow404: boolean; +interface ApiConfig extends AxiosRequestConfig { + // Configure whether to allow takeover of 404 errors + allow404?: boolean; + ignoreError?: '403' | '50X'; + // Configure whether to pass errors directly + passingError?: boolean; } class Request { @@ -52,14 +56,17 @@ class Request { return data; }, (error) => { - const { status, data: respData } = error.response || {}; - const { data = {}, msg = '', reason = '' } = respData || {}; - - console.log('response error:', error); - + const { + status, + data: errModel, + config: errConfig, + } = error.response || {}; + const { data = {}, msg = '' } = errModel || {}; if (status === 400) { - // show error message - if (data instanceof Object && data.err_type) { + if (data?.err_type && errConfig?.passingError) { + return errModel; + } + if (data?.err_type) { if (data.err_type === 'toast') { // toast error message toastStore.getState().show({ @@ -90,7 +97,6 @@ class Request { return Promise.reject({ code: status, msg, - reason, isError: true, list: data, }); @@ -107,14 +113,13 @@ class Request { // 401: Re-login required if (status === 401) { // clear userinfo - errorCode.getState().reset(); + errorCodeStore.getState().reset(); loggedUserInfoStore.getState().clear(); floppyNavigation.navigateToLogin(); return Promise.reject(false); } if (status === 403) { // Permission interception - errorCode.getState().reset(); if (data?.type === 'url_expired') { // url expired floppyNavigation.navigate(RouteAlias.activationFailed, { @@ -135,6 +140,14 @@ class Request { return Promise.reject(false); } + if (isIgnoredPath(IGNORE_PATH_LIST)) { + return Promise.reject(false); + } + if (error.config?.url.includes('/admin/api')) { + errorCodeStore.getState().update('403'); + return Promise.reject(false); + } + if (msg) { toastStore.getState().show({ msg, @@ -148,14 +161,18 @@ class Request { if (isIgnoredPath(IGNORE_PATH_LIST)) { return Promise.reject(false); } - errorCode.getState().update('404'); + errorCodeStore.getState().update('404'); return Promise.reject(false); } if (status >= 500) { if (isIgnoredPath(IGNORE_PATH_LIST)) { return Promise.reject(false); } - errorCode.getState().update('50X'); + + if (error.config?.ignoreError !== '50X') { + errorCodeStore.getState().update('50X'); + } + console.error( `Request failed with status code ${status}, ${msg || ''}`, ); @@ -169,7 +186,7 @@ class Request { return this.instance.request(config); } - public get(url: string, config?: APIconfig): Promise { + public get(url: string, config?: ApiConfig): Promise { return this.instance.get(url, config); } diff --git a/ui/src/utils/saveDraft.ts b/ui/src/utils/saveDraft.ts index 65a3df12..2d579f65 100644 --- a/ui/src/utils/saveDraft.ts +++ b/ui/src/utils/saveDraft.ts @@ -11,7 +11,7 @@ export type QuestionDraft = { title: string; content: string; tags: any[]; - answer: string; + answer_content: string; }; callback?: () => void; }; diff --git a/ui/tsconfig.json b/ui/tsconfig.json index c6e49931..b16f340c 100644 --- a/ui/tsconfig.json +++ b/ui/tsconfig.json @@ -14,6 +14,7 @@ "resolveJsonModule": true, "isolatedModules": true, "noImplicitAny": false, + "ignoreDeprecations": "5.0", "suppressImplicitAnyIndexErrors": true, "noEmit": true, "jsx": "react-jsx",