Compare commits
3 Commits
42bbdebf6f
...
869e857f2c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
869e857f2c | ||
|
|
efb687b742 | ||
|
|
c49f498309 |
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
|
@ -10,6 +10,8 @@
|
||||||
"Groupbutton",
|
"Groupbutton",
|
||||||
"handelnavigate",
|
"handelnavigate",
|
||||||
"Karim",
|
"Karim",
|
||||||
|
"katex",
|
||||||
|
"Latext",
|
||||||
"Popconfirm",
|
"Popconfirm",
|
||||||
"queryqlent",
|
"queryqlent",
|
||||||
"registraion",
|
"registraion",
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,16 @@
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/App/Logo2.png" />
|
<link rel="icon" type="image/png" sizes="32x32" href="/App/Logo2.png" />
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/App/Logo2.png" />
|
<link rel="icon" type="image/png" sizes="16x16" href="/App/Logo2.png" />
|
||||||
<link rel="manifest" href="/site.webmanifest" />
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
|
<link
|
||||||
|
href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0/katex.min.css"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="social networking platform with automated content moderation and context-based authentication system"
|
content="social networking platform with automated content moderation and context-based authentication system"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<script type="module" src="/src/index.tsx"></script>
|
<script type="module" src="/src/index.tsx"></script>
|
||||||
|
|
||||||
<title>NERD DASHBOARD</title>
|
<title>NERD DASHBOARD</title>
|
||||||
|
|
|
||||||
418
package-lock.json
generated
418
package-lock.json
generated
|
|
@ -13,21 +13,31 @@
|
||||||
"@dnd-kit/modifiers": "^7.0.0",
|
"@dnd-kit/modifiers": "^7.0.0",
|
||||||
"@dnd-kit/sortable": "^8.0.0",
|
"@dnd-kit/sortable": "^8.0.0",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
|
"@types/katex": "^0.16.7",
|
||||||
"antd": "^5.17.4",
|
"antd": "^5.17.4",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
|
"better-react-mathjax": "^2.0.3",
|
||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
"i18next": "^23.11.5",
|
"i18next": "^23.11.5",
|
||||||
|
"katex": "^0.16.11",
|
||||||
"lottie-react": "^2.4.0",
|
"lottie-react": "^2.4.0",
|
||||||
|
"mathjax-full": "^3.2.2",
|
||||||
|
"mathml-to-latex": "^1.4.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-i18next": "^13.5.0",
|
"react-i18next": "^13.5.0",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
|
"react-katex": "^3.0.1",
|
||||||
|
"react-latex": "^2.0.0",
|
||||||
|
"react-latex-next": "^3.0.0",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
|
"react-window": "^1.8.10",
|
||||||
|
"react-window-dynamic": "^1.8.0-alpha.2",
|
||||||
"reactstrap": "^9.2.2",
|
"reactstrap": "^9.2.2",
|
||||||
"sass": "^1.77.4",
|
"sass": "^1.77.4",
|
||||||
"yup": "^1.4.0",
|
"yup": "^1.4.0",
|
||||||
|
|
@ -42,6 +52,9 @@
|
||||||
"@types/react-beautiful-dnd": "^13.1.8",
|
"@types/react-beautiful-dnd": "^13.1.8",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@types/react-helmet": "^6.1.11",
|
"@types/react-helmet": "^6.1.11",
|
||||||
|
"@types/react-katex": "^3.0.4",
|
||||||
|
"@types/react-latex": "^2.0.3",
|
||||||
|
"@types/react-window": "^1.8.8",
|
||||||
"@vitejs/plugin-legacy": "^5.4.1",
|
"@vitejs/plugin-legacy": "^5.4.1",
|
||||||
"@vitejs/plugin-react": "^4.3.0",
|
"@vitejs/plugin-react": "^4.3.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
|
|
@ -3566,6 +3579,11 @@
|
||||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/katex": {
|
||||||
|
"version": "0.16.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz",
|
||||||
|
"integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ=="
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.14.15",
|
"version": "20.14.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.15.tgz",
|
||||||
|
|
@ -3616,6 +3634,24 @@
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-katex": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-katex/-/react-katex-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-aLkykKzSKLpXI6REJ3uClao6P47HAFfR1gcHOZwDeTuALsyjgMhz+oynLV4gX0kiJVnvHrBKF/TLXqyNTpHDUg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/react-latex": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-latex/-/react-latex-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-PdH5UI5AT2aj+sBJkQbmXc/0S7pR/7i/u5oFhDrFHTeI2TedMk+RwQsVNcHMXleT1L7RqyNjm0FE4AtUHsv/DA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/react-redux": {
|
"node_modules/@types/react-redux": {
|
||||||
"version": "7.1.33",
|
"version": "7.1.33",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.33.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.33.tgz",
|
||||||
|
|
@ -3627,6 +3663,15 @@
|
||||||
"redux": "^4.0.0"
|
"redux": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-window": {
|
||||||
|
"version": "1.8.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.8.tgz",
|
||||||
|
"integrity": "sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/stack-utils": {
|
"node_modules/@types/stack-utils": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
|
||||||
|
|
@ -3892,6 +3937,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@xmldom/xmldom": {
|
||||||
|
"version": "0.8.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
|
||||||
|
"integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@xtuc/ieee754": {
|
"node_modules/@xtuc/ieee754": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
|
||||||
|
|
@ -4325,6 +4378,17 @@
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/better-react-mathjax": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/better-react-mathjax/-/better-react-mathjax-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-wfifT8GFOKb1TWm2+E50I6DJpLZ5kLbch283Lu043EJtwSv0XvZDjr4YfR4d2MjAhqP6SH4VjjrKgbX8R00oCQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"mathjax-full": "^3.2.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/big-integer": {
|
"node_modules/big-integer": {
|
||||||
"version": "1.6.52",
|
"version": "1.6.52",
|
||||||
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
|
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
|
||||||
|
|
@ -4701,6 +4765,14 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/commander": {
|
||||||
|
"version": "8.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
|
||||||
|
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/compute-scroll-into-view": {
|
"node_modules/compute-scroll-into-view": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz",
|
||||||
|
|
@ -5208,6 +5280,14 @@
|
||||||
"node": ">=8.0.0"
|
"node": ">=8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/esm": {
|
||||||
|
"version": "3.2.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
|
||||||
|
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/esprima": {
|
"node_modules/esprima": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||||
|
|
@ -7372,6 +7452,21 @@
|
||||||
"node": ">= 10.0.0"
|
"node": ">= 10.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/katex": {
|
||||||
|
"version": "0.16.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz",
|
||||||
|
"integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==",
|
||||||
|
"funding": [
|
||||||
|
"https://opencollective.com/katex",
|
||||||
|
"https://github.com/sponsors/katex"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^8.3.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"katex": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/kind-of": {
|
"node_modules/kind-of": {
|
||||||
"version": "6.0.3",
|
"version": "6.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||||
|
|
@ -7554,6 +7649,25 @@
|
||||||
"remove-accents": "0.5.0"
|
"remove-accents": "0.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mathjax-full": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w==",
|
||||||
|
"dependencies": {
|
||||||
|
"esm": "^3.2.25",
|
||||||
|
"mhchemparser": "^4.1.0",
|
||||||
|
"mj-context-menu": "^0.6.1",
|
||||||
|
"speech-rule-engine": "^4.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mathml-to-latex": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mathml-to-latex/-/mathml-to-latex-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-3B+q88sVnQCqWG0UN5scYZRsUE0O2GFNfqCA0AMY/+iNkrwm3n4eiqFNKpJQ0lguHhbLfuKKoJuPixDKuqiLCQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@xmldom/xmldom": "^0.8.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/memoize-one": {
|
"node_modules/memoize-one": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
||||||
|
|
@ -7577,6 +7691,11 @@
|
||||||
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/mhchemparser": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ=="
|
||||||
|
},
|
||||||
"node_modules/micromatch": {
|
"node_modules/micromatch": {
|
||||||
"version": "4.0.7",
|
"version": "4.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
||||||
|
|
@ -7643,6 +7762,11 @@
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mj-context-menu": {
|
||||||
|
"version": "0.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz",
|
||||||
|
"integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA=="
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
|
@ -8809,6 +8933,58 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/react-katex": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-katex/-/react-katex-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-wIUW1fU5dHlkKvq4POfDkHruQsYp3fM8xNb/jnc8dnQ+nNCnaj0sx5pw7E6UyuEdLRyFKK0HZjmXBo+AtXXy0A==",
|
||||||
|
"dependencies": {
|
||||||
|
"katex": "^0.16.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"prop-types": "^15.8.1",
|
||||||
|
"react": ">=15.3.2 <=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-latex": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-latex/-/react-latex-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-x17uDCfqBgR+5ZF/zplRCuHdEbX22CJlVipOqMUinRMoiOwh5fr3jbjD4zqVQ8pIs4AnF0BWPDR2S7Fyd8Snxw==",
|
||||||
|
"dependencies": {
|
||||||
|
"katex": "^0.10.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-latex-next": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-latex-next/-/react-latex-next-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-x70f1b1G7TronVigsRgKHKYYVUNfZk/3bciFyYX1lYLQH2y3/TXku3+5Vap8MDbJhtopePSYBsYWS6jhzIdz+g==",
|
||||||
|
"dependencies": {
|
||||||
|
"katex": "^0.16.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12",
|
||||||
|
"npm": ">=5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-latex/node_modules/commander": {
|
||||||
|
"version": "2.20.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
||||||
|
},
|
||||||
|
"node_modules/react-latex/node_modules/katex": {
|
||||||
|
"version": "0.10.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/katex/-/katex-0.10.2.tgz",
|
||||||
|
"integrity": "sha512-cQOmyIRoMloCoSIOZ1+gEwsksdJZ1EW4SWm3QzxSza/QsnZr6D4U1V9S4q+B/OLm2OQ8TCBecQ8MaIfnScI7cw==",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^2.19.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"katex": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-popper": {
|
"node_modules/react-popper": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
|
||||||
|
|
@ -8948,6 +9124,38 @@
|
||||||
"react-dom": ">=16.6.0"
|
"react-dom": ">=16.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-window": {
|
||||||
|
"version": "1.8.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.10.tgz",
|
||||||
|
"integrity": "sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"memoize-one": ">=3.1.1 <6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-window-dynamic": {
|
||||||
|
"version": "1.8.0-alpha.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-window-dynamic/-/react-window-dynamic-1.8.0-alpha.2.tgz",
|
||||||
|
"integrity": "sha512-PYR1nu5kzEr+PDg9/+19uTqO1OqUCckYE5dDpjFpEGBtVTcq4smxE3jXhk+zLi4AOZlLVr9pJIjwPL68zwq5Ww==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"memoize-one": ">=3.1.1 <6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^15.0.0 || ^16.0.0",
|
||||||
|
"react-dom": "^15.0.0 || ^16.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/reactstrap": {
|
"node_modules/reactstrap": {
|
||||||
"version": "9.2.2",
|
"version": "9.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-9.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-9.2.2.tgz",
|
||||||
|
|
@ -9483,6 +9691,27 @@
|
||||||
"source-map": "^0.6.0"
|
"source-map": "^0.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/speech-rule-engine": {
|
||||||
|
"version": "4.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.0.7.tgz",
|
||||||
|
"integrity": "sha512-sJrL3/wHzNwJRLBdf6CjJWIlxC04iYKkyXvYSVsWVOiC2DSkHmxsqOhEeMsBA9XK+CHuNcsdkbFDnoUfAsmp9g==",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "9.2.0",
|
||||||
|
"wicked-good-xpath": "1.3.0",
|
||||||
|
"xmldom-sre": "0.1.31"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"sre": "bin/sre"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/speech-rule-engine/node_modules/commander": {
|
||||||
|
"version": "9.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz",
|
||||||
|
"integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==",
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sprintf-js": {
|
"node_modules/sprintf-js": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||||
|
|
@ -10539,6 +10768,11 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/wicked-good-xpath": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw=="
|
||||||
|
},
|
||||||
"node_modules/wildcard": {
|
"node_modules/wildcard": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
|
||||||
|
|
@ -10616,6 +10850,14 @@
|
||||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/xmldom-sre": {
|
||||||
|
"version": "0.1.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz",
|
||||||
|
"integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/y18n": {
|
"node_modules/y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
|
@ -13154,6 +13396,11 @@
|
||||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/katex": {
|
||||||
|
"version": "0.16.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz",
|
||||||
|
"integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ=="
|
||||||
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "20.14.15",
|
"version": "20.14.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.15.tgz",
|
||||||
|
|
@ -13204,6 +13451,24 @@
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/react-katex": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-katex/-/react-katex-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-aLkykKzSKLpXI6REJ3uClao6P47HAFfR1gcHOZwDeTuALsyjgMhz+oynLV4gX0kiJVnvHrBKF/TLXqyNTpHDUg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/react-latex": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-latex/-/react-latex-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-PdH5UI5AT2aj+sBJkQbmXc/0S7pR/7i/u5oFhDrFHTeI2TedMk+RwQsVNcHMXleT1L7RqyNjm0FE4AtUHsv/DA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/react-redux": {
|
"@types/react-redux": {
|
||||||
"version": "7.1.33",
|
"version": "7.1.33",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.33.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.33.tgz",
|
||||||
|
|
@ -13215,6 +13480,15 @@
|
||||||
"redux": "^4.0.0"
|
"redux": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/react-window": {
|
||||||
|
"version": "1.8.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.8.tgz",
|
||||||
|
"integrity": "sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/stack-utils": {
|
"@types/stack-utils": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
|
||||||
|
|
@ -13441,6 +13715,11 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
"@xmldom/xmldom": {
|
||||||
|
"version": "0.8.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
|
||||||
|
"integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw=="
|
||||||
|
},
|
||||||
"@xtuc/ieee754": {
|
"@xtuc/ieee754": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
|
||||||
|
|
@ -13785,6 +14064,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||||
},
|
},
|
||||||
|
"better-react-mathjax": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/better-react-mathjax/-/better-react-mathjax-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-wfifT8GFOKb1TWm2+E50I6DJpLZ5kLbch283Lu043EJtwSv0XvZDjr4YfR4d2MjAhqP6SH4VjjrKgbX8R00oCQ==",
|
||||||
|
"requires": {
|
||||||
|
"mathjax-full": "^3.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"big-integer": {
|
"big-integer": {
|
||||||
"version": "1.6.52",
|
"version": "1.6.52",
|
||||||
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
|
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
|
||||||
|
|
@ -14031,6 +14318,11 @@
|
||||||
"delayed-stream": "~1.0.0"
|
"delayed-stream": "~1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"commander": {
|
||||||
|
"version": "8.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
|
||||||
|
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="
|
||||||
|
},
|
||||||
"compute-scroll-into-view": {
|
"compute-scroll-into-view": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz",
|
||||||
|
|
@ -14418,6 +14710,11 @@
|
||||||
"estraverse": "^4.1.1"
|
"estraverse": "^4.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"esm": {
|
||||||
|
"version": "3.2.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
|
||||||
|
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA=="
|
||||||
|
},
|
||||||
"esprima": {
|
"esprima": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||||
|
|
@ -15984,6 +16281,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"katex": {
|
||||||
|
"version": "0.16.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz",
|
||||||
|
"integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==",
|
||||||
|
"requires": {
|
||||||
|
"commander": "^8.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"kind-of": {
|
"kind-of": {
|
||||||
"version": "6.0.3",
|
"version": "6.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||||
|
|
@ -16131,6 +16436,25 @@
|
||||||
"remove-accents": "0.5.0"
|
"remove-accents": "0.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mathjax-full": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w==",
|
||||||
|
"requires": {
|
||||||
|
"esm": "^3.2.25",
|
||||||
|
"mhchemparser": "^4.1.0",
|
||||||
|
"mj-context-menu": "^0.6.1",
|
||||||
|
"speech-rule-engine": "^4.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mathml-to-latex": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mathml-to-latex/-/mathml-to-latex-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-3B+q88sVnQCqWG0UN5scYZRsUE0O2GFNfqCA0AMY/+iNkrwm3n4eiqFNKpJQ0lguHhbLfuKKoJuPixDKuqiLCQ==",
|
||||||
|
"requires": {
|
||||||
|
"@xmldom/xmldom": "^0.8.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"memoize-one": {
|
"memoize-one": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
||||||
|
|
@ -16148,6 +16472,11 @@
|
||||||
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"mhchemparser": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ=="
|
||||||
|
},
|
||||||
"micromatch": {
|
"micromatch": {
|
||||||
"version": "4.0.7",
|
"version": "4.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
||||||
|
|
@ -16196,6 +16525,11 @@
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mj-context-menu": {
|
||||||
|
"version": "0.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz",
|
||||||
|
"integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA=="
|
||||||
|
},
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
|
@ -17001,6 +17335,45 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
},
|
},
|
||||||
|
"react-katex": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-katex/-/react-katex-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-wIUW1fU5dHlkKvq4POfDkHruQsYp3fM8xNb/jnc8dnQ+nNCnaj0sx5pw7E6UyuEdLRyFKK0HZjmXBo+AtXXy0A==",
|
||||||
|
"requires": {
|
||||||
|
"katex": "^0.16.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-latex": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-latex/-/react-latex-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-x17uDCfqBgR+5ZF/zplRCuHdEbX22CJlVipOqMUinRMoiOwh5fr3jbjD4zqVQ8pIs4AnF0BWPDR2S7Fyd8Snxw==",
|
||||||
|
"requires": {
|
||||||
|
"katex": "^0.10.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"commander": {
|
||||||
|
"version": "2.20.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
||||||
|
},
|
||||||
|
"katex": {
|
||||||
|
"version": "0.10.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/katex/-/katex-0.10.2.tgz",
|
||||||
|
"integrity": "sha512-cQOmyIRoMloCoSIOZ1+gEwsksdJZ1EW4SWm3QzxSza/QsnZr6D4U1V9S4q+B/OLm2OQ8TCBecQ8MaIfnScI7cw==",
|
||||||
|
"requires": {
|
||||||
|
"commander": "^2.19.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-latex-next": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-latex-next/-/react-latex-next-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-x70f1b1G7TronVigsRgKHKYYVUNfZk/3bciFyYX1lYLQH2y3/TXku3+5Vap8MDbJhtopePSYBsYWS6jhzIdz+g==",
|
||||||
|
"requires": {
|
||||||
|
"katex": "^0.16.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-popper": {
|
"react-popper": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
|
||||||
|
|
@ -17089,6 +17462,24 @@
|
||||||
"prop-types": "^15.6.2"
|
"prop-types": "^15.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-window": {
|
||||||
|
"version": "1.8.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.10.tgz",
|
||||||
|
"integrity": "sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"memoize-one": ">=3.1.1 <6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-window-dynamic": {
|
||||||
|
"version": "1.8.0-alpha.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-window-dynamic/-/react-window-dynamic-1.8.0-alpha.2.tgz",
|
||||||
|
"integrity": "sha512-PYR1nu5kzEr+PDg9/+19uTqO1OqUCckYE5dDpjFpEGBtVTcq4smxE3jXhk+zLi4AOZlLVr9pJIjwPL68zwq5Ww==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"memoize-one": ">=3.1.1 <6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"reactstrap": {
|
"reactstrap": {
|
||||||
"version": "9.2.2",
|
"version": "9.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-9.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-9.2.2.tgz",
|
||||||
|
|
@ -17497,6 +17888,23 @@
|
||||||
"source-map": "^0.6.0"
|
"source-map": "^0.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"speech-rule-engine": {
|
||||||
|
"version": "4.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.0.7.tgz",
|
||||||
|
"integrity": "sha512-sJrL3/wHzNwJRLBdf6CjJWIlxC04iYKkyXvYSVsWVOiC2DSkHmxsqOhEeMsBA9XK+CHuNcsdkbFDnoUfAsmp9g==",
|
||||||
|
"requires": {
|
||||||
|
"commander": "9.2.0",
|
||||||
|
"wicked-good-xpath": "1.3.0",
|
||||||
|
"xmldom-sre": "0.1.31"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"commander": {
|
||||||
|
"version": "9.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz",
|
||||||
|
"integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"sprintf-js": {
|
"sprintf-js": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||||
|
|
@ -18194,6 +18602,11 @@
|
||||||
"has-tostringtag": "^1.0.2"
|
"has-tostringtag": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"wicked-good-xpath": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw=="
|
||||||
|
},
|
||||||
"wildcard": {
|
"wildcard": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
|
||||||
|
|
@ -18245,6 +18658,11 @@
|
||||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"xmldom-sre": {
|
||||||
|
"version": "0.1.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz",
|
||||||
|
"integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw=="
|
||||||
|
},
|
||||||
"y18n": {
|
"y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
|
|
||||||
13
package.json
13
package.json
|
|
@ -8,21 +8,31 @@
|
||||||
"@dnd-kit/modifiers": "^7.0.0",
|
"@dnd-kit/modifiers": "^7.0.0",
|
||||||
"@dnd-kit/sortable": "^8.0.0",
|
"@dnd-kit/sortable": "^8.0.0",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
|
"@types/katex": "^0.16.7",
|
||||||
"antd": "^5.17.4",
|
"antd": "^5.17.4",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
|
"better-react-mathjax": "^2.0.3",
|
||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
"i18next": "^23.11.5",
|
"i18next": "^23.11.5",
|
||||||
|
"katex": "^0.16.11",
|
||||||
"lottie-react": "^2.4.0",
|
"lottie-react": "^2.4.0",
|
||||||
|
"mathjax-full": "^3.2.2",
|
||||||
|
"mathml-to-latex": "^1.4.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-i18next": "^13.5.0",
|
"react-i18next": "^13.5.0",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
|
"react-katex": "^3.0.1",
|
||||||
|
"react-latex": "^2.0.0",
|
||||||
|
"react-latex-next": "^3.0.0",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
|
"react-window": "^1.8.10",
|
||||||
|
"react-window-dynamic": "^1.8.0-alpha.2",
|
||||||
"reactstrap": "^9.2.2",
|
"reactstrap": "^9.2.2",
|
||||||
"sass": "^1.77.4",
|
"sass": "^1.77.4",
|
||||||
"yup": "^1.4.0",
|
"yup": "^1.4.0",
|
||||||
|
|
@ -63,6 +73,9 @@
|
||||||
"@types/react-beautiful-dnd": "^13.1.8",
|
"@types/react-beautiful-dnd": "^13.1.8",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@types/react-helmet": "^6.1.11",
|
"@types/react-helmet": "^6.1.11",
|
||||||
|
"@types/react-katex": "^3.0.4",
|
||||||
|
"@types/react-latex": "^2.0.3",
|
||||||
|
"@types/react-window": "^1.8.8",
|
||||||
"@vitejs/plugin-legacy": "^5.4.1",
|
"@vitejs/plugin-legacy": "^5.4.1",
|
||||||
"@vitejs/plugin-react": "^4.3.0",
|
"@vitejs/plugin-react": "^4.3.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
|
|
|
||||||
8861
pnpm-lock.yaml
8861
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -62,6 +62,7 @@ const ImageBoxField = ({ name }: any) => {
|
||||||
fileInputRef.current.value = "";
|
fileInputRef.current.value = "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
console.log(name);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ImageBoxField">
|
<div className="ImageBoxField">
|
||||||
|
|
|
||||||
105
src/Components/CustomFields/ImageBoxField/ImageBoxFieldMemo.tsx
Normal file
105
src/Components/CustomFields/ImageBoxField/ImageBoxFieldMemo.tsx
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
import "./ImageBoxField.scss";
|
||||||
|
import { useState, useRef, useEffect,memo } from "react";
|
||||||
|
import ImageIcon from "./ImageIcon";
|
||||||
|
import ImageCancelIcon from "./ImageCancelIcon";
|
||||||
|
import { getNestedValue } from "../../../utils/getNestedValue";
|
||||||
|
import { generateImagePreview } from "./generateImagePreview";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { areFieldPropsEqual } from "../../../utils/areFieldPropsEqual";
|
||||||
|
|
||||||
|
// Helper function to generate image preview from a File
|
||||||
|
|
||||||
|
const ImageBoxFieldMemo = memo(({ form,field }: any) => {
|
||||||
|
const {values,setFieldValue} = form
|
||||||
|
const {name} = field;
|
||||||
|
const value = getNestedValue(values, name);
|
||||||
|
const [imagePreview, setImagePreview] = useState<string | null>(null);
|
||||||
|
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
||||||
|
const [t] = useTranslation();
|
||||||
|
useEffect(() => {
|
||||||
|
if (value instanceof File) {
|
||||||
|
generateImagePreview(value, setImagePreview);
|
||||||
|
} else if (typeof value === "string") {
|
||||||
|
setImagePreview(value);
|
||||||
|
} else {
|
||||||
|
setImagePreview(null);
|
||||||
|
}
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
const handleFileChange = (event: any) => {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
const maxSize = 2 * 1024 * 1024;
|
||||||
|
|
||||||
|
if (file.size > maxSize) {
|
||||||
|
alert(t('validation.File_size_exceeds_2_MB_limit.'));
|
||||||
|
event.target.value = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the file
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
generateImagePreview(file, setImagePreview);
|
||||||
|
|
||||||
|
setFieldValue(name, file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleButtonClick = () => {
|
||||||
|
const fileInput = fileInputRef.current;
|
||||||
|
if (fileInput) {
|
||||||
|
fileInput.click();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
setImagePreview("");
|
||||||
|
setFieldValue(name, null);
|
||||||
|
|
||||||
|
if (fileInputRef.current) {
|
||||||
|
fileInputRef.current.value = "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(name);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="ImageBoxField">
|
||||||
|
<div className="ImageHeader">
|
||||||
|
{imagePreview ? (
|
||||||
|
<>
|
||||||
|
<ImageCancelIcon
|
||||||
|
onClick={handleCancel}
|
||||||
|
className="ImageCancelIcon"
|
||||||
|
/>
|
||||||
|
<ImageIcon onClick={handleButtonClick} className="ImageBoxIcon" />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="VisibleHidden">hidden</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="ImageBox" onClick={handleButtonClick}>
|
||||||
|
{imagePreview ? (
|
||||||
|
<img src={imagePreview} alt="Preview" className="imagePreview" />
|
||||||
|
) : (
|
||||||
|
<ImageIcon className="ImageBoxIcon" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
id={`file-input-${name}`}
|
||||||
|
type="file"
|
||||||
|
accept="image/png, image/jpeg, image/webp"
|
||||||
|
style={{ display: "none" }}
|
||||||
|
onChange={handleFileChange}
|
||||||
|
ref={fileInputRef}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, (prevProps, nextProps) => {
|
||||||
|
return areFieldPropsEqual(prevProps, nextProps)
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ImageBoxFieldMemo;
|
||||||
14
src/Components/CustomFields/MathComponent.tsx
Normal file
14
src/Components/CustomFields/MathComponent.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react';
|
||||||
|
import 'katex/dist/katex.min.css';
|
||||||
|
import { BlockMath } from 'react-katex';
|
||||||
|
import { convertMathMLToLaTeX } from '../../utils/convertMathMLToLaTeX';
|
||||||
|
|
||||||
|
|
||||||
|
const LatexPreview = ({Latex}:{Latex:string}) => {
|
||||||
|
|
||||||
|
return(
|
||||||
|
<BlockMath math={Latex} />
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LatexPreview;
|
||||||
84
src/Components/CustomFields/SelectTagV2.tsx
Normal file
84
src/Components/CustomFields/SelectTagV2.tsx
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { Select, Spin } from "antd";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useDebounce } from "../../utils/useDebounce";
|
||||||
|
import { useGetAllTag } from "../../api/tags";
|
||||||
|
import { useFormikContext } from "formik";
|
||||||
|
|
||||||
|
const SelectTagV2: React.FC = () => {
|
||||||
|
const [searchValue, setSearchValue] = useState<string>("");
|
||||||
|
const [fieldValue, setFieldValue] = useState<string>("");
|
||||||
|
const formik = useFormikContext<any>();
|
||||||
|
|
||||||
|
// Fetch tags based on search value
|
||||||
|
const { data, isLoading } = useGetAllTag({ name: searchValue });
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
|
||||||
|
// Get selected tags from Formik
|
||||||
|
const CurrentTags = formik.values.tags ?? []; // Assuming tags are stored as array of objects
|
||||||
|
console.log(CurrentTags,"CurrentTags");
|
||||||
|
|
||||||
|
const NewShapeTags = CurrentTags?.map((item:any)=> {return item?.name ?? item })
|
||||||
|
|
||||||
|
const handleChange = (_value: any[],option:any) => {
|
||||||
|
console.log(option,"option");
|
||||||
|
const NewShapeOption = option?.map((item:any)=> {return ({name:item?.name,id:item?.id})})
|
||||||
|
console.log(NewShapeOption);
|
||||||
|
|
||||||
|
formik.setFieldValue("tags", NewShapeOption);
|
||||||
|
setSearchValue("");
|
||||||
|
setFieldValue("");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = useDebounce((value: string) => {
|
||||||
|
setSearchValue(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleBlur = () => {
|
||||||
|
setSearchValue("");
|
||||||
|
setFieldValue("");
|
||||||
|
};
|
||||||
|
|
||||||
|
const options = data?.data ?? [];
|
||||||
|
|
||||||
|
const additionalData =
|
||||||
|
options.length < 1 && searchValue.length >= 1 && !isLoading
|
||||||
|
? [{ id: searchValue, name: searchValue }]
|
||||||
|
: options;
|
||||||
|
|
||||||
|
console.log(additionalData);
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="SelectTag">
|
||||||
|
<label>{t("models.tag")}</label>
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
allowClear
|
||||||
|
style={{ width: "100%", height: "40px" }}
|
||||||
|
placeholder=""
|
||||||
|
fieldNames={{ label: "name", value: "name" }}
|
||||||
|
onChange={handleChange}
|
||||||
|
options={additionalData}
|
||||||
|
filterOption={false}
|
||||||
|
loading={isLoading}
|
||||||
|
notFoundContent={isLoading ? <Spin /> : t("practical.not_found")}
|
||||||
|
onSearch={(value) => {
|
||||||
|
handleSearch(value);
|
||||||
|
setFieldValue(value);
|
||||||
|
}}
|
||||||
|
searchValue={fieldValue}
|
||||||
|
onDropdownVisibleChange={(open) => {
|
||||||
|
if (!open) {
|
||||||
|
handleBlur();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
value={NewShapeTags}
|
||||||
|
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SelectTagV2;
|
||||||
82
src/Components/LatextInput/AddLaTexModal.tsx
Normal file
82
src/Components/LatextInput/AddLaTexModal.tsx
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
import { Modal } from 'antd'
|
||||||
|
import TextArea from 'antd/es/input/TextArea'
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { convertMathMLToLaTeX } from '../../utils/convertMathMLToLaTeX';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
const AddLaTexModal = ({name,setLatex,Latex,setIsModalOpen,isModalOpen}:{
|
||||||
|
name:string,
|
||||||
|
setLatex: (value:string)=> void,
|
||||||
|
Latex:string,
|
||||||
|
setIsModalOpen: (value:boolean)=> void ,
|
||||||
|
isModalOpen:boolean,
|
||||||
|
|
||||||
|
}) => {
|
||||||
|
const {values,setFieldValue} = useFormikContext<any>()
|
||||||
|
|
||||||
|
|
||||||
|
const handleOk = () => {
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
|
const oldValue = values?.[name];
|
||||||
|
const newLatex = convertMathMLToLaTeX(Latex);
|
||||||
|
console.log(newLatex,'Latex');
|
||||||
|
console.log(newLatex);
|
||||||
|
|
||||||
|
if(newLatex){
|
||||||
|
setFieldValue(name, oldValue + " $$ " +newLatex +" $$ ");
|
||||||
|
setLatex("")
|
||||||
|
setIsModalOpen(false);
|
||||||
|
}else{
|
||||||
|
setLatex("")
|
||||||
|
toast.error(t("validation.that_is_not_a_valid_mml"))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
setIsModalOpen(false);
|
||||||
|
setLatex("")
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChangeInputLatex = (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
|
) => {
|
||||||
|
const newValue = e.target.value;
|
||||||
|
setLatex(newValue)
|
||||||
|
};
|
||||||
|
|
||||||
|
const [t] = useTranslation()
|
||||||
|
return (
|
||||||
|
|
||||||
|
<Modal footer={false} open={isModalOpen} onOk={handleOk} onCancel={handleCancel}>
|
||||||
|
<div className='latexModal'>
|
||||||
|
<label className='mb-3'> {t("header.past_your_MMl_text")} </label>
|
||||||
|
<TextArea
|
||||||
|
size="large"
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
autoSize={{ minRows: 4, maxRows: 10 }}
|
||||||
|
style={{height:"400px"}}
|
||||||
|
onChange={handleChangeInputLatex}
|
||||||
|
value={Latex}
|
||||||
|
/>
|
||||||
|
<div className="buttons">
|
||||||
|
<div className="back_button pointer" onClick={handleCancel}>
|
||||||
|
{t("practical.cancel")}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="add_button"
|
||||||
|
onClick={handleOk}
|
||||||
|
>
|
||||||
|
{t(`practical.${ "add"}`)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AddLaTexModal
|
||||||
89
src/Components/LatextInput/EditLaTexModal.tsx
Normal file
89
src/Components/LatextInput/EditLaTexModal.tsx
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
import { Modal } from 'antd'
|
||||||
|
import TextArea from 'antd/es/input/TextArea'
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { convertMathMLToLaTeX } from '../../utils/convertMathMLToLaTeX';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import { parseTextAndLatex } from '../../utils/parseTextAndLatex';
|
||||||
|
|
||||||
|
const EditLaTexModal = ({name,setLatex,Latex,setIsModalOpen,isModalOpen}:{
|
||||||
|
name:string,
|
||||||
|
setLatex: (value:string)=> void,
|
||||||
|
Latex:any,
|
||||||
|
setIsModalOpen: (value:boolean)=> void ,
|
||||||
|
isModalOpen:boolean,
|
||||||
|
|
||||||
|
}) => {
|
||||||
|
const {values} = useFormikContext<any>()
|
||||||
|
const [Value, setValue] = useState(Latex?.text ?? Latex)
|
||||||
|
|
||||||
|
const handleOk = () => {
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
|
const oldValue = values?.[name];
|
||||||
|
const currentKey = Latex?.key ;
|
||||||
|
const Preview = parseTextAndLatex(oldValue ?? "") ;
|
||||||
|
console.log(Latex);
|
||||||
|
|
||||||
|
const newLatex = convertMathMLToLaTeX(Latex);
|
||||||
|
console.log(newLatex);
|
||||||
|
|
||||||
|
if(newLatex){
|
||||||
|
const newArray = Preview?.map((item:any,index:number)=>{
|
||||||
|
if(item?.key)
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
|
||||||
|
}else{
|
||||||
|
toast.error(t("validation.that_is_not_a_valid_mml"))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
setIsModalOpen(false);
|
||||||
|
setLatex("")
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChangeInputLatex = (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
|
) => {
|
||||||
|
const newValue = e.target.value;
|
||||||
|
console.log(newValue,"newValue");
|
||||||
|
setValue(newValue)
|
||||||
|
};
|
||||||
|
|
||||||
|
const [t] = useTranslation()
|
||||||
|
return (
|
||||||
|
|
||||||
|
<Modal footer={false} open={isModalOpen} onOk={handleOk} onCancel={handleCancel}>
|
||||||
|
<div className='latexModal'>
|
||||||
|
<label className='mb-3'> {t("header.past_your_MMl_text")} </label>
|
||||||
|
<TextArea
|
||||||
|
size="large"
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
autoSize={{ minRows: 4, maxRows: 10 }}
|
||||||
|
style={{height:"400px"}}
|
||||||
|
onChange={handleChangeInputLatex}
|
||||||
|
value={Value
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<div className="buttons">
|
||||||
|
<div className="back_button pointer" onClick={handleCancel}>
|
||||||
|
{t("practical.cancel")}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="add_button"
|
||||||
|
onClick={handleOk}
|
||||||
|
>
|
||||||
|
{t(`practical.${ "edit"}`)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EditLaTexModal
|
||||||
110
src/Components/LatextInput/LaTeXInput.tsx
Normal file
110
src/Components/LatextInput/LaTeXInput.tsx
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
import TextArea from 'antd/es/input/TextArea'
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
|
import React, { Suspense, useState } from 'react'
|
||||||
|
import { parseTextAndLatex } from '../../utils/parseTextAndLatex';
|
||||||
|
import LatexPreview from '../../Components/CustomFields/MathComponent';
|
||||||
|
import { Checkbox } from 'antd';
|
||||||
|
import { CheckboxProps } from 'antd/lib';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FaPlus } from 'react-icons/fa';
|
||||||
|
import { useObjectToEdit } from '../../zustand/ObjectToEditState';
|
||||||
|
import { TextAreaProps } from 'antd/lib/input';
|
||||||
|
import SpinContainer from '../Layout/SpinContainer';
|
||||||
|
const AddLazyModal = React.lazy(()=> import("./AddLaTexModal"));
|
||||||
|
const EditLazyModal = React.lazy(()=> import("./EditLaTexModal"));
|
||||||
|
interface ILaTeXInput extends TextAreaProps {
|
||||||
|
name:string,label:string
|
||||||
|
}
|
||||||
|
const LaTeXInput = ({name,label,...props}:ILaTeXInput) => {
|
||||||
|
|
||||||
|
|
||||||
|
const {values,setFieldValue,getFieldProps} = useFormikContext<any>()
|
||||||
|
const { ShowLatexOption } = useObjectToEdit();
|
||||||
|
const [showPreview, setShowPreview] = useState(false) ;
|
||||||
|
const value = getFieldProps(name)?.value
|
||||||
|
const handleChangeInput =
|
||||||
|
(
|
||||||
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
|
) => {
|
||||||
|
setFieldValue(name,e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Preview = parseTextAndLatex(value ?? "") ;
|
||||||
|
|
||||||
|
const onPreviewChange: CheckboxProps['onChange'] = (e) => {
|
||||||
|
const value = e.target.checked
|
||||||
|
setShowPreview(value)
|
||||||
|
};
|
||||||
|
const [t] = useTranslation()
|
||||||
|
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
||||||
|
|
||||||
|
const [Latex, setLatex] = useState<string>("")
|
||||||
|
|
||||||
|
|
||||||
|
const showModal = () => {
|
||||||
|
setIsModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const handelEditModal = (item:any)=>{
|
||||||
|
console.log(item);
|
||||||
|
|
||||||
|
setLatex(item)
|
||||||
|
setIsEditModalOpen(true)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className='LaTeXInput'>
|
||||||
|
|
||||||
|
<label htmlFor={name} className="text">
|
||||||
|
{t(`${label ? label : name}`)}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div className='LaTeXInputArea'>
|
||||||
|
<TextArea
|
||||||
|
size="large"
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
autoSize={{ minRows: 6, maxRows: 10 }}
|
||||||
|
style={{height:"400px"}}
|
||||||
|
onChange={handleChangeInput}
|
||||||
|
value={value}
|
||||||
|
{...props}
|
||||||
|
|
||||||
|
/>
|
||||||
|
{ShowLatexOption &&
|
||||||
|
<div className='LaTeXInputOptions'>
|
||||||
|
|
||||||
|
<Checkbox onChange={onPreviewChange}>{t("header.show_preview")}</Checkbox>
|
||||||
|
<button type='button' className='addMML' onClick={showModal}> <FaPlus/> {t("MML")} </button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
}
|
||||||
|
{showPreview &&
|
||||||
|
<div className='showPreviewInput'>
|
||||||
|
{Preview?.map((item:any,index:number)=>{
|
||||||
|
if(item?.isLatex){
|
||||||
|
return <div key={index} onClick={()=>handelEditModal(item)} className='LatexPreview'> <LatexPreview Latex={item?.text} /> </div>
|
||||||
|
}
|
||||||
|
return <div key={index}>
|
||||||
|
{item?.text}
|
||||||
|
</div>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<Suspense fallback={<SpinContainer/>}>
|
||||||
|
<AddLazyModal name={name} Latex={Latex} isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} setLatex={setLatex} />
|
||||||
|
|
||||||
|
<EditLazyModal name={name} Latex={Latex} isModalOpen={isEditModalOpen} setIsModalOpen={setIsEditModalOpen} setLatex={setLatex} />
|
||||||
|
</Suspense>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LaTeXInput
|
||||||
106
src/Components/LatextInput/LaTeXInputMemo.tsx
Normal file
106
src/Components/LatextInput/LaTeXInputMemo.tsx
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
import TextArea from 'antd/es/input/TextArea';
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
|
import React, { Suspense, useState } from 'react';
|
||||||
|
import { parseTextAndLatex } from '../../utils/parseTextAndLatex';
|
||||||
|
import LatexPreview from '../CustomFields/MathComponent';
|
||||||
|
import { Checkbox } from 'antd';
|
||||||
|
import { CheckboxProps } from 'antd/lib';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FaPlus } from 'react-icons/fa';
|
||||||
|
import { useObjectToEdit } from '../../zustand/ObjectToEditState';
|
||||||
|
import SpinContainer from '../Layout/SpinContainer';
|
||||||
|
import { areFieldPropsEqual } from './areFieldPropsEqual';
|
||||||
|
|
||||||
|
const AddLazyModal = React.lazy(() => import("./AddLaTexModal"));
|
||||||
|
const EditLazyModal = React.lazy(() => import("./EditLaTexModal"));
|
||||||
|
|
||||||
|
|
||||||
|
const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...props }) => {
|
||||||
|
const { name ,value} = field;
|
||||||
|
|
||||||
|
const { setFieldValue } = form;
|
||||||
|
|
||||||
|
const { ShowLatexOption } = useObjectToEdit();
|
||||||
|
const [showPreview, setShowPreview] = useState(false);
|
||||||
|
|
||||||
|
const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
setFieldValue(name, e.target.value);
|
||||||
|
};
|
||||||
|
console.log(name,"name");
|
||||||
|
|
||||||
|
const Preview = parseTextAndLatex(value ?? "");
|
||||||
|
|
||||||
|
const onPreviewChange: CheckboxProps['onChange'] = (e) => {
|
||||||
|
setShowPreview(e.target.checked);
|
||||||
|
};
|
||||||
|
|
||||||
|
const [t] = useTranslation();
|
||||||
|
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
||||||
|
const [Latex, setLatex] = useState<string>("");
|
||||||
|
|
||||||
|
const showModal = () => {
|
||||||
|
setIsModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEditModal = (item: any) => {
|
||||||
|
console.log(item);
|
||||||
|
setLatex(item);
|
||||||
|
setIsEditModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='LaTeXInput'>
|
||||||
|
<label htmlFor={name} className="text">
|
||||||
|
{t(label || name)}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div className='LaTeXInputArea'>
|
||||||
|
<TextArea
|
||||||
|
size="large"
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
autoSize={{ minRows: 6, maxRows: 10 }}
|
||||||
|
style={{ height: "400px" }}
|
||||||
|
onChange={handleChangeInput}
|
||||||
|
value={value}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{ShowLatexOption && (
|
||||||
|
<div className='LaTeXInputOptions'>
|
||||||
|
<Checkbox onChange={onPreviewChange}>{t("header.show_preview")}</Checkbox>
|
||||||
|
<button type='button' className='addMML' onClick={showModal}>
|
||||||
|
<FaPlus/> {t("MML")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showPreview && (
|
||||||
|
<div className='showPreviewInput'>
|
||||||
|
{Preview?.map((item: any, index: number) => {
|
||||||
|
if (item?.isLatex) {
|
||||||
|
return (
|
||||||
|
<div key={index} onClick={() => handleEditModal(item)} className='LatexPreview'>
|
||||||
|
<LatexPreview Latex={item?.text} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <div key={index}>{item?.text}</div>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Suspense fallback={<SpinContainer />}>
|
||||||
|
<AddLazyModal name={name} Latex={Latex} isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} setLatex={setLatex} />
|
||||||
|
<EditLazyModal name={name} Latex={Latex} isModalOpen={isEditModalOpen} setIsModalOpen={setIsEditModalOpen} setLatex={setLatex} />
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, (prevProps, nextProps) => {
|
||||||
|
return areFieldPropsEqual(prevProps, nextProps)
|
||||||
|
});
|
||||||
|
|
||||||
|
export default LaTeXInputMemo;
|
||||||
23
src/Components/LatextInput/areFieldPropsEqual.ts
Normal file
23
src/Components/LatextInput/areFieldPropsEqual.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
// utilityFunctions.ts
|
||||||
|
import { FieldProps } from 'formik';
|
||||||
|
|
||||||
|
export const areFieldPropsEqual = (
|
||||||
|
prevProps: any,
|
||||||
|
nextProps: any
|
||||||
|
): boolean => {
|
||||||
|
const prevError = prevProps.form.errors[prevProps.field.name];
|
||||||
|
const nextError = nextProps.form.errors[nextProps.field.name];
|
||||||
|
|
||||||
|
const prevTouched = prevProps.form.touched[prevProps.field.name];
|
||||||
|
const nextTouched = nextProps.form.touched[nextProps.field.name];
|
||||||
|
|
||||||
|
const prevValue = prevProps.field.value;
|
||||||
|
const nextValue = nextProps.field.value;
|
||||||
|
|
||||||
|
return (
|
||||||
|
prevValue === nextValue
|
||||||
|
&&
|
||||||
|
prevError === nextError &&
|
||||||
|
prevTouched === nextTouched
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -11,6 +11,7 @@ import {
|
||||||
SearchField,
|
SearchField,
|
||||||
TextField,
|
TextField,
|
||||||
DropFile,
|
DropFile,
|
||||||
|
TextAreaMML,
|
||||||
Default,
|
Default,
|
||||||
} from "./View";
|
} from "./View";
|
||||||
import { ValidationFieldProps, ValidationFieldType } from "./utils/types";
|
import { ValidationFieldProps, ValidationFieldType } from "./utils/types";
|
||||||
|
|
@ -23,6 +24,7 @@ const components: { [key: string]: React.FC<any> } = {
|
||||||
LocalSearch: LocalSearchField,
|
LocalSearch: LocalSearchField,
|
||||||
DataRange: DataRange,
|
DataRange: DataRange,
|
||||||
TextArea: TextField,
|
TextArea: TextField,
|
||||||
|
TextAreaMML: TextAreaMML,
|
||||||
Date: Date,
|
Date: Date,
|
||||||
Time: Time,
|
Time: Time,
|
||||||
File: File,
|
File: File,
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ const TextField = ({
|
||||||
|
|
||||||
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||||
<Field
|
<Field
|
||||||
as={TextArea}
|
as={TextArea}
|
||||||
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
||||||
name={name}
|
name={name}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
|
|
|
||||||
61
src/Components/ValidationField/View/TextFieldMML.tsx
Normal file
61
src/Components/ValidationField/View/TextFieldMML.tsx
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { Input } from "antd";
|
||||||
|
import React from "react";
|
||||||
|
import useFormField from "../../../Hooks/useFormField";
|
||||||
|
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
|
||||||
|
import { ValidationFieldContainer } from "../components/ValidationFieldContainer";
|
||||||
|
import LatexPreview from "../../CustomFields/MathComponent";
|
||||||
|
const { TextArea } = Input;
|
||||||
|
|
||||||
|
const TextFieldMML = ({
|
||||||
|
name,
|
||||||
|
label,
|
||||||
|
placeholder,
|
||||||
|
isDisabled,
|
||||||
|
onChange,
|
||||||
|
no_label,
|
||||||
|
label_icon,
|
||||||
|
className,
|
||||||
|
mathContent, // Add mathContent prop
|
||||||
|
...props
|
||||||
|
}: any) => {
|
||||||
|
const { formik, isError, errorMsg, t } = useFormField(name, props);
|
||||||
|
|
||||||
|
const TextFilehandleChange = (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
|
) => {
|
||||||
|
formik.setFieldValue(name, e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`ValidationField w-100 ${className ?? ""} `}>
|
||||||
|
<ValidationFieldLabel
|
||||||
|
name={name}
|
||||||
|
label={label}
|
||||||
|
label_icon={label_icon}
|
||||||
|
no_label={no_label}
|
||||||
|
placeholder={placeholder}
|
||||||
|
t={t}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ValidationFieldContainer isError={isError} errorMsg={errorMsg}>
|
||||||
|
<TextArea
|
||||||
|
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
||||||
|
name={name}
|
||||||
|
disabled={isDisabled}
|
||||||
|
size="large"
|
||||||
|
showCount
|
||||||
|
maxLength={1000}
|
||||||
|
autoSize={{ minRows: 4, maxRows: 10 }}
|
||||||
|
onChange={onChange || TextFilehandleChange}
|
||||||
|
id={name}
|
||||||
|
{...props}
|
||||||
|
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
</ValidationFieldContainer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(TextFieldMML);
|
||||||
|
|
@ -9,6 +9,7 @@ import MaltyFile from "./MaltyFile";
|
||||||
import SearchField from "./SearchField";
|
import SearchField from "./SearchField";
|
||||||
import TextField from "./TextField";
|
import TextField from "./TextField";
|
||||||
import DropFile from "./DropFile.tsx";
|
import DropFile from "./DropFile.tsx";
|
||||||
|
import TextAreaMML from "./TextFieldMML";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Time,
|
Time,
|
||||||
|
|
@ -22,4 +23,5 @@ export {
|
||||||
SearchField,
|
SearchField,
|
||||||
TextField,
|
TextField,
|
||||||
DropFile,
|
DropFile,
|
||||||
|
TextAreaMML
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ export type FieldProps = BaseFieldProps &
|
||||||
| "password"
|
| "password"
|
||||||
| "email"
|
| "email"
|
||||||
| "TextArea"
|
| "TextArea"
|
||||||
|
| "TextAreaMML"
|
||||||
| "NumberFormate";
|
| "NumberFormate";
|
||||||
label2?: string;
|
label2?: string;
|
||||||
Group?: boolean;
|
Group?: boolean;
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,12 @@ import { Checkbox, CheckboxProps, Popconfirm, Popover } from "antd";
|
||||||
import { CombinationKeyEnum } from "../../enums/CombinationKeyEnum";
|
import { CombinationKeyEnum } from "../../enums/CombinationKeyEnum";
|
||||||
import { PopconfirmProps } from "antd/lib";
|
import { PopconfirmProps } from "antd/lib";
|
||||||
import { SettingFilled } from "@ant-design/icons";
|
import { SettingFilled } from "@ant-design/icons";
|
||||||
|
import { LocalStorageEnum } from "../../enums/LocalStorageEnum";
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const { values, setValues } = useFormikContext<any>();
|
const { values, setValues } = useFormikContext<any>();
|
||||||
const { isBseQuestion, setIsBseQuestion,ShowHint,setShowHint } = useObjectToEdit();
|
const { isBseQuestion, setIsBseQuestion,ShowHint,setShowHint,ShowLatexOption,setShowLatexOption } = useObjectToEdit();
|
||||||
// const [Setting, setSetting] = useState(false)
|
// const [Setting, setSetting] = useState(false)
|
||||||
const isEdited = ()=>{
|
const isEdited = ()=>{
|
||||||
|
|
||||||
|
|
@ -73,24 +74,32 @@ const Header = () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const handleOpenChange = (newOpen: boolean) => {
|
const onChangeHint: CheckboxProps['onChange'] = (e) => {
|
||||||
// setSetting(newOpen);
|
|
||||||
};
|
|
||||||
const onChange: CheckboxProps['onChange'] = (e) => {
|
|
||||||
setShowHint(e.target.checked);
|
setShowHint(e.target.checked);
|
||||||
|
localStorage?.setItem(LocalStorageEnum.HINT_INPUT,e.target.checked ? "true" : "false" )
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangeLatexOption: CheckboxProps['onChange'] = (e) => {
|
||||||
|
setShowLatexOption(e.target.checked);
|
||||||
|
localStorage?.setItem(LocalStorageEnum.LATEX_OPTION_INPUT,e.target.checked ? "true" : "false" )
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const contentSetting = (
|
const contentSetting = (
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<Checkbox checked={ShowHint} onChange={onChange}>
|
<Checkbox checked={ShowHint} onChange={onChangeHint}>
|
||||||
{ t("header.show_hint")}
|
{ t("header.show_hint")}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
|
|
||||||
|
<Checkbox checked={ShowLatexOption} onChange={onChangeLatexOption}>
|
||||||
|
{ t("header.show_MMl")}
|
||||||
|
</Checkbox>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="exercise_add_header mb-4">
|
<header className="exercise_add_header mb-4">
|
||||||
<article>
|
<article>
|
||||||
|
|
@ -105,7 +114,7 @@ const Header = () => {
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<div className="question_header_setting">
|
<div className="question_header_setting">
|
||||||
<Popover onOpenChange={handleOpenChange} trigger="click" content={contentSetting}>
|
<Popover trigger="click" content={contentSetting}>
|
||||||
<SettingFilled/>
|
<SettingFilled/>
|
||||||
|
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ export const useColumns = () => {
|
||||||
key: "name",
|
key: "name",
|
||||||
align: "center",
|
align: "center",
|
||||||
render: (_text, record) => record?.name,
|
render: (_text, record) => record?.name,
|
||||||
|
ellipsis:true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("columns.image"),
|
title: t("columns.image"),
|
||||||
|
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
import React, { useState, useMemo } from "react";
|
|
||||||
import { Select, Spin } from "antd";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { useFormikContext } from "formik";
|
|
||||||
import { useDebounce } from "../../../../utils/useDebounce";
|
|
||||||
import { useGetAllTag } from "../../../../api/tags";
|
|
||||||
|
|
||||||
const SelectTag: React.FC = () => {
|
|
||||||
const [searchValue, setSearchValue] = useState<string>("");
|
|
||||||
|
|
||||||
const [fieldValue, setFieldValue] = useState<string>("");
|
|
||||||
const formik = useFormikContext<any>();
|
|
||||||
const handleChange = (value: string[]) => {
|
|
||||||
console.log(value,"value");
|
|
||||||
|
|
||||||
formik.setFieldValue("tags", value);
|
|
||||||
setSearchValue("");
|
|
||||||
setFieldValue("");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSearch = useDebounce((value: string) => {
|
|
||||||
setSearchValue(value);
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleFieldChange = (value: string) => {
|
|
||||||
setFieldValue(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBlur = () => {
|
|
||||||
setSearchValue("");
|
|
||||||
setFieldValue("");
|
|
||||||
};
|
|
||||||
|
|
||||||
const { data, isLoading } = useGetAllTag({
|
|
||||||
name: searchValue,
|
|
||||||
});
|
|
||||||
|
|
||||||
const [t] = useTranslation();
|
|
||||||
|
|
||||||
const options = data?.data ?? [];
|
|
||||||
const additionalData =
|
|
||||||
options.length < 1 && searchValue.length > 1 && !isLoading
|
|
||||||
? [{ id: searchValue, name: searchValue }]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const value =
|
|
||||||
formik?.values?.tags?.map((item: any) => item?.id ?? item) ?? [];
|
|
||||||
|
|
||||||
const AllOptions = [...options, ...additionalData];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="SelectTag">
|
|
||||||
<label htmlFor="">{t("models.tag")}</label>
|
|
||||||
<Select
|
|
||||||
mode="multiple"
|
|
||||||
allowClear
|
|
||||||
style={{ width: "100%", height: "40px" }}
|
|
||||||
placeholder=""
|
|
||||||
fieldNames={{ label: "name", value: "id" }}
|
|
||||||
onChange={handleChange}
|
|
||||||
options={AllOptions}
|
|
||||||
filterOption={false}
|
|
||||||
loading={isLoading}
|
|
||||||
notFoundContent={isLoading ? <Spin /> : t("practical.not_found")}
|
|
||||||
onSearch={(value) => {
|
|
||||||
handleSearch(value);
|
|
||||||
handleFieldChange(value);
|
|
||||||
}}
|
|
||||||
searchValue={fieldValue}
|
|
||||||
onDropdownVisibleChange={(open) => {
|
|
||||||
if (!open) {
|
|
||||||
handleBlur();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
value={value}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SelectTag;
|
|
||||||
|
|
@ -34,6 +34,7 @@ export const useColumns = () => {
|
||||||
dataIndex: "name",
|
dataIndex: "name",
|
||||||
key: "name",
|
key: "name",
|
||||||
align: "center",
|
align: "center",
|
||||||
|
ellipsis:true
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ export const useColumns = () => {
|
||||||
key: "name",
|
key: "name",
|
||||||
align: "center",
|
align: "center",
|
||||||
render: (text) => text,
|
render: (text) => text,
|
||||||
|
ellipsis:true
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ export const useColumns = () => {
|
||||||
key: "name",
|
key: "name",
|
||||||
align: "center",
|
align: "center",
|
||||||
render: (text, record) => record?.name,
|
render: (text, record) => record?.name,
|
||||||
|
ellipsis:true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// canAddLesson ? (
|
// canAddLesson ? (
|
||||||
|
|
|
||||||
|
|
@ -20,20 +20,19 @@ import ModelForm from "./Model/ModelForm";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { Form, Formik } from "formik";
|
import { Form, Formik } from "formik";
|
||||||
import { MdOutlineArrowForwardIos } from "react-icons/md";
|
import { MdOutlineArrowForwardIos } from "react-icons/md";
|
||||||
import { getCharFromNumber } from "../../../utils/getCharFromNumber";
|
|
||||||
|
|
||||||
const AddPage: React.FC = () => {
|
const AddPage: React.FC = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
const { mutateAsync,isLoading:LoadingAsync } = useAddQuestionAsync();
|
const { mutateAsync,isLoading:LoadingAsync } = useAddQuestionAsync();
|
||||||
const { mutate, isLoading, isSuccess } = useAddQuestion();
|
const { mutate, isLoading, isSuccess } = useAddQuestion();
|
||||||
const { isBseQuestion, setTagsSearch, setSuccess , ShowHint,setShowHint } =
|
const { isBseQuestion, setTagsSearch, setSuccess } =
|
||||||
useObjectToEdit();
|
useObjectToEdit();
|
||||||
|
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const { subject_id, lesson_id } = useParams<ParamsEnum>();
|
const { subject_id, lesson_id } = useParams<ParamsEnum>();
|
||||||
|
|
||||||
const handleSubmit = ( values: any) => {
|
const handleFormSubmit = ( values: any) => {
|
||||||
const DataToSend = structuredClone(values);
|
const DataToSend = structuredClone(values);
|
||||||
setTagsSearch(null);
|
setTagsSearch(null);
|
||||||
|
|
||||||
|
|
@ -100,14 +99,14 @@ const AddPage: React.FC = () => {
|
||||||
mutate(NewQuestion);
|
mutate(NewQuestion);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleValidateSingleQuestion = (values:any)=>{
|
|
||||||
|
const handleValidateSingleQuestion = (values:any,isValid:boolean,handleSubmit:any)=>{
|
||||||
const haveMoreThanOneAnswer = values?.answers?.length > 1;
|
const haveMoreThanOneAnswer = values?.answers?.length > 1;
|
||||||
const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true )
|
const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true )
|
||||||
const haveImageOrContent = haveOneAnswerRight && values?.answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
const haveImageOrContent = haveOneAnswerRight && values?.answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
||||||
const content = values.content ;
|
const content = values.content ;
|
||||||
const content_image = values.content_image ;
|
const content_image = values.content_image ;
|
||||||
const haveContentOrContentImage = !!content || !!content_image ;
|
const haveContentOrContentImage = !!content || !!content_image ;
|
||||||
|
|
||||||
console.log(haveImageOrContent,"haveImageOrContent");
|
console.log(haveImageOrContent,"haveImageOrContent");
|
||||||
if(!haveContentOrContentImage){
|
if(!haveContentOrContentImage){
|
||||||
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
||||||
|
|
@ -123,22 +122,30 @@ const AddPage: React.FC = () => {
|
||||||
return false ;
|
return false ;
|
||||||
}
|
}
|
||||||
if(haveImageOrContent){
|
if(haveImageOrContent){
|
||||||
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer_in_answer"))
|
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
|
if(isValid){
|
||||||
|
handleSubmit(values)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
const handleValidateBaseQuestion = (values: any) => {
|
const handleValidateBaseQuestion = (values: any,isValid:boolean,handleSubmit:any) => {
|
||||||
const content = values.content ;
|
const content = values.content ;
|
||||||
const content_image = values.content_image ;
|
const content_image = values.content_image ;
|
||||||
const haveContentOrContentImage = !!content || !!content_image ;
|
const haveContentOrContentImage = !!content || !!content_image ;
|
||||||
|
console.log(2);
|
||||||
|
|
||||||
if(!haveContentOrContentImage){
|
if(!haveContentOrContentImage){
|
||||||
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
values?.Questions?.every((Question: any, QuestionsIndex: number) => {
|
const isValidate = values?.Questions?.every((Question: any, QuestionsIndex: number) => {
|
||||||
|
|
||||||
|
|
||||||
const content = Question.content ;
|
const content = Question.content ;
|
||||||
|
|
@ -180,9 +187,15 @@ const AddPage: React.FC = () => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
|
if(isValid && isValidate){
|
||||||
|
console.log(2);
|
||||||
|
handleSubmit(values)
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -213,12 +226,13 @@ const AddPage: React.FC = () => {
|
||||||
|
|
||||||
<div className="exercise_add">
|
<div className="exercise_add">
|
||||||
<Formik
|
<Formik
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleFormSubmit}
|
||||||
initialValues={getInitialValuesBase({} as any)}
|
initialValues={getInitialValuesBase({} as any)}
|
||||||
validationSchema={getValidationSchemaBase}
|
validationSchema={getValidationSchemaBase}
|
||||||
enableReinitialize
|
enableReinitialize
|
||||||
|
|
||||||
>
|
>
|
||||||
{({ values,handleSubmit }) => (
|
{({ values,isValid,handleSubmit }) => (
|
||||||
|
|
||||||
<Form className="w-100">
|
<Form className="w-100">
|
||||||
<main className="w-100 exercise_add_main">
|
<main className="w-100 exercise_add_main">
|
||||||
|
|
@ -227,9 +241,9 @@ const AddPage: React.FC = () => {
|
||||||
|
|
||||||
<div className="exercise_add_buttons">
|
<div className="exercise_add_buttons">
|
||||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||||
<button disabled={Loading} className="relative" type="submit"
|
<button disabled={Loading} className="relative" type="button"
|
||||||
onClick={()=>{handleValidateBaseQuestion(values) ;handleSubmit(values)}}
|
onClick={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
|
||||||
onSubmit={()=>{handleValidateBaseQuestion(values) ;handleSubmit(values) }}
|
onSubmit={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
|
||||||
>
|
>
|
||||||
{t("practical.add")}
|
{t("practical.add")}
|
||||||
|
|
||||||
|
|
@ -262,11 +276,12 @@ const AddPage: React.FC = () => {
|
||||||
enableReinitialize={true}
|
enableReinitialize={true}
|
||||||
initialValues={getInitialValues({} as any)}
|
initialValues={getInitialValues({} as any)}
|
||||||
validationSchema={getValidationSchema}
|
validationSchema={getValidationSchema}
|
||||||
|
validateOnMount={true}
|
||||||
onSubmit={(values) => {
|
onSubmit={(values) => {
|
||||||
handleSubmit(values);
|
handleFormSubmit(values);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ values,handleSubmit }) => (
|
{({ values,isValid ,handleSubmit}) => (
|
||||||
<Form className="w-100">
|
<Form className="w-100">
|
||||||
<main className="w-100 exercise_add_main">
|
<main className="w-100 exercise_add_main">
|
||||||
<Header />
|
<Header />
|
||||||
|
|
@ -274,12 +289,9 @@ const AddPage: React.FC = () => {
|
||||||
|
|
||||||
<div className="exercise_add_buttons">
|
<div className="exercise_add_buttons">
|
||||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||||
<button
|
<div
|
||||||
disabled={Loading}
|
|
||||||
className="relative"
|
className="relative"
|
||||||
onClick={()=>{handleValidateSingleQuestion(values) ;handleSubmit(values)}}
|
onClick={()=>{ Loading ? ()=>{} : handleValidateSingleQuestion(values,isValid,handleSubmit) }}
|
||||||
onSubmit={()=>{handleValidateSingleQuestion(values) ;handleSubmit(values) }}
|
|
||||||
type="submit"
|
|
||||||
>
|
>
|
||||||
{t("practical.add")}
|
{t("practical.add")}
|
||||||
|
|
||||||
|
|
@ -288,7 +300,7 @@ const AddPage: React.FC = () => {
|
||||||
<Spin />
|
<Spin />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,11 @@ import { Form, Formik } from "formik";
|
||||||
import { MdOutlineArrowForwardIos } from "react-icons/md";
|
import { MdOutlineArrowForwardIos } from "react-icons/md";
|
||||||
import { SettingFilled } from "@ant-design/icons";
|
import { SettingFilled } from "@ant-design/icons";
|
||||||
import { CheckboxProps } from "antd/lib";
|
import { CheckboxProps } from "antd/lib";
|
||||||
|
import { LocalStorageEnum } from "../../../enums/LocalStorageEnum";
|
||||||
|
|
||||||
const EditPage: React.FC = () => {
|
const EditPage: React.FC = () => {
|
||||||
const { subject_id, lesson_id, question_id } = useParams<ParamsEnum>();
|
const { subject_id, lesson_id, question_id } = useParams<ParamsEnum>();
|
||||||
const { isBseQuestion, setIsBseQuestion, setTagsSearch, DeletedQuestions , ShowHint,setShowHint } =
|
const { isBseQuestion, setIsBseQuestion, setTagsSearch, DeletedQuestions , ShowHint,setShowHint , ShowLatexOption,setShowLatexOption } =
|
||||||
useObjectToEdit();
|
useObjectToEdit();
|
||||||
|
|
||||||
const { mutate, isSuccess, isLoading } = useUpdateQuestion();
|
const { mutate, isSuccess, isLoading } = useUpdateQuestion();
|
||||||
|
|
@ -45,6 +46,7 @@ const EditPage: React.FC = () => {
|
||||||
const { data: Questions, isLoading: QuestionsDataLoading } =
|
const { data: Questions, isLoading: QuestionsDataLoading } =
|
||||||
useGetAllQuestion({
|
useGetAllQuestion({
|
||||||
parent_id: question_id,
|
parent_id: question_id,
|
||||||
|
isPaginated:false
|
||||||
});
|
});
|
||||||
|
|
||||||
const objectToEdit = { ...data?.data, Questions: Questions?.data };
|
const objectToEdit = { ...data?.data, Questions: Questions?.data };
|
||||||
|
|
@ -189,20 +191,19 @@ const EditPage: React.FC = () => {
|
||||||
navigate(-1);
|
navigate(-1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleValidateSingleQuestion = (values:any,isValid:boolean,handleSubmit:any)=>{
|
||||||
const handleValidateSingleQuestion = (values:any)=>{
|
|
||||||
const haveMoreThanOneAnswer = values?.answers?.length > 1;
|
const haveMoreThanOneAnswer = values?.answers?.length > 1;
|
||||||
const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true )
|
const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true )
|
||||||
const haveImageOrContent = haveOneAnswerRight && values?.answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
const haveImageOrContent = haveOneAnswerRight && values?.answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
||||||
const content = values.content ;
|
const content = values.content ;
|
||||||
const content_image = values.content_image ;
|
const content_image = values.content_image ;
|
||||||
const haveContentOrContentImage = !!content || !!content_image ;
|
const haveContentOrContentImage = !!content || !!content_image ;
|
||||||
|
|
||||||
console.log(haveImageOrContent,"haveImageOrContent");
|
console.log(haveImageOrContent,"haveImageOrContent");
|
||||||
if(!haveContentOrContentImage){
|
if(!haveContentOrContentImage){
|
||||||
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!haveMoreThanOneAnswer){
|
if(!haveMoreThanOneAnswer){
|
||||||
toast.error(t("validation.it_should_have_more_than_one_answers")) ;
|
toast.error(t("validation.it_should_have_more_than_one_answers")) ;
|
||||||
return false ;
|
return false ;
|
||||||
|
|
@ -216,10 +217,26 @@ const EditPage: React.FC = () => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
console.log(1);
|
||||||
|
|
||||||
const handleValidateBaseQuestion = (values: any) => {
|
if(isValid){
|
||||||
const haveAnswers = values?.Questions?.every((Question: any, QuestionsIndex: number) => {
|
handleSubmit(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
const handleValidateBaseQuestion = (values: any,isValid:boolean,handleSubmit:any) => {
|
||||||
|
const content = values.content ;
|
||||||
|
const content_image = values.content_image ;
|
||||||
|
const haveContentOrContentImage = !!content || !!content_image ;
|
||||||
|
console.log(2);
|
||||||
|
|
||||||
|
if(!haveContentOrContentImage){
|
||||||
|
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
|
const isValidate = values?.Questions?.every((Question: any, QuestionsIndex: number) => {
|
||||||
|
|
||||||
|
|
||||||
const content = Question.content ;
|
const content = Question.content ;
|
||||||
|
|
@ -231,13 +248,15 @@ const handleValidateBaseQuestion = (values: any) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//// answers
|
//// answers
|
||||||
const answers = Question?.answers;
|
const answers = Question?.answers;
|
||||||
const haveAnswers = answers?.length > 0;
|
const haveAnswers = answers?.length > 0;
|
||||||
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
|
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
|
||||||
const haveOneAnswerRight =
|
const haveOneAnswerRight = haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true);
|
||||||
haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true);
|
const haveImageOrContent = haveOneAnswerRight && answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
||||||
const haveImageOrContent = haveOneAnswerRight && answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!haveAnswers) {
|
if (!haveAnswers) {
|
||||||
toast.error(t("validation.it_should_have_more_than_one_answers"));
|
toast.error(t("validation.it_should_have_more_than_one_answers"));
|
||||||
|
|
@ -259,13 +278,17 @@ const handleValidateBaseQuestion = (values: any) => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(haveAnswers, "haveAnswers");
|
console.log(1);
|
||||||
};
|
|
||||||
|
|
||||||
|
if(isValid && isValidate){
|
||||||
|
console.log(2);
|
||||||
|
handleSubmit(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
const handleNavigateToPage = () => {
|
const handleNavigateToPage = () => {
|
||||||
const cleanedUrl = location.pathname.replace(/\/Question\/\d+$/, "");
|
const cleanedUrl = location.pathname.replace(/\/Question\/\d+$/, "");
|
||||||
|
|
@ -279,17 +302,29 @@ const handleNavigateToPage = () => {
|
||||||
}
|
}
|
||||||
}, [isSuccess]);
|
}, [isSuccess]);
|
||||||
|
|
||||||
const onChange: CheckboxProps['onChange'] = (e) => {
|
const onChangeHint: CheckboxProps['onChange'] = (e) => {
|
||||||
setShowHint(e.target.checked);
|
setShowHint(e.target.checked);
|
||||||
|
localStorage?.setItem(LocalStorageEnum.HINT_INPUT,e.target.checked ? "true" : "false" )
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onChangeLatexOption: CheckboxProps['onChange'] = (e) => {
|
||||||
|
setShowLatexOption(e.target.checked);
|
||||||
|
localStorage?.setItem(LocalStorageEnum.LATEX_OPTION_INPUT,e.target.checked ? "true" : "false" )
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const contentSetting = (
|
const contentSetting = (
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<Checkbox checked={ShowHint} onChange={onChange}>
|
<Checkbox checked={ShowHint} onChange={onChangeHint}>
|
||||||
{ t("header.show_hint")}
|
{ t("header.show_hint")}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
|
|
||||||
|
<Checkbox checked={ShowLatexOption} onChange={onChangeLatexOption}>
|
||||||
|
{ t("header.show_MMl")}
|
||||||
|
</Checkbox>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -316,7 +351,7 @@ const handleNavigateToPage = () => {
|
||||||
validationSchema={getValidationSchemaBase}
|
validationSchema={getValidationSchemaBase}
|
||||||
enableReinitialize
|
enableReinitialize
|
||||||
>
|
>
|
||||||
{({ values,handleSubmit }) => (
|
{({ values,isValid,handleSubmit }) => (
|
||||||
|
|
||||||
<Form className="w-100">
|
<Form className="w-100">
|
||||||
<main className="w-100 exercise_add_main">
|
<main className="w-100 exercise_add_main">
|
||||||
|
|
@ -336,10 +371,10 @@ const handleNavigateToPage = () => {
|
||||||
<BaseForm />
|
<BaseForm />
|
||||||
<div className="exercise_add_buttons">
|
<div className="exercise_add_buttons">
|
||||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||||
<button disabled={Loading} className="relative" type="submit"
|
<button disabled={Loading} className="relative" type="button"
|
||||||
onClick={()=>{handleValidateBaseQuestion(values) ;handleSubmit(values)}}
|
onClick={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
|
||||||
onSubmit={()=>{handleValidateBaseQuestion(values) ;handleSubmit(values) }}
|
onSubmit={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
|
||||||
> {t("practical.edit")}
|
> {t("practical.edit")}
|
||||||
|
|
||||||
{Loading && (
|
{Loading && (
|
||||||
<span className="Spinier_Div">
|
<span className="Spinier_Div">
|
||||||
|
|
@ -375,7 +410,7 @@ const handleNavigateToPage = () => {
|
||||||
handleSubmit(values);
|
handleSubmit(values);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ values,handleSubmit , dirty }) => (
|
{({ values , dirty,isValid,handleSubmit }) => (
|
||||||
<Form className="w-100">
|
<Form className="w-100">
|
||||||
<main className="w-100 exercise_add_main">
|
<main className="w-100 exercise_add_main">
|
||||||
{/* <Header/> */}
|
{/* <Header/> */}
|
||||||
|
|
@ -383,25 +418,28 @@ const handleNavigateToPage = () => {
|
||||||
<div>
|
<div>
|
||||||
{t("practical.edit")} {t("models.exercise")}{" "}
|
{t("practical.edit")} {t("models.exercise")}{" "}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="SettingEdit">
|
||||||
|
|
||||||
|
<Popover trigger="click" content={contentSetting}>
|
||||||
|
<SettingFilled/>
|
||||||
|
|
||||||
|
</Popover>
|
||||||
<div>{t("header.exercise")}</div>
|
<div>{t("header.exercise")}</div>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<ModelForm />
|
<ModelForm />
|
||||||
<div className="exercise_add_buttons">
|
<div className="exercise_add_buttons">
|
||||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||||
<button
|
<div
|
||||||
disabled={Loading || !dirty}
|
|
||||||
className="relative"
|
className="relative"
|
||||||
onClick={()=>{handleValidateSingleQuestion(values) ;handleSubmit(values)}}
|
onClick={()=>{ Loading ? ()=>{} : handleValidateSingleQuestion(values,isValid,handleSubmit) }}
|
||||||
onSubmit={()=>{handleValidateSingleQuestion(values) ;handleSubmit(values) }}
|
> {t("practical.edit")}
|
||||||
type="submit"
|
|
||||||
|
|
||||||
> {t("practical.edit")}
|
|
||||||
{Loading && (
|
{Loading && (
|
||||||
<span className="Spinier_Div">
|
<span className="Spinier_Div">
|
||||||
<Spin />
|
<Spin />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Choice } from "../../../../../types/Item";
|
import { Choice } from "../../../../../types/Item";
|
||||||
import ValidationField from "../../../../../Components/ValidationField/ValidationField";
|
import ValidationField from "../../../../../Components/ValidationField/ValidationField";
|
||||||
import { useFormikContext } from "formik";
|
import { Field, useFormikContext } from "formik";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { getCharFromNumber } from "../../../../../utils/getCharFromNumber";
|
|
||||||
import CheckboxField from "./CheckboxField";
|
import CheckboxField from "./CheckboxField";
|
||||||
import TextField from "./TextField";
|
|
||||||
import ImageBoxField from "../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
|
||||||
import { GoTrash } from "react-icons/go";
|
import { GoTrash } from "react-icons/go";
|
||||||
import { Popconfirm } from "antd";
|
import { Popconfirm } from "antd";
|
||||||
import { useObjectToEdit } from "../../../../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../../../../zustand/ObjectToEditState";
|
||||||
|
import LaTeXInputMemo from "../../../../../Components/LatextInput/LaTeXInputMemo";
|
||||||
|
import ImageBoxFieldMemo from "../../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo";
|
||||||
|
|
||||||
const ChoiceFields = ({ index }: { index: number; data: Choice }) => {
|
const ChoiceFields = ({ index }: { index: number; data: Choice }) => {
|
||||||
const formik = useFormikContext<any>();
|
const formik = useFormikContext<any>();
|
||||||
|
|
@ -43,21 +42,14 @@ const ChoiceFields = ({ index }: { index: number; data: Choice }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div id={`ChoiceField_${index}`} className="ChoiceFields">
|
<div id={`ChoiceField_${index}`} className="ChoiceFields">
|
||||||
<TextField
|
<Field
|
||||||
className="textarea_exercise"
|
component={LaTeXInputMemo}
|
||||||
placeholder={"choice"}
|
id={`choice_${index + 1}`} name={`answers.${index}.content`} label={t(`input.choice`) + ` ` +`( ${index + 1} )`}
|
||||||
label2={
|
/>
|
||||||
t(`input.choice`) +
|
<Field
|
||||||
` ` +
|
component={ImageBoxFieldMemo}
|
||||||
`( ${t(`alphabet.${getCharFromNumber(index)}`)} )`
|
name={`answers.${index}.content_image`}
|
||||||
}
|
/>
|
||||||
name={index}
|
|
||||||
id={`choice_${index + 1}`}
|
|
||||||
type="TextArea"
|
|
||||||
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ImageBoxField name={`answers.${index}.content_image`} />
|
|
||||||
|
|
||||||
<div className="answer_status">
|
<div className="answer_status">
|
||||||
<CheckboxField
|
<CheckboxField
|
||||||
|
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
import { Form, Input } from "antd";
|
|
||||||
import React from "react";
|
|
||||||
import useFormField from "../../../../../Hooks/useFormField";
|
|
||||||
import { MdOutlineEdit } from "react-icons/md";
|
|
||||||
import { Field } from "formik";
|
|
||||||
const { TextArea } = Input;
|
|
||||||
|
|
||||||
const TextField = ({
|
|
||||||
name,
|
|
||||||
label,
|
|
||||||
label2,
|
|
||||||
placeholder,
|
|
||||||
isDisabled,
|
|
||||||
onChange,
|
|
||||||
props,
|
|
||||||
no_label,
|
|
||||||
label_icon,
|
|
||||||
id,
|
|
||||||
className,
|
|
||||||
}: any) => {
|
|
||||||
const newName = `answers[${name}].content`;
|
|
||||||
const { formik, isError, errorMsg, t } = useFormField(newName, props);
|
|
||||||
const TextFilehandleChange = (
|
|
||||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
|
||||||
) => {
|
|
||||||
// console.log('Change:', e.target.value);
|
|
||||||
formik.setFieldValue(newName, e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={`ValidationField w-100 ${className ?? ""} `}>
|
|
||||||
{no_label ? (
|
|
||||||
<label htmlFor={name} className="text">
|
|
||||||
<span>empty</span>
|
|
||||||
</label>
|
|
||||||
) : label_icon ? (
|
|
||||||
<div className="LabelWithIcon">
|
|
||||||
<label htmlFor={name} className="text">
|
|
||||||
{label2 ? label2 : t(`input.${label ? label : name}`)}
|
|
||||||
</label>
|
|
||||||
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<label htmlFor={name} className="text">
|
|
||||||
{label2 ? label2 : t(`input.${label ? label : name}`)}
|
|
||||||
</label>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
hasFeedback
|
|
||||||
validateStatus={isError ? "error" : ""}
|
|
||||||
help={isError ? errorMsg : ""}
|
|
||||||
>
|
|
||||||
<Field
|
|
||||||
as={TextArea}
|
|
||||||
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
|
||||||
name={newName}
|
|
||||||
disabled={isDisabled}
|
|
||||||
size="large"
|
|
||||||
showCount
|
|
||||||
maxLength={1000}
|
|
||||||
onChange={onChange || TextFilehandleChange}
|
|
||||||
autoSize={{ minRows: 4, maxRows: 10 }}
|
|
||||||
|
|
||||||
id={id}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default React.memo(TextField);
|
|
||||||
|
|
@ -16,7 +16,7 @@ const CheckboxField = ({
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const CheckboxhandleChange = (value: any) => {
|
const CheckboxhandleChange = (value: any) => {
|
||||||
const allAreZero = formik?.values?.Questions?.[parent_index]?.answers?.some(
|
const allAreZero = formik?.values?.Questions?.[parent_index]?.answers?.some(
|
||||||
(item: any) => item.isCorrect === 1,
|
(item: any) => item.isCorrect === 1 || item.isCorrect === true,
|
||||||
);
|
);
|
||||||
if (allAreZero) {
|
if (allAreZero) {
|
||||||
formik?.values?.Questions?.[parent_index]?.answers.forEach(
|
formik?.values?.Questions?.[parent_index]?.answers.forEach(
|
||||||
|
|
|
||||||
|
|
@ -1,138 +1,128 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Choice } from "../../../../../../types/Item";
|
|
||||||
import ValidationField from "../../../../../../Components/ValidationField/ValidationField";
|
import ValidationField from "../../../../../../Components/ValidationField/ValidationField";
|
||||||
import { useFormikContext } from "formik";
|
import { Field } from "formik";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { getCharFromNumber } from "../../../../../../utils/getCharFromNumber";
|
|
||||||
import CheckboxField from "./CheckboxField";
|
import CheckboxField from "./CheckboxField";
|
||||||
import TextField from "./TextField";
|
|
||||||
import { toast } from "react-toastify";
|
|
||||||
import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
|
||||||
import { GoTrash } from "react-icons/go";
|
import { GoTrash } from "react-icons/go";
|
||||||
import { Popconfirm } from "antd";
|
import { Popconfirm } from "antd";
|
||||||
import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
|
||||||
|
import LaTeXInputMemo from "../../../../../../Components/LatextInput/LaTeXInputMemo";
|
||||||
|
import ImageBoxFieldMemo from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo";
|
||||||
|
|
||||||
const ChoiceFields = ({
|
const ChoiceFields = React.memo(
|
||||||
index,
|
({
|
||||||
parent_index,
|
index,
|
||||||
data,
|
parent_index,
|
||||||
}: {
|
setFieldValue,
|
||||||
index: number;
|
values
|
||||||
parent_index: number;
|
}: {
|
||||||
data: Choice;
|
index: number;
|
||||||
}) => {
|
parent_index: number;
|
||||||
const formik = useFormikContext<any>();
|
setFieldValue:any;
|
||||||
|
values:any
|
||||||
|
}) => {
|
||||||
|
console.log(567)
|
||||||
|
const [t] = useTranslation();
|
||||||
|
const { ShowHint } = useObjectToEdit();
|
||||||
|
const handleDeleteChoice = () => {
|
||||||
|
document.getElementById(`ChoiceField_${parent_index}_${index}`)?.classList.add("exit")
|
||||||
|
|
||||||
const [t] = useTranslation();
|
const updatedAnswers = values.Questions?.[
|
||||||
const { ShowHint } = useObjectToEdit();
|
parent_index
|
||||||
const handleDeleteChoice = () => {
|
].answers.filter((_: any, i: any) => i !== index);
|
||||||
document.getElementById(`ChoiceField_${parent_index}_${index}`)?.classList.add("exit")
|
setTimeout(() => {
|
||||||
|
setFieldValue(`Questions[${parent_index}].answers`, updatedAnswers);
|
||||||
|
document.getElementById(`ChoiceField_${parent_index}_${index}`)?.classList.remove("exit")
|
||||||
|
|
||||||
const updatedAnswers = formik.values.Questions?.[
|
}, 500);
|
||||||
parent_index
|
};
|
||||||
].answers.filter((_: any, i: any) => i !== index);
|
|
||||||
setTimeout(() => {
|
|
||||||
formik.setFieldValue(`Questions[${parent_index}].answers`, updatedAnswers);
|
|
||||||
document.getElementById(`ChoiceField_${parent_index}_${index}`)?.classList.remove("exit")
|
|
||||||
|
|
||||||
}, 500);
|
const value = values.Questions?.[parent_index]?.answers?.[index] ;
|
||||||
};
|
|
||||||
|
|
||||||
const values = formik.values.Questions?.[parent_index]?.answers?.[index] ;
|
const handelCanDeleteAnswers = ()=>{
|
||||||
|
const content = value?.content ;
|
||||||
const handelCanDeleteAnswers = ()=>{
|
const content_image = value?.content_image ;
|
||||||
const content = values?.content ;
|
if(!content && !content_image ){
|
||||||
const content_image = values?.content_image ;
|
return true
|
||||||
if(!content && !content_image ){
|
}
|
||||||
return true
|
return false
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div id={`ChoiceField_${parent_index}_${index}`} className="ChoiceFields">
|
<div id={`ChoiceField_${parent_index}_${index}`} className="ChoiceFields">
|
||||||
<TextField
|
|
||||||
className="textarea_exercise"
|
<Field
|
||||||
placeholder={"choice"}
|
component={LaTeXInputMemo}
|
||||||
label2={
|
name={`Questions[${parent_index}].answers[${index}].content`} label={
|
||||||
t(`input.choice`) +
|
t(`input.choice`) +
|
||||||
` ` +
|
` ` +
|
||||||
`( ${t(`alphabet.${getCharFromNumber(index)}`)} )`
|
`( ${index + 1} )`
|
||||||
}
|
}
|
||||||
name={index}
|
|
||||||
parent_index={parent_index}
|
|
||||||
type="TextArea"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ImageBoxField
|
<Field
|
||||||
|
component={ImageBoxFieldMemo}
|
||||||
name={`Questions.${parent_index}.answers.${index}.content_image`}
|
name={`Questions.${parent_index}.answers.${index}.content_image`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="answer_status">
|
|
||||||
<CheckboxField
|
|
||||||
className=""
|
|
||||||
label="The_correct_answer"
|
|
||||||
name={index}
|
|
||||||
type="Checkbox"
|
|
||||||
parent_index={parent_index}
|
|
||||||
/>
|
|
||||||
|
|
||||||
|
<div className="answer_status">
|
||||||
{handelCanDeleteAnswers() ?
|
<CheckboxField
|
||||||
<p className="delete_question_options" onClick={()=>{handleDeleteChoice()}} >
|
className=""
|
||||||
{t("header.delete_choice")}
|
label="The_correct_answer"
|
||||||
<GoTrash
|
name={index}
|
||||||
className="trash_icon"
|
type="Checkbox"
|
||||||
|
parent_index={parent_index}
|
||||||
size={17}
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
:
|
|
||||||
|
|
||||||
<Popconfirm
|
|
||||||
title={t("header.this_will_un_do_all_your_changes")}
|
|
||||||
okText={t("practical.yes")}
|
|
||||||
cancelText={t("practical.no")}
|
|
||||||
onConfirm={()=>{handleDeleteChoice()}}
|
|
||||||
defaultOpen={false}
|
|
||||||
|
|
||||||
>
|
|
||||||
<p className="delete_question_options" >
|
|
||||||
{t("header.delete_choice")}
|
|
||||||
<GoTrash
|
|
||||||
className="trash_icon"
|
|
||||||
|
|
||||||
size={17}
|
|
||||||
/>
|
/>
|
||||||
</p>
|
|
||||||
|
|
||||||
</Popconfirm>
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
{handelCanDeleteAnswers() ?
|
||||||
|
<p className="delete_question_options" onClick={()=>{handleDeleteChoice()}} >
|
||||||
|
{t("header.delete_choice")}
|
||||||
|
<GoTrash
|
||||||
|
className="trash_icon"
|
||||||
|
|
||||||
|
size={17}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
:
|
||||||
|
|
||||||
|
<Popconfirm
|
||||||
|
title={t("header.this_will_un_do_all_your_changes")}
|
||||||
|
okText={t("practical.yes")}
|
||||||
|
cancelText={t("practical.no")}
|
||||||
|
onConfirm={()=>{handleDeleteChoice()}}
|
||||||
|
defaultOpen={false}
|
||||||
|
|
||||||
|
>
|
||||||
|
<p className="delete_question_options" >
|
||||||
|
{t("header.delete_choice")}
|
||||||
|
<GoTrash
|
||||||
|
className="trash_icon"
|
||||||
|
|
||||||
|
size={17}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</Popconfirm>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="exercise_form_width">
|
|
||||||
{ShowHint &&
|
|
||||||
<ValidationField
|
|
||||||
className="hint"
|
|
||||||
placeholder="_"
|
|
||||||
name={`Questions.${parent_index}.answers.${index}.hint`}
|
|
||||||
label="hint"
|
|
||||||
type="TextArea"
|
|
||||||
style={{ width: "100%" , height: 60,resize:"none" }}
|
|
||||||
showCount={false}
|
|
||||||
autoSize={{ minRows: 2, maxRows: 10 }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
}
|
</>
|
||||||
</div>
|
);
|
||||||
</>
|
}
|
||||||
);
|
, (prevProps, nextProps) => {
|
||||||
};
|
console.log(prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[prevProps?.index] === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[prevProps?.index]);
|
||||||
|
console.log(2255);
|
||||||
|
|
||||||
|
return prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[prevProps?.index] === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[prevProps?.index];
|
||||||
|
});
|
||||||
|
|
||||||
export default ChoiceFields;
|
export default ChoiceFields;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ChoiceFields from "./ChoiceFields";
|
import ChoiceFields from "./ChoiceFields";
|
||||||
import { Choice } from "../../../../../../types/Item";
|
import { Choice } from "../../../../../../types/Item";
|
||||||
import { useFormikContext } from "formik";
|
// import { useFormikContext } from "formik";
|
||||||
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
|
// import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
|
||||||
import { HolderOutlined } from "@ant-design/icons";
|
// import { HolderOutlined } from "@ant-design/icons";
|
||||||
|
|
||||||
const Choices = ({ parent_index }: { parent_index: number }) => {
|
const Choices = React.memo( ({setFieldValue ,values,parent_index }:any) => {
|
||||||
const formik = useFormikContext<any>();
|
|
||||||
|
|
||||||
const handleDragEnd = (result: any) => {
|
const handleDragEnd = (result: any) => {
|
||||||
// Check if the item was dropped outside the list
|
// Check if the item was dropped outside the list
|
||||||
|
|
@ -15,11 +14,11 @@ const Choices = ({ parent_index }: { parent_index: number }) => {
|
||||||
|
|
||||||
if (!result.destination) return;
|
if (!result.destination) return;
|
||||||
|
|
||||||
console.log(formik?.values?.Questions?.[parent_index]?.answers);
|
console.log(values?.Questions?.[parent_index]?.answers);
|
||||||
|
|
||||||
// Create a new array from the current answers
|
// Create a new array from the current answers
|
||||||
const items = Array.from(
|
const items = Array.from(
|
||||||
formik?.values?.Questions?.[parent_index]?.answers,
|
values?.Questions?.[parent_index]?.answers,
|
||||||
);
|
);
|
||||||
console.log(items);
|
console.log(items);
|
||||||
// Remove the item from the original position
|
// Remove the item from the original position
|
||||||
|
|
@ -36,18 +35,21 @@ const Choices = ({ parent_index }: { parent_index: number }) => {
|
||||||
order: index + 1, // Update order to be 1-based index
|
order: index + 1, // Update order to be 1-based index
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Update the formik state with the new order
|
// Update the state with the new order
|
||||||
console.log(updatedItems, "updatedItems");
|
console.log(updatedItems, "updatedItems");
|
||||||
|
|
||||||
formik.setFieldValue(`Questions.${parent_index}.answers`, updatedItems);
|
setFieldValue(`Questions.${parent_index}.answers`, updatedItems);
|
||||||
};
|
};
|
||||||
|
console.log(123);
|
||||||
|
console.log(setFieldValue);
|
||||||
|
console.log(values?.Questions?.[parent_index]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{(
|
{(
|
||||||
(formik?.values as any)?.Questions?.[parent_index]?.answers ||
|
values?.Questions?.[parent_index]?.answers ||
|
||||||
[]
|
[]
|
||||||
).map((item: Choice, index: number) => {
|
).map((item: Choice, index: number) => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -59,7 +61,8 @@ const Choices = ({ parent_index }: { parent_index: number }) => {
|
||||||
key={index}
|
key={index}
|
||||||
parent_index={parent_index}
|
parent_index={parent_index}
|
||||||
index={index}
|
index={index}
|
||||||
data={item}
|
setFieldValue={setFieldValue}
|
||||||
|
values={values}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -112,6 +115,11 @@ const Choices = ({ parent_index }: { parent_index: number }) => {
|
||||||
</DragDropContext> */}
|
</DragDropContext> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
}, (prevProps, nextProps) => {
|
||||||
|
console.log(prevProps.values?.Questions?.[prevProps?.parent_index]?.answers === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers);
|
||||||
|
console.log(22);
|
||||||
|
|
||||||
|
return prevProps.values?.Questions?.[prevProps?.parent_index]?.answers === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers;
|
||||||
|
});
|
||||||
|
|
||||||
export default Choices;
|
export default Choices;
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,19 @@
|
||||||
import { Col, Row } from "reactstrap";
|
import { Row } from "reactstrap";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import ValidationField from "../../../../../Components/ValidationField/ValidationField";
|
import { useFormikContext } from "formik";
|
||||||
import { useFormikContext } from "formik";
|
|
||||||
import { FaCirclePlus } from "react-icons/fa6";
|
import { FaCirclePlus } from "react-icons/fa6";
|
||||||
import { Choice } from "../../../../../types/Item";
|
import { Choice } from "../../../../../types/Item";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import QuestionFIeld from "./QuestionFIeld/QuestionFIeld";
|
|
||||||
import { useObjectToEdit } from "../../../../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../../../../zustand/ObjectToEditState";
|
||||||
import Choices from "./ChoiceField/Choices";
|
|
||||||
import ImageBoxField from "../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
|
||||||
import MaltySelectTag from "./Tags/MaltySelectTag";
|
|
||||||
import useKeyCombination from "../../../../../Hooks/useKeyCombination";
|
import useKeyCombination from "../../../../../Hooks/useKeyCombination";
|
||||||
import { CombinationKeyEnum } from "../../../../../enums/CombinationKeyEnum";
|
import { CombinationKeyEnum } from "../../../../../enums/CombinationKeyEnum";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
import MainInputs from "./components/MainInputs";
|
||||||
|
import Questions from "./components/Questions";
|
||||||
|
|
||||||
const Form = () => {
|
const Form = () => {
|
||||||
const formik = useFormikContext<any>();
|
const formik = useFormikContext<any>();
|
||||||
const { setSuccess, Success, setSavedQuestionData ,ShowHint} = useObjectToEdit();
|
const { setSuccess, Success ,ShowHint} = useObjectToEdit();
|
||||||
console.log(formik.errors);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setSavedQuestionData(formik.values);
|
|
||||||
}, [formik?.values]);
|
|
||||||
|
|
||||||
const handleAddChoice = (
|
const handleAddChoice = (
|
||||||
parent_index: number,
|
parent_index: number,
|
||||||
|
|
@ -70,7 +62,8 @@ const Form = () => {
|
||||||
};
|
};
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
|
||||||
const lastQuestions = formik?.values?.Questions?.length - 1;
|
|
||||||
|
const lastQuestions = formik?.values?.Questions?.length - 1;
|
||||||
useKeyCombination(
|
useKeyCombination(
|
||||||
{ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE },
|
{ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE },
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -100,65 +93,9 @@ const Form = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row className="w-100 exercise_form_container">
|
<Row className="w-100 exercise_form_container">
|
||||||
<div className="exercise_form">
|
<MainInputs/>
|
||||||
<ValidationField
|
|
||||||
className="textarea_exercise"
|
|
||||||
name="content"
|
|
||||||
label="main_question"
|
|
||||||
type="TextArea"
|
|
||||||
/>
|
|
||||||
<ImageBoxField name="content_image" />
|
|
||||||
|
|
||||||
<div></div>
|
|
||||||
</div>
|
|
||||||
<div className="flex"></div>
|
<div className="flex"></div>
|
||||||
|
<Questions setFieldValue={formik.setFieldValue} values={formik.values} />
|
||||||
{((formik?.values as any)?.Questions || [])?.map(
|
|
||||||
(item: Choice, parent_index: number) => {
|
|
||||||
return (
|
|
||||||
<div key={parent_index}>
|
|
||||||
<div className="exercise_form QuestionFIeld">
|
|
||||||
<QuestionFIeld
|
|
||||||
key={parent_index}
|
|
||||||
index={parent_index}
|
|
||||||
data={item}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Choices parent_index={parent_index} />
|
|
||||||
|
|
||||||
{formik?.values?.Questions?.[parent_index]?.answers?.length <
|
|
||||||
5 && (
|
|
||||||
<p className="add_new_button">
|
|
||||||
<FaCirclePlus
|
|
||||||
onClick={() => handleAddChoice(parent_index)}
|
|
||||||
size={23}
|
|
||||||
/>{" "}
|
|
||||||
{t("header.add_new_choice")}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="exercise_form_width">
|
|
||||||
{ShowHint &&
|
|
||||||
<ValidationField
|
|
||||||
className=" "
|
|
||||||
placeholder="_"
|
|
||||||
name={`Questions.${parent_index}.hint`}
|
|
||||||
label="hint_question"
|
|
||||||
type="TextArea"
|
|
||||||
style={{ width: "100%" , height: 60,resize:"none" }}
|
|
||||||
autoSize={{ minRows: 2, maxRows: 10 }}
|
|
||||||
showCount={false}
|
|
||||||
/>
|
|
||||||
|
|
||||||
}
|
|
||||||
<MaltySelectTag parent_index={parent_index} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
|
|
||||||
<p className="add_new_button">
|
<p className="add_new_button">
|
||||||
<FaCirclePlus onClick={() => handleAddQuestion()} size={23} />{" "}
|
<FaCirclePlus onClick={() => handleAddQuestion()} size={23} />{" "}
|
||||||
{t("header.add_new_question")}
|
{t("header.add_new_question")}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Choice } from "../../../../../../types/Item";
|
import { Choice } from "../../../../../../types/Item";
|
||||||
import { useFormikContext } from "formik";
|
import { Field, useFormikContext } from "formik";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { getCharFromNumber } from "../../../../../../utils/getCharFromNumber";
|
import { getCharFromNumber } from "../../../../../../utils/getCharFromNumber";
|
||||||
import TextField from "./TextField";
|
import TextField from "./TextField";
|
||||||
|
|
@ -8,8 +8,11 @@ import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
|
||||||
import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
||||||
import { GoTrash } from "react-icons/go";
|
import { GoTrash } from "react-icons/go";
|
||||||
import { Popconfirm } from "antd";
|
import { Popconfirm } from "antd";
|
||||||
|
import LaTeXInput from "../../../../../../Components/LatextInput/LaTeXInput";
|
||||||
|
import LaTeXInputMemo from "../../../../../../Components/LatextInput/LaTeXInputMemo";
|
||||||
|
import ImageBoxFieldMemo from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo";
|
||||||
|
|
||||||
const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => {
|
const QuestionFIeld = ({ index , setFieldValue,values }: { index: number , setFieldValue:any,values:any }) => {
|
||||||
const formik = useFormikContext<any>();
|
const formik = useFormikContext<any>();
|
||||||
const { setDeletedQuestions, DeletedQuestions } = useObjectToEdit();
|
const { setDeletedQuestions, DeletedQuestions } = useObjectToEdit();
|
||||||
|
|
||||||
|
|
@ -31,11 +34,11 @@ const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const values = formik.values.Questions?.[index] ;
|
const value = formik.values.Questions?.[index] ;
|
||||||
|
|
||||||
const handelCanDeleteAnswers = ()=>{
|
const handelCanDeleteAnswers = ()=>{
|
||||||
const content = values?.content ;
|
const content = value?.content ;
|
||||||
const content_image = values?.content_image ;
|
const content_image = value?.content_image ;
|
||||||
if(!content && !content_image ){
|
if(!content && !content_image ){
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -48,21 +51,18 @@ const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => {
|
||||||
<>
|
<>
|
||||||
<div className="exercise_forms">
|
<div className="exercise_forms">
|
||||||
<div className="ChoiceFields">
|
<div className="ChoiceFields">
|
||||||
<TextField
|
<Field
|
||||||
className="textarea_exercise"
|
component={LaTeXInputMemo}
|
||||||
placeholder={"question"}
|
id={`question_${index + 1}`} name={`Questions[${index}].content`} label={
|
||||||
label2={
|
t(`input.question`) +
|
||||||
t(`input.question`) +
|
` ` +
|
||||||
` ` +
|
`( ${index + 1} )`
|
||||||
`( ${t(`alphabet.${getCharFromNumber(index)}`)} )`
|
}
|
||||||
}
|
/>
|
||||||
name={index}
|
<Field
|
||||||
id={`question_${index + 1}`}
|
component={ImageBoxFieldMemo}
|
||||||
type="TextArea"
|
name={`Questions.${index}.content_image`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ImageBoxField name={`Questions.${index}.content_image`} />
|
|
||||||
|
|
||||||
{handelCanDeleteAnswers() ?
|
{handelCanDeleteAnswers() ?
|
||||||
<div className="answer_status" >
|
<div className="answer_status" >
|
||||||
<p className="delete_question_options" onClick={()=>{handleDeleteQuestion()}}>
|
<p className="delete_question_options" onClick={()=>{handleDeleteQuestion()}}>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const QuestionList = () => {
|
||||||
|
return (
|
||||||
|
<div>QuestionList</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default QuestionList
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Field } from 'formik'
|
||||||
|
import React from 'react'
|
||||||
|
import LaTeXInputMemo from '../../../../../../Components/LatextInput/LaTeXInputMemo'
|
||||||
|
import ImageBoxFieldMemo from '../../../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
const MainInputs = () => {
|
||||||
|
const [t] = useTranslation()
|
||||||
|
return (
|
||||||
|
<div className="exercise_form">
|
||||||
|
<Field
|
||||||
|
name="content"
|
||||||
|
component={LaTeXInputMemo}
|
||||||
|
label={t("input.answer_content")}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Field
|
||||||
|
component={ImageBoxFieldMemo}
|
||||||
|
name="content_image"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MainInputs
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
import React, { useCallback, useMemo } from 'react';
|
||||||
|
import { FixedSizeList as List, areEqual } from 'react-window';
|
||||||
|
import { Choice } from '../../../../../../types/Item';
|
||||||
|
import QuestionFIeld from '../QuestionFIeld/QuestionFIeld';
|
||||||
|
import Choices from '../ChoiceField/Choices';
|
||||||
|
import { FaCirclePlus } from 'react-icons/fa6';
|
||||||
|
import ValidationField from '../../../../../../Components/ValidationField/ValidationField';
|
||||||
|
import MaltySelectTag from '../Tags/MaltySelectTag';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useObjectToEdit } from '../../../../../../zustand/ObjectToEditState';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
interface QuestionsProps {
|
||||||
|
setFieldValue: (field: string, value: any) => void;
|
||||||
|
values: {
|
||||||
|
Questions: Choice[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const Row: React.FC<any> = React.memo(({ index, data }) => {
|
||||||
|
const { values, setFieldValue } = data;
|
||||||
|
const { ShowHint } = useObjectToEdit();
|
||||||
|
const [t] = useTranslation();
|
||||||
|
|
||||||
|
const handleAddChoice = useCallback((
|
||||||
|
parent_index: number,
|
||||||
|
fromKeyCombination: boolean = false,
|
||||||
|
) => {
|
||||||
|
setFieldValue(`Questions.[${parent_index}].answers`, [
|
||||||
|
...(values?.Questions?.[parent_index]?.answers as Choice[]),
|
||||||
|
{
|
||||||
|
answer: null,
|
||||||
|
content_image: null,
|
||||||
|
content: null,
|
||||||
|
isCorrect: 0,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (fromKeyCombination) {
|
||||||
|
toast.success(t("header.new_choice_have_been_added"));
|
||||||
|
}
|
||||||
|
}, [setFieldValue, values, t]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={index}>
|
||||||
|
<div className="exercise_form QuestionFIeld">
|
||||||
|
<QuestionFIeld setFieldValue={setFieldValue} values={values} key={index} index={index} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Choices setFieldValue={setFieldValue} values={values} parent_index={index} />
|
||||||
|
|
||||||
|
{values?.Questions?.[index]?.answers?.length < 5 && (
|
||||||
|
<p className="add_new_button">
|
||||||
|
<FaCirclePlus
|
||||||
|
onClick={() => handleAddChoice(index)}
|
||||||
|
size={23}
|
||||||
|
/>{" "}
|
||||||
|
{t("header.add_new_choice")}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="exercise_form_width">
|
||||||
|
{ShowHint && (
|
||||||
|
<ValidationField
|
||||||
|
className=" "
|
||||||
|
placeholder="_"
|
||||||
|
name={`Questions.${index}.hint`}
|
||||||
|
label="hint_question"
|
||||||
|
type="TextArea"
|
||||||
|
style={{ width: "100%", height: 60, resize: "none" }}
|
||||||
|
autoSize={{ minRows: 2, maxRows: 10 }}
|
||||||
|
showCount={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<MaltySelectTag parent_index={index} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, areEqual);
|
||||||
|
|
||||||
|
const Questions: React.FC<QuestionsProps> = React.memo(({ setFieldValue, values }) => {
|
||||||
|
const questions = values.Questions || [];
|
||||||
|
|
||||||
|
const itemData = useMemo(() => ({ values, setFieldValue }), [values, setFieldValue]);
|
||||||
|
const itemSize = 1100;
|
||||||
|
const listHeight = useMemo(() => {
|
||||||
|
return Math.min(1300, questions.length * itemSize); // Adjust 400 to your desired max height
|
||||||
|
}, [questions.length]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<List
|
||||||
|
height={listHeight}
|
||||||
|
itemCount={questions.length}
|
||||||
|
itemSize={itemSize}
|
||||||
|
width="100%"
|
||||||
|
itemData={itemData}
|
||||||
|
direction='rtl'
|
||||||
|
>
|
||||||
|
{Row}
|
||||||
|
</List>
|
||||||
|
|
||||||
|
{/* {(values?.Questions || [])?.map(
|
||||||
|
(item: Choice, parent_index: number) => {
|
||||||
|
return (
|
||||||
|
<Row key={parent_index} index={parent_index} data={{values, setFieldValue}} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)} */}
|
||||||
|
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}, (prevProps, nextProps) => prevProps.values.Questions === nextProps.values.Questions);
|
||||||
|
|
||||||
|
export default Questions;
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
import React from 'react'
|
||||||
|
import QuestionFIeld from '../QuestionFIeld/QuestionFIeld';
|
||||||
|
import { Choice } from '../../../../../../types/Item';
|
||||||
|
import Choices from '../ChoiceField/Choices';
|
||||||
|
import { FaCirclePlus } from 'react-icons/fa6';
|
||||||
|
import ValidationField from '../../../../../../Components/ValidationField/ValidationField';
|
||||||
|
import MaltySelectTag from '../Tags/MaltySelectTag';
|
||||||
|
import { useObjectToEdit } from '../../../../../../zustand/ObjectToEditState';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
// Memoized Questions Component
|
||||||
|
const Questions = React.memo(({setFieldValue,values}:any) => {
|
||||||
|
const { ShowHint } = useObjectToEdit();
|
||||||
|
const [t] = useTranslation();
|
||||||
|
|
||||||
|
const handleAddChoice = (
|
||||||
|
parent_index: number,
|
||||||
|
fromKeyCombination: boolean = false,
|
||||||
|
) => {
|
||||||
|
setFieldValue(`Questions.[${parent_index}].answers`, [
|
||||||
|
...((values as any)?.Questions?.[parent_index]
|
||||||
|
?.answers as Choice[]),
|
||||||
|
{
|
||||||
|
answer: null,
|
||||||
|
content_image: null,
|
||||||
|
content: null,
|
||||||
|
isCorrect: 0,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (fromKeyCombination) {
|
||||||
|
toast.success(t("header.new_choice_have_been_added"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{(values?.Questions || [])?.map(
|
||||||
|
(item: Choice, parent_index: number) => {
|
||||||
|
return (
|
||||||
|
<div key={parent_index}>
|
||||||
|
<div className="exercise_form QuestionFIeld">
|
||||||
|
<QuestionFIeld setFieldValue={setFieldValue} values={values} key={parent_index} index={parent_index} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Choices setFieldValue={setFieldValue} values={values} parent_index={parent_index} />
|
||||||
|
|
||||||
|
{values?.Questions?.[parent_index]?.answers?.length < 5 && (
|
||||||
|
<p className="add_new_button">
|
||||||
|
<FaCirclePlus
|
||||||
|
onClick={() => handleAddChoice(parent_index)}
|
||||||
|
size={23}
|
||||||
|
/>{" "}
|
||||||
|
{t("header.add_new_choice")}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="exercise_form_width">
|
||||||
|
{ShowHint && (
|
||||||
|
<ValidationField
|
||||||
|
className=" "
|
||||||
|
placeholder="_"
|
||||||
|
name={`Questions.${parent_index}.hint`}
|
||||||
|
label="hint_question"
|
||||||
|
type="TextArea"
|
||||||
|
style={{ width: "100%", height: 60, resize: "none" }}
|
||||||
|
autoSize={{ minRows: 2, maxRows: 10 }}
|
||||||
|
showCount={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<MaltySelectTag parent_index={parent_index} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}, (prevProps, nextProps) => {
|
||||||
|
|
||||||
|
return prevProps.values.Questions === nextProps.values.Questions;
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Questions;
|
||||||
126
src/Pages/Admin/question/Model/Malty/components/Questions.tsx
Normal file
126
src/Pages/Admin/question/Model/Malty/components/Questions.tsx
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
import React, { useCallback, useMemo, useRef, useEffect } from 'react';
|
||||||
|
import { VariableSizeList as List } from 'react-window';
|
||||||
|
import { Choice } from '../../../../../../types/Item';
|
||||||
|
import QuestionFIeld from '../QuestionFIeld/QuestionFIeld';
|
||||||
|
import Choices from '../ChoiceField/Choices';
|
||||||
|
import { FaCirclePlus } from 'react-icons/fa6';
|
||||||
|
import ValidationField from '../../../../../../Components/ValidationField/ValidationField';
|
||||||
|
import MaltySelectTag from '../Tags/MaltySelectTag';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useObjectToEdit } from '../../../../../../zustand/ObjectToEditState';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
interface QuestionsProps {
|
||||||
|
setFieldValue: (field: string, value: any) => void;
|
||||||
|
values: {
|
||||||
|
Questions: any[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const Row: React.FC<any> = React.memo(({ index, style, data }) => {
|
||||||
|
const { values, setFieldValue, ShowHint, t } = data;
|
||||||
|
|
||||||
|
const handleAddChoice = useCallback((
|
||||||
|
parent_index: number,
|
||||||
|
fromKeyCombination: boolean = false,
|
||||||
|
) => {
|
||||||
|
setFieldValue(`Questions.[${parent_index}].answers`, [
|
||||||
|
...(values?.Questions?.[parent_index]?.answers as Choice[]),
|
||||||
|
{
|
||||||
|
answer: null,
|
||||||
|
content_image: null,
|
||||||
|
content: null,
|
||||||
|
isCorrect: 0,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (fromKeyCombination) {
|
||||||
|
toast.success(t("header.new_choice_have_been_added"));
|
||||||
|
}
|
||||||
|
}, [setFieldValue, values, t]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={style}>
|
||||||
|
<div className="exercise_form QuestionFIeld">
|
||||||
|
<QuestionFIeld setFieldValue={setFieldValue} values={values} key={index} index={index} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Choices setFieldValue={setFieldValue} values={values} parent_index={index} />
|
||||||
|
|
||||||
|
{values?.Questions?.[index]?.answers?.length < 5 && (
|
||||||
|
<p className="add_new_button">
|
||||||
|
<FaCirclePlus
|
||||||
|
onClick={() => handleAddChoice(index)}
|
||||||
|
size={23}
|
||||||
|
/>{" "}
|
||||||
|
{t("header.add_new_choice")}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="exercise_form_width">
|
||||||
|
{ShowHint && (
|
||||||
|
<ValidationField
|
||||||
|
className=" "
|
||||||
|
placeholder="_"
|
||||||
|
name={`Questions.${index}.hint`}
|
||||||
|
label="hint_question"
|
||||||
|
type="TextArea"
|
||||||
|
style={{ width: "100%", height: 60, resize: "none" }}
|
||||||
|
autoSize={{ minRows: 2, maxRows: 10 }}
|
||||||
|
showCount={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<MaltySelectTag parent_index={index} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const Questions: React.FC<QuestionsProps> = React.memo(({ setFieldValue, values }) => {
|
||||||
|
const questions = values.Questions || [];
|
||||||
|
const { ShowHint } = useObjectToEdit();
|
||||||
|
const [t] = useTranslation();
|
||||||
|
const listRef = useRef<List>(null);
|
||||||
|
|
||||||
|
const getItemSize = useCallback((index: number) => {
|
||||||
|
const question = questions[index];
|
||||||
|
let height = 300; // Base height for QuestionField
|
||||||
|
|
||||||
|
height += (question.answers?.length || 0) * 212; // Height for each answer
|
||||||
|
if (question.answers?.length < 5) height += 40; // "Add new choice" button
|
||||||
|
if (ShowHint) height += 80; // Hint field
|
||||||
|
height += 50; // MaltySelectTag
|
||||||
|
|
||||||
|
return height;
|
||||||
|
}, [questions, ShowHint]);
|
||||||
|
|
||||||
|
const itemData = useMemo(() => ({
|
||||||
|
values,
|
||||||
|
setFieldValue,
|
||||||
|
ShowHint,
|
||||||
|
t
|
||||||
|
}), [values, setFieldValue, ShowHint, t]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (listRef.current) {
|
||||||
|
listRef.current.resetAfterIndex(0);
|
||||||
|
}
|
||||||
|
}, [questions, ShowHint]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List
|
||||||
|
ref={listRef}
|
||||||
|
height={window.innerHeight - 20} // Adjust based on your layout
|
||||||
|
itemCount={questions.length}
|
||||||
|
itemSize={getItemSize}
|
||||||
|
width="100%"
|
||||||
|
itemData={itemData}
|
||||||
|
direction='rtl'
|
||||||
|
className='ListQuestions'
|
||||||
|
>
|
||||||
|
{Row}
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
}, (prevProps, nextProps) => prevProps.values.Questions === nextProps.values.Questions);
|
||||||
|
|
||||||
|
export default Questions;
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
import { Row } from "reactstrap";
|
import { Row } from "reactstrap";
|
||||||
import ValidationField from "../../../../Components/ValidationField/ValidationField";
|
import ValidationField from "../../../../Components/ValidationField/ValidationField";
|
||||||
import { useFormikContext } from "formik";
|
import { Field, useFormikContext } from "formik";
|
||||||
import { FaCirclePlus } from "react-icons/fa6";
|
import { FaCirclePlus } from "react-icons/fa6";
|
||||||
import { Choice } from "../../../../types/Item";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import Choices from "./Field/Choices";
|
import Choices from "./Field/Choices";
|
||||||
import ImageBoxField from "../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
|
|
||||||
import SelectTag from "../../../../Components/CustomFields/SelectTag";
|
import SelectTag from "../../../../Components/CustomFields/SelectTag";
|
||||||
import useKeyCombination from "../../../../Hooks/useKeyCombination";
|
import useKeyCombination from "../../../../Hooks/useKeyCombination";
|
||||||
import { CombinationKeyEnum } from "../../../../enums/CombinationKeyEnum";
|
import { CombinationKeyEnum } from "../../../../enums/CombinationKeyEnum";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
import LaTeXInput from "../../../../Components/LatextInput/LaTeXInput";
|
||||||
|
import LaTeXInputMemo from "../../../../Components/LatextInput/LaTeXInputMemo";
|
||||||
|
import ImageBoxFieldMemo from "../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo";
|
||||||
|
|
||||||
const Form = () => {
|
const Form = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
|
@ -51,13 +52,16 @@ const Form = () => {
|
||||||
return (
|
return (
|
||||||
<Row className="w-100 exercise_form_container">
|
<Row className="w-100 exercise_form_container">
|
||||||
<div className="exercise_form">
|
<div className="exercise_form">
|
||||||
<ValidationField
|
<Field
|
||||||
className="textarea_exercise"
|
name="content"
|
||||||
name="content"
|
component={LaTeXInputMemo}
|
||||||
label="answer_content"
|
label={t("input.answer_content")}
|
||||||
type="TextArea"
|
/>
|
||||||
/>
|
|
||||||
<ImageBoxField name="content_image" />
|
<Field
|
||||||
|
component={ImageBoxFieldMemo}
|
||||||
|
name="content_image"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Choices />
|
<Choices />
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ export const getValidationSchema = () => {
|
||||||
"At least one of content or content_image must be provided",
|
"At least one of content or content_image must be provided",
|
||||||
(obj:any) => {
|
(obj:any) => {
|
||||||
const isValid = !!obj.content || !!obj.content_image;
|
const isValid = !!obj.content || !!obj.content_image;
|
||||||
console.log(isValid,"isValid");
|
|
||||||
|
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +82,7 @@ export const getInitialValuesBase = (objectToEdit: Question): any => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: objectToEdit?.id ?? null,
|
id: objectToEdit?.id ?? null,
|
||||||
content: objectToEdit?.content ?? "",
|
content: objectToEdit?.content ?? null,
|
||||||
content_image: objectToEdit?.content_image ?? "",
|
content_image: objectToEdit?.content_image ?? "",
|
||||||
subject_id: objectToEdit?.subject_id ?? "",
|
subject_id: objectToEdit?.subject_id ?? "",
|
||||||
isBase: 1,
|
isBase: 1,
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ const TableWithHeader = () => {
|
||||||
const deleteMutation = useDeleteSubject();
|
const deleteMutation = useDeleteSubject();
|
||||||
|
|
||||||
const { grade_id } = useParams<ParamsEnum>();
|
const { grade_id } = useParams<ParamsEnum>();
|
||||||
console.log(grade_id);
|
|
||||||
|
|
||||||
const { data: grade } = useGetAllGrade({
|
const { data: grade } = useGetAllGrade({
|
||||||
show: grade_id,
|
show: grade_id,
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ export const useColumns = () => {
|
||||||
dataIndex: "name",
|
dataIndex: "name",
|
||||||
key: "name",
|
key: "name",
|
||||||
align: "center",
|
align: "center",
|
||||||
|
ellipsis:true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("columns.icon"),
|
title: t("columns.icon"),
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,12 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import useFilter from "../../Components/FilterField/components/useFilter";
|
|
||||||
import { Select } from "antd";
|
|
||||||
|
|
||||||
const Dummy = () => {
|
const Dummy = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
// const { FilterButton, FilterBody } = useFilter();
|
|
||||||
return (
|
return (
|
||||||
<div className="DummyHomePage">
|
<div className="DummyHomePage">
|
||||||
|
|
||||||
{/* <FilterButton/>
|
|
||||||
<FilterBody>
|
|
||||||
karim
|
|
||||||
</FilterBody>
|
|
||||||
<Select
|
|
||||||
style={{width:"200px"}}
|
|
||||||
showSearch
|
|
||||||
/>
|
|
||||||
*/}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -110,3 +110,8 @@ svg{
|
||||||
scale: 1.1;
|
scale: 1.1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.LaTeXRenderer{
|
||||||
|
direction: ltr;
|
||||||
|
}
|
||||||
|
|
@ -17,3 +17,6 @@
|
||||||
@import "../DataTable/index.scss";
|
@import "../DataTable/index.scss";
|
||||||
|
|
||||||
@import "../Pages/index.scss";
|
@import "../Pages/index.scss";
|
||||||
|
|
||||||
|
|
||||||
|
@import '../components/index.scss';
|
||||||
|
|
@ -8,6 +8,9 @@
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
// background: #000 !important;
|
// background: #000 !important;
|
||||||
}
|
}
|
||||||
|
.exercise_form{
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
.exercise_form,
|
.exercise_form,
|
||||||
.ChoiceFields {
|
.ChoiceFields {
|
||||||
.upload_image_button {
|
.upload_image_button {
|
||||||
|
|
@ -42,7 +45,7 @@
|
||||||
.exercise_add_main {
|
.exercise_add_main {
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
padding: 10px 2vw;
|
padding: 10px 2vw;
|
||||||
max-height: 84vh;
|
// max-height: 84vh;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
@include Scrollbar();
|
@include Scrollbar();
|
||||||
}
|
}
|
||||||
|
|
@ -176,7 +179,7 @@
|
||||||
.answer_status {
|
.answer_status {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
|
||||||
padding-block: 30px;
|
padding-block: 30px;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
}
|
}
|
||||||
|
|
@ -351,3 +354,8 @@
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.ListQuestions{
|
||||||
|
@include Scrollbar()
|
||||||
|
}
|
||||||
74
src/Styles/components/LaTeXInput.scss
Normal file
74
src/Styles/components/LaTeXInput.scss
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
.DummyHomePage{
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LaTeXInputArea{
|
||||||
|
|
||||||
|
width: 50vw;
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
.showPreviewInput{
|
||||||
|
background-color: var(--bg);
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 44px);
|
||||||
|
word-wrap: break-word;
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
align-items: baseline;
|
||||||
|
align-content: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
padding: 5px 10px;
|
||||||
|
row-gap: 0px;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
.addMML{
|
||||||
|
all: unset;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
background: var(--primary);
|
||||||
|
color: var(--white);
|
||||||
|
padding: 2px 14px;
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.latexModal{
|
||||||
|
padding: 30px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.buttons{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 20px;
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.LatexPreview{
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.LaTeXInputOptions{
|
||||||
|
display: flex;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.text{
|
||||||
|
margin-bottom: 7px !important;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 19px;
|
||||||
|
> span {
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/Styles/components/index.scss
Normal file
1
src/Styles/components/index.scss
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
@import './LaTeXInput.scss' ;
|
||||||
|
|
@ -3,4 +3,6 @@ export enum LocalStorageEnum {
|
||||||
LANGUAGE_KEY = LocalStorageEnum.PROJECT_NAME + "_LANGUAGE",
|
LANGUAGE_KEY = LocalStorageEnum.PROJECT_NAME + "_LANGUAGE",
|
||||||
TOKEN_KEY = LocalStorageEnum.PROJECT_NAME + "_TOKEN_KEY",
|
TOKEN_KEY = LocalStorageEnum.PROJECT_NAME + "_TOKEN_KEY",
|
||||||
USER_KEY = LocalStorageEnum.PROJECT_NAME + "_USER_KEY",
|
USER_KEY = LocalStorageEnum.PROJECT_NAME + "_USER_KEY",
|
||||||
|
HINT_INPUT = LocalStorageEnum.PROJECT_NAME + "HINT_INPUT",
|
||||||
|
LATEX_OPTION_INPUT = LocalStorageEnum.PROJECT_NAME + "LATEX_OPTION_INPUT",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,8 @@
|
||||||
"it_should_have_more_than_one_correct_answers": "يجب أن يحتوي على إجابة صحيحة",
|
"it_should_have_more_than_one_correct_answers": "يجب أن يحتوي على إجابة صحيحة",
|
||||||
"File_size_exceeds_2_MB_limit.":"حجم الملف يتجاوز الحد الأقصى البالغ 2 ميجابايت",
|
"File_size_exceeds_2_MB_limit.":"حجم الملف يتجاوز الحد الأقصى البالغ 2 ميجابايت",
|
||||||
"one_of_image_and_content_should_be_enter_in_answer":"يجب إدخال صورة أو محتوى واحد على الأقل في الاجابة",
|
"one_of_image_and_content_should_be_enter_in_answer":"يجب إدخال صورة أو محتوى واحد على الأقل في الاجابة",
|
||||||
"one_of_image_and_content_should_be_enter_in_question":"يجب إدخال صورة أو محتوى واحد على الأقل في السؤال"
|
"one_of_image_and_content_should_be_enter_in_question":"يجب إدخال صورة أو محتوى واحد على الأقل في السؤال",
|
||||||
|
"that_is_not_a_valid_mml":"هذا ليس mml صالح"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"register_students": "تسجيل الطلاب",
|
"register_students": "تسجيل الطلاب",
|
||||||
|
|
@ -142,7 +143,11 @@
|
||||||
"managers":"مدراء",
|
"managers":"مدراء",
|
||||||
"sales":"المبيعات",
|
"sales":"المبيعات",
|
||||||
"hide_hint":"اخفاء الشرح",
|
"hide_hint":"اخفاء الشرح",
|
||||||
"show_hint":"عرض الشرح"
|
"show_hint":"عرض الشرح",
|
||||||
|
"past_your_MMl_text":"ضع نص MMl الخاص بك",
|
||||||
|
"add_MML":"إضافة MML",
|
||||||
|
"show_preview":"عرض المعاينة",
|
||||||
|
"show_MMl":" MML عرض"
|
||||||
},
|
},
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": "الرقم التعريفي",
|
"id": "الرقم التعريفي",
|
||||||
|
|
|
||||||
23
src/utils/areFieldPropsEqual.ts
Normal file
23
src/utils/areFieldPropsEqual.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
// utilityFunctions.ts
|
||||||
|
import { FieldProps } from 'formik';
|
||||||
|
|
||||||
|
export const areFieldPropsEqual = (
|
||||||
|
prevProps: any,
|
||||||
|
nextProps: any
|
||||||
|
): boolean => {
|
||||||
|
const prevError = prevProps.form.errors[prevProps.field.name];
|
||||||
|
const nextError = nextProps.form.errors[nextProps.field.name];
|
||||||
|
|
||||||
|
const prevTouched = prevProps.form.touched[prevProps.field.name];
|
||||||
|
const nextTouched = nextProps.form.touched[nextProps.field.name];
|
||||||
|
|
||||||
|
const prevValue = prevProps.field.value;
|
||||||
|
const nextValue = nextProps.field.value;
|
||||||
|
|
||||||
|
return (
|
||||||
|
prevValue === nextValue
|
||||||
|
&&
|
||||||
|
prevError === nextError &&
|
||||||
|
prevTouched === nextTouched
|
||||||
|
);
|
||||||
|
};
|
||||||
5
src/utils/convertMathMLToLaTeX.ts
Normal file
5
src/utils/convertMathMLToLaTeX.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { MathMLToLaTeX } from 'mathml-to-latex';
|
||||||
|
|
||||||
|
export function convertMathMLToLaTeX(mathml: string): string {
|
||||||
|
return MathMLToLaTeX.convert(mathml);
|
||||||
|
}
|
||||||
24
src/utils/parseTextAndLatex.ts
Normal file
24
src/utils/parseTextAndLatex.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
interface TextLatexPart {
|
||||||
|
text: string;
|
||||||
|
isLatex: boolean;
|
||||||
|
key:number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const parseTextAndLatex = (input: string): TextLatexPart[] => {
|
||||||
|
const result: TextLatexPart[] = [];
|
||||||
|
|
||||||
|
const parts = input?.split(/(\$\$[^$]+\$\$)/g);
|
||||||
|
|
||||||
|
parts.forEach((part,index) => {
|
||||||
|
if (part.startsWith('$$') && part.endsWith('$$')) {
|
||||||
|
|
||||||
|
result.push({ text: part.slice(2, -2), isLatex: true , key:index });
|
||||||
|
} else if (part.trim()) {
|
||||||
|
|
||||||
|
result.push({ text: part, isLatex: false,key:index });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
|
import { LocalStorageEnum } from "../enums/LocalStorageEnum";
|
||||||
|
|
||||||
interface ModelState {
|
interface ModelState {
|
||||||
objectToEdit: any;
|
objectToEdit: any;
|
||||||
|
|
@ -27,6 +28,9 @@ interface ModelState {
|
||||||
|
|
||||||
ShowHint: any;
|
ShowHint: any;
|
||||||
setShowHint: (data: any) => void;
|
setShowHint: (data: any) => void;
|
||||||
|
|
||||||
|
ShowLatexOption: any;
|
||||||
|
setShowLatexOption: (data: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useObjectToEdit = create<ModelState>((set) => ({
|
export const useObjectToEdit = create<ModelState>((set) => ({
|
||||||
|
|
@ -52,6 +56,8 @@ export const useObjectToEdit = create<ModelState>((set) => ({
|
||||||
setDeletedQuestions: (data) => set(() => ({ DeletedQuestions: data })),
|
setDeletedQuestions: (data) => set(() => ({ DeletedQuestions: data })),
|
||||||
SavedQuestionData: [],
|
SavedQuestionData: [],
|
||||||
setSavedQuestionData: (data) => set(() => ({ SavedQuestionData: data })),
|
setSavedQuestionData: (data) => set(() => ({ SavedQuestionData: data })),
|
||||||
ShowHint: false,
|
ShowHint: localStorage?.getItem(LocalStorageEnum.HINT_INPUT) === "true",
|
||||||
setShowHint: (data) => set(() => ({ ShowHint: data })),
|
setShowHint: (data) => set(() => ({ ShowHint: data })),
|
||||||
|
ShowLatexOption: localStorage?.getItem(LocalStorageEnum.LATEX_OPTION_INPUT) === "true" ,
|
||||||
|
setShowLatexOption: (data) => set(() => ({ ShowLatexOption: data })),
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user