Compare commits

..

5 Commits

Author SHA1 Message Date
karimaldeen
ba2b5b411c add permission and wait for api #166 2024-09-23 17:27:25 +03:00
karimaldeen
d603736a16 math 2024-09-23 15:12:24 +03:00
karimaldeen
999573fa0c change logo and color 2024-09-22 15:06:15 +03:00
karimaldeen
470cae3b13 add check on reload 2024-09-22 11:09:15 +03:00
karimaldeen
ec4850cbb8 re make 2024-09-21 16:42:38 +03:00
56 changed files with 5359 additions and 729 deletions

View File

@ -12,6 +12,7 @@
"Karim", "Karim",
"katex", "katex",
"Latext", "Latext",
"mathml",
"Popconfirm", "Popconfirm",
"queryqlent", "queryqlent",
"registraion", "registraion",

View File

@ -4,20 +4,14 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" sizes="180x180" href="/App/Logo2.png" /> <link rel="apple-touch-icon" sizes="180x180" href="/App/Logo.svg" />
<link rel="icon" type="image/png" sizes="32x32" href="/App/Logo2.png" /> <link rel="icon" type="image/png" sizes="32x32" href="/App/Logo.svg" />
<link rel="icon" type="image/png" sizes="16x16" href="/App/Logo2.png" /> <link rel="icon" type="image/png" sizes="16x16" href="/App/Logo.svg" />
<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>

4175
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -16,10 +16,16 @@
"dayjs": "^1.11.11", "dayjs": "^1.11.11",
"formik": "^2.4.6", "formik": "^2.4.6",
"i18next": "^23.11.5", "i18next": "^23.11.5",
"install": "^0.13.0",
"katex": "^0.16.11", "katex": "^0.16.11",
"lottie-react": "^2.4.0", "lottie-react": "^2.4.0",
"mathjax": "^3.2.2",
"mathjax-full": "^3.2.2", "mathjax-full": "^3.2.2",
"mathjs": "^13.1.1",
"mathml-to-latex": "^1.4.1", "mathml-to-latex": "^1.4.1",
"mathml2latex": "^1.1.3",
"mml2tex": "^0.0.2",
"npm": "^10.8.3",
"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",
@ -29,6 +35,9 @@
"react-katex": "^3.0.1", "react-katex": "^3.0.1",
"react-latex": "^2.0.0", "react-latex": "^2.0.0",
"react-latex-next": "^3.0.0", "react-latex-next": "^3.0.0",
"react-mathjax": "^1.0.1",
"react-mathjax-preview": "^2.2.6",
"react-mathjax2": "^0.0.2",
"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",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

38
public/App/Logo.svg Normal file
View File

@ -0,0 +1,38 @@
<svg width="157" height="119" viewBox="0 0 157 119" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M153.338 33.2514C154.044 33.5665 154.674 33.9951 155.216 34.5497C155.758 35.1043 156.174 35.7345 156.489 36.453C156.804 37.1715 156.956 37.9404 156.956 38.7723V68.9229C156.956 69.7548 156.804 70.5237 156.489 71.2422C156.174 71.9607 155.746 72.5909 155.216 73.1455C154.687 73.7001 154.056 74.1287 153.338 74.4438C152.62 74.7589 151.851 74.9102 151.019 74.9102H122.645C121.813 74.9102 121.045 74.7589 120.326 74.4438C119.608 74.1287 118.99 73.7001 118.448 73.1455C117.906 72.5909 117.49 71.9607 117.175 71.2422C116.86 70.5237 116.708 69.7548 116.708 68.9229V61.2214H143.317V46.5368H135.767C133.057 46.4612 130.687 45.9822 128.633 45.0747C126.578 44.1671 124.826 43.0579 123.376 41.747C122.028 40.5369 120.919 39.2513 120.074 37.8899C119.229 36.5286 118.612 35.3186 118.221 34.2219C117.83 33.1253 117.692 32.2556 117.78 31.6128C117.868 30.9699 118.158 30.7682 118.637 31.0077C119.923 31.5623 121.435 31.9657 123.162 32.2052C124.889 32.4447 126.691 32.6085 128.557 32.6716C130.422 32.7346 132.25 32.7724 134.053 32.7472C135.855 32.722 137.443 32.7472 138.792 32.7724" fill="white"/>
<path d="M134.67 20.8736C134.872 24.8819 131.822 28.3104 127.864 28.5121C123.855 28.7137 120.402 25.5121 120.25 21.4534C120.112 17.5837 123.212 14.2182 127.095 14.0166C131.09 13.8149 134.469 16.8778 134.67 20.8736Z" fill="#FDBB2E"/>
<path d="M109.393 69.4019C109.608 73.5741 106.431 77.1413 102.31 77.3556C98.1373 77.5698 94.5323 74.2296 94.3811 70.007C94.2298 65.9734 97.4566 62.4693 101.503 62.2676C105.662 62.066 109.179 65.2424 109.393 69.4145V69.4019Z" fill="white"/>
<path d="M109.406 15.9451C109.394 20.1299 106.028 23.5206 101.894 23.4954C97.709 23.4827 94.3057 19.9534 94.3814 15.7182C94.457 11.6847 97.8729 8.35701 101.919 8.38222C106.079 8.40743 109.419 11.7729 109.406 15.9451Z" fill="white"/>
<path d="M103.293 18.6173L102.953 17.3946H100.848L100.444 18.6173H98.9192L101.062 12.4409H102.738L104.869 18.6173H103.293ZM101.894 13.9787L101.201 16.2224H102.524L101.881 13.9787H101.894Z" fill="#0290D2"/>
<path d="M109.406 33.9069C109.394 38.0917 106.028 41.4824 101.894 41.4572C97.709 41.4446 94.3057 37.9153 94.3814 33.6801C94.457 29.6465 97.8729 26.3189 101.919 26.3441C106.079 26.3693 109.419 29.7348 109.406 33.9069Z" fill="white"/>
<path d="M99.3604 37.411V30.5162H102.827C104.289 30.5162 104.932 31.2599 104.932 32.3187C104.932 32.9615 104.541 33.4783 104.037 33.68C104.629 33.8817 105.133 34.3858 105.133 35.369C105.133 36.6043 104.339 37.411 102.524 37.411H99.3604ZM100.911 31.8397V33.201H102.587C103.091 33.201 103.369 32.9867 103.369 32.5203C103.369 32.054 103.104 31.8397 102.549 31.8397H100.923H100.911ZM100.911 34.3858V36.1001H102.638C103.23 36.1001 103.558 35.7472 103.558 35.2052C103.558 34.6631 103.23 34.3858 102.638 34.3858H100.898H100.911Z" fill="#0290D2"/>
<path d="M109.381 51.8057C109.406 55.9905 106.053 59.4064 101.932 59.419C97.7469 59.4316 94.3185 55.9401 94.3563 51.7049C94.3941 47.6714 97.7848 44.3185 101.831 44.3059C105.99 44.3059 109.356 47.6336 109.381 51.8057Z" fill="#FDBB2E"/>
<path d="M105.12 52.9779C104.818 54.6166 103.671 55.7006 101.969 55.7006C100.066 55.7006 98.6038 54.4149 98.6038 51.9317C98.6038 49.4486 99.902 48.0117 101.982 48.0117C103.81 48.0117 104.969 49.1587 105.108 50.6208H103.431C103.242 49.8772 102.675 49.4738 101.994 49.4738C100.822 49.4738 100.305 50.3688 100.305 51.8435C100.305 53.3183 100.81 54.2384 101.919 54.2384C102.763 54.2384 103.23 53.7846 103.431 52.9779H105.108H105.12Z" fill="#0290D2"/>
<path d="M99.5366 73.1456V66.4902H102.146C103.974 66.4902 105.272 67.7255 105.272 69.7423C105.272 71.759 104.1 73.1456 102.36 73.1456H99.5492H99.5366ZM102.045 71.8725C103.217 71.8725 103.684 71.1792 103.684 69.7423C103.684 68.3053 103.242 67.7633 101.932 67.7633H101.049V71.8725H102.058H102.045Z" fill="#0290D2"/>
<path d="M84.1211 39.1252C83.5665 38.5706 82.9362 38.1421 82.2178 37.8269C81.5119 37.5118 80.7304 37.3606 79.8985 37.3606H56.6805L67.7475 29.054L91.5957 11.2813C90.9025 10.8527 90.1588 11.1174 89.1252 11.9241C86.2009 14.2182 83.1757 16.3988 79.6086 19.0584C79.2935 16.6383 79.0918 16.4997 79.2683 14.4577C79.4447 12.4409 78.2977 12.0502 76.8986 11.483C75.2851 10.8275 75.1969 10.5628 73.1423 9.56703C73.2305 8.98721 73.2053 8.83595 73.2558 8.79814C75.4364 7.14691 77.6422 5.5335 79.7851 3.84446C82.9237 1.38653 83.9698 1.28569 83.264 0L62.882 15.1762L57.1973 19.2223C57.1973 19.2223 57.1216 19.2601 57.0712 19.2853C56.8948 19.3988 56.7813 19.4744 56.7057 19.5248C56.8065 19.4492 56.8443 19.4366 56.1763 19.8525C55.7855 20.1046 54.941 20.7475 53.8948 21.5542L46.1933 27.0246C41.164 30.5918 38.7943 42.6924 42.374 47.7091C42.8782 48.6166 43.5337 49.3099 44.3278 49.8141C45.1219 50.3183 46.0294 50.6586 47.0378 50.8351C48.0462 51.0115 49.0546 51.0746 50.063 51.0494H72.2348V61.9273H33.0339V62.1794C33.0339 61.3475 32.8826 60.5786 32.5675 59.8601C32.2524 59.1416 31.8239 58.5114 31.2945 57.9568C30.7525 57.4022 30.1348 56.9736 29.4163 56.6585C28.7105 56.3434 27.929 56.1921 27.0971 56.1921H19.3325V61.9399C19.4081 63.4651 19.4081 64.8894 19.3325 66.2129C19.2569 67.5364 19.156 68.7591 19.0174 69.9061C18.8787 71.154 18.614 72.2758 18.2359 73.259C17.8578 74.2422 17.3788 75.1371 16.799 75.9186C16.2318 76.7001 15.5889 77.406 14.8704 78.0488C14.1646 78.6916 13.4209 79.2841 12.652 79.8513C11.7192 80.5067 10.7487 81.1496 9.76548 81.7546C8.78231 82.3596 7.79915 83.0025 6.82859 83.6831C5.85802 84.3638 4.92524 85.1075 4.0429 85.9268C3.16057 86.7461 2.37908 87.6915 1.72363 88.7629C1.16902 89.6704 0.753072 90.4771 0.475767 91.2082C0.198461 91.9393 0.0472101 92.5569 0.0093958 93.0611C-0.0284185 93.5653 0.0472132 93.9056 0.24889 94.0821C0.437961 94.2585 0.740478 94.2081 1.15644 93.9308C2.54296 93.0233 3.99249 92.2544 5.50506 91.6115C7.01763 90.9687 8.55542 90.4015 10.1184 89.8973C11.6814 89.3931 13.2444 88.9141 14.8074 88.4603C16.3704 88.0066 17.8956 87.4898 19.3956 86.8974C20.6812 86.4058 21.9165 85.8512 23.1139 85.2083C24.3114 84.5655 25.4332 83.7966 26.4668 82.9142C27.5004 82.0319 28.4458 80.9983 29.2777 79.8135C30.1096 78.6286 30.8281 77.2421 31.4079 75.6539H79.8733C80.7052 75.6539 81.4741 75.5026 82.1925 75.1875C82.8984 74.8724 83.5413 74.4438 84.0959 73.8892C84.6505 73.3346 85.079 72.7044 85.3942 71.9859C85.7093 71.2674 85.8605 70.4985 85.8605 69.6666V43.4235C85.8605 42.5916 85.7093 41.8101 85.3942 41.079C85.079 40.3479 84.6505 39.7051 84.0959 39.1504L84.1211 39.1252Z" fill="white"/>
<path d="M85.4824 3.27722C84.4866 4.44947 82.5329 5.68474 81.3228 6.6427C80.0623 7.53764 78.3229 9.05021 76.9111 9.68045C77.9069 8.52081 79.8606 7.27294 81.0707 6.31497C82.3312 5.42003 84.0706 3.90746 85.4824 3.27722Z" fill="#FDBB2E"/>
<path d="M87.4614 5.59656C86.6168 6.64275 84.9026 7.71416 83.8438 8.54608C82.7346 9.32757 81.2346 10.6637 79.9741 11.1679C80.8186 10.1217 82.5329 9.05027 83.5917 8.21835C84.7009 7.43686 86.2009 6.10075 87.4614 5.59656Z" fill="#FDBB2E"/>
<path d="M88.5327 8.76031C87.726 9.7813 86.0622 10.8149 85.0412 11.6216C83.9698 12.3779 82.5203 13.6762 81.2976 14.1552C82.1043 13.1342 83.7682 12.1006 84.7892 11.2939C85.8606 10.5502 87.3101 9.2393 88.5327 8.76031Z" fill="#FDBB2E"/>
<path d="M59.7836 35.0245L51.1941 23.5049L49.9512 24.4317L58.5407 35.9512L59.7836 35.0245Z" fill="url(#paint0_linear_19_2009)"/>
<path d="M61.5795 33.7296L52.99 22.21L51.7471 23.1368L60.3366 34.6564L61.5795 33.7296Z" fill="url(#paint1_linear_19_2009)"/>
<path d="M24.141 109.118V113.353H11.0698V110.366L18.4814 102.488H11.1959V98.2525H23.9393V101.24L16.5025 109.118H24.141Z" fill="white"/>
<path d="M41.649 98.2399V113.353H38.2709V110.328C37.1491 112.408 35.2205 113.706 32.7626 113.706C28.6156 113.706 25.4771 110.303 25.4771 105.79C25.4771 101.278 28.6156 97.8743 32.7626 97.8743C35.2205 97.8743 37.1491 99.1726 38.2709 101.252V98.2273H41.649V98.2399ZM38.2709 105.803C38.2709 103.761 36.2793 102.223 33.6197 102.223C30.9601 102.223 28.9938 103.761 28.9938 105.803C28.9938 107.845 30.9475 109.383 33.6197 109.383C36.2919 109.383 38.2709 107.845 38.2709 105.803Z" fill="white"/>
<path d="M50.649 107.492L48.4557 109.093V113.366H45.0776V92.0383H48.4557V103.446H49.1112L54.2035 98.2651H59.8631L53.3464 105.135L60.0395 113.378H55.6531L50.649 107.517V107.492Z" fill="white"/>
<path d="M75.6819 107.076H62.9763C63.5939 108.702 65.346 109.748 67.7409 109.748C69.5182 109.748 71.0938 109.244 71.7744 108.588H75.5054C74.3836 111.639 71.3585 113.719 67.6527 113.719C62.9763 113.719 59.4722 110.315 59.4722 105.803C59.4722 101.29 62.9637 97.8869 67.6148 97.8869C72.266 97.8869 75.7576 101.265 75.7576 105.891C75.7576 106.282 75.7323 106.723 75.6693 107.076H75.6819ZM63.0015 104.492H72.3038C71.7114 102.866 69.8711 101.857 67.6275 101.857C65.3838 101.857 63.6317 102.891 63.0015 104.492Z" fill="white"/>
<path d="M87.1774 98.0003V103.332C83.5977 103.332 81.6691 104.643 81.6691 107V113.34H78.291V98.2272H81.6691V101.983C82.8539 99.5003 84.7825 97.9877 87.1774 97.9877V98.0003Z" fill="white"/>
<path d="M111.29 98.2399V113.353H107.912V110.328C106.79 112.408 104.862 113.706 102.404 113.706C98.2568 113.706 95.1182 110.303 95.1182 105.79C95.1182 101.278 98.2568 97.8743 102.404 97.8743C104.862 97.8743 106.79 99.1726 107.912 101.252V98.2273H111.29V98.2399ZM107.912 105.803C107.912 103.761 105.92 102.223 103.261 102.223C100.601 102.223 98.6349 103.761 98.6349 105.803C98.6349 107.845 100.589 109.383 103.261 109.383C105.933 109.383 107.912 107.845 107.912 105.803Z" fill="white"/>
<path d="M130.903 105.803C130.903 110.303 127.79 113.719 123.618 113.719C121.16 113.719 119.206 112.382 118.11 110.315V119H114.731V98.2651H118.11V101.315C119.206 99.2357 121.16 97.9122 123.618 97.9122C127.803 97.9122 130.903 101.315 130.903 105.828V105.803ZM127.399 105.803C127.399 103.761 125.42 102.223 122.748 102.223C120.076 102.223 118.097 103.761 118.097 105.803C118.097 107.845 120.088 109.383 122.748 109.383C125.408 109.383 127.399 107.845 127.399 105.803Z" fill="white"/>
<path d="M149.684 105.803C149.684 110.303 146.571 113.719 142.399 113.719C139.941 113.719 137.987 112.382 136.891 110.315V119H133.512V98.2651H136.891V101.315C137.987 99.2357 139.941 97.9122 142.399 97.9122C146.584 97.9122 149.684 101.315 149.684 105.828V105.803ZM146.18 105.803C146.18 103.761 144.201 102.223 141.529 102.223C138.857 102.223 136.878 103.761 136.878 105.803C136.878 107.845 138.87 109.383 141.529 109.383C144.189 109.383 146.18 107.845 146.18 105.803Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_19_2009" x1="49.9496" y1="29.7083" x2="59.7813" y2="29.7083" gradientUnits="userSpaceOnUse">
<stop offset="0.02" stop-color="#FFD140"/>
<stop offset="0.94" stop-color="#F9A61C"/>
<stop offset="1" stop-color="#F7941D"/>
</linearGradient>
<linearGradient id="paint1_linear_19_2009" x1="51.7318" y1="28.416" x2="61.5761" y2="28.416" gradientUnits="userSpaceOnUse">
<stop offset="0.02" stop-color="#FFD140"/>
<stop offset="0.94" stop-color="#F9A61C"/>
<stop offset="1" stop-color="#F7941D"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

BIN
public/App/whiteLogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -8,17 +8,17 @@
"theme_color": "#000000", "theme_color": "#000000",
"icons": [ "icons": [
{ {
"src": "/App/Logo.png", "src": "/App/Logo.svg",
"sizes": "81x113", "sizes": "81x113",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "/App/Logo.png", "src": "/App/Logo.svg",
"sizes": "81x113", "sizes": "81x113",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "/App/Logo.png", "src": "/App/Logo.svg",
"sizes": "81x113", "sizes": "81x113",
"type": "image/png", "type": "image/png",
"purpose": "maskable" "purpose": "maskable"

View File

@ -1,14 +1,22 @@
import React from 'react'; import React from 'react';
import 'katex/dist/katex.min.css';
import { BlockMath } from 'react-katex'; import { BlockMath } from 'react-katex';
import { convertMathMLToLaTeX } from '../../utils/convertMathMLToLaTeX'; import 'katex/dist/katex.min.css';
const LatexPreview = ({ latex }: { latex: string }) => {
console.log(latex);
const sanitizedLatex = latex.replace(/\\_/g, '_');
return (
<div>
const LatexPreview = ({Latex}:{Latex:string}) => { <BlockMath>
{sanitizedLatex}
</BlockMath>
return(
<BlockMath math={Latex} /> </div>
) );
}; };
export default LatexPreview; export default LatexPreview;

View File

@ -15,16 +15,13 @@ const AddLaTexModal = ({name,setLatex,Latex,setIsModalOpen,isModalOpen,setCurren
setCurrentValue:(value:string)=> void setCurrentValue:(value:string)=> void
}) => { }) => {
const {values,setFieldValue} = useFormikContext<any>() const {values,setFieldValue,getFieldProps} = useFormikContext<any>()
const currentValue = getFieldProps(name).value
const handleOk = () => { const handleOk = () => {
console.log(1); const oldValue = currentValue ?? "";
const oldValue = values?.[name];
const newLatex = convertMathMLToLaTeX(Latex); const newLatex = convertMathMLToLaTeX(Latex);
console.log(newLatex,'Latex'); console.log(oldValue);
console.log(newLatex);
if(newLatex){ if(newLatex){
setFieldValue(name, oldValue + " $$ " +newLatex +" $$ "); setFieldValue(name, oldValue + " $$ " +newLatex +" $$ ");

View File

@ -1,110 +0,0 @@
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 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)
}
const [curCentValue, setCurrentValue] = useState(value)
const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
setFieldValue(name, e.target.value);
setCurrentValue(e.target.value)
};
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={curCentValue}
{...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

View File

@ -1,5 +1,4 @@
import TextArea from 'antd/es/input/TextArea'; import TextArea from 'antd/es/input/TextArea';
import { useFormikContext } from 'formik';
import React, { Suspense, useEffect, useState } from 'react'; import React, { Suspense, useEffect, useState } from 'react';
import { parseTextAndLatex } from '../../utils/parseTextAndLatex'; import { parseTextAndLatex } from '../../utils/parseTextAndLatex';
import LatexPreview from '../CustomFields/MathComponent'; import LatexPreview from '../CustomFields/MathComponent';
@ -49,15 +48,24 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
setCurrentValue(e.target.value) setCurrentValue(e.target.value)
}; };
const onBlur = ()=>{ const onBlur = ()=>{
if (curCentValue !== value) {
setFieldValue(name, curCentValue); setFieldValue(name, curCentValue);
} }
}
useEffect(() => { useEffect(() => {
if(Success){ if(Success){
setCurrentValue(null) setCurrentValue(null)
} }
}, [Success]) }, [Success])
useEffect(() => {
if(value){
setCurrentValue(value)
}
}, [value])
const isError = !!touched?.[name] && !!errors?.[name]; const isError = !!touched?.[name] && !!errors?.[name];
const errorMessage = isError ? errors?.[name] as string ?? "" : "" ; const errorMessage = isError ? errors?.[name] as string ?? "" : "" ;
return ( return (
@ -92,10 +100,12 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
<div className='showPreviewInput'> <div className='showPreviewInput'>
{Preview?.map((item: any, index: number) => { {Preview?.map((item: any, index: number) => {
if (item?.isLatex) { if (item?.isLatex) {
console.log(item?.text);
return ( return (
<div key={index} onClick={() => handleEditModal(item)} className='LatexPreview'> <span dir='ltr' key={index} onClick={() => handleEditModal(item)} className='LatexPreview'>
<LatexPreview Latex={item?.text} /> <LatexPreview latex={item?.text} />
</div> </span>
); );
} }
return <div key={index}>{item?.text}</div>; return <div key={index}>{item?.text}</div>;
@ -104,9 +114,10 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
)} )}
</div> </div>
<Suspense fallback={<SpinContainer />}>
<AddLazyModal name={name} Latex={Latex} isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} setLatex={setLatex} setCurrentValue={setCurrentValue} /> <AddLazyModal name={name} Latex={Latex} isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} setLatex={setLatex} setCurrentValue={setCurrentValue} />
<EditLazyModal name={name} Latex={Latex} isModalOpen={isEditModalOpen} setIsModalOpen={setIsEditModalOpen} setLatex={setLatex} /> <EditLazyModal name={name} Latex={Latex} isModalOpen={isEditModalOpen} setIsModalOpen={setIsEditModalOpen} setLatex={setLatex} />
<Suspense fallback={<SpinContainer />}>
</Suspense> </Suspense>
</div> </div>
); );

View File

@ -0,0 +1,42 @@
import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
const useUnsavedChangesWarning = (unsavedChanges: boolean) => {
const [t] = useTranslation();
useEffect(() => {
const handleBeforeUnload = (event: BeforeUnloadEvent) => {
if (unsavedChanges) {
// Prevent default action and stop the event
event.preventDefault();
// Optionally set returnValue to an empty string
event.returnValue = '';
}
};
const handleNavigation = (event: MouseEvent) => {
if (unsavedChanges) {
console.log(t("Access denied: You have unsaved changes!"));
event.preventDefault();
}
};
window.addEventListener('beforeunload', handleBeforeUnload);
// Intercept link clicks (example for <a> elements)
document.querySelectorAll('a').forEach(link => {
link.addEventListener('click', handleNavigation);
});
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
// Clean up event listeners
document.querySelectorAll('a').forEach(link => {
link.removeEventListener('click', handleNavigation);
});
};
}, [unsavedChanges, t]);
};
export default useUnsavedChangesWarning;

View File

@ -34,7 +34,7 @@ const SideBar = ({
return ( return (
<div className={isOpen ? "side_bar" : "side_bar side_bar_closed"}> <div className={isOpen ? "side_bar" : "side_bar side_bar_closed"}>
<div className="side_bar_header"> <div className="side_bar_header">
<img src={isOpen ? "/App/Logo.png" : "/App/Logo2.png"} alt="" /> <img src={isOpen ? "/App/Logo.svg" : "/App/Logo.svg"} alt="" />
<HiMenuAlt3 onClick={toggleSidebar} /> <HiMenuAlt3 onClick={toggleSidebar} />
</div> </div>
{/* <Divider /> */} {/* <Divider /> */}

View File

@ -6,7 +6,6 @@ const Form = () => {
<Row className="w-100"> <Row className="w-100">
<Col> <Col>
<ValidationField placeholder="name" label="name" name="name" /> <ValidationField placeholder="name" label="name" name="name" />
<ValidationField placeholder="created_at" label="created_at" name="created_at" />
</Col> </Col>
</Row> </Row>
); );

View File

@ -0,0 +1,29 @@
import React from 'react'
import DataTable from '../../../../Layout/Dashboard/Table/DataTable'
import { useColumns } from './useTableColumns'
import { useFormikContext } from 'formik'
const FormTable = ({response}:{response:any}) => {
const {values} = useFormikContext<any>()
console.log(response);
const data = response?.data?.data?.abilities ;
console.log(data);
return (
<div>
<DataTable
response={response}
useColumns={useColumns}
dataSource={data}
pagination={false}
loading={false}
rowKey={"name"}
/>
</div>
)
}
export default FormTable

View File

@ -4,8 +4,6 @@ import { Spin } from "antd";
import useSetPageTitle from "../../../../Hooks/useSetPageTitle"; import useSetPageTitle from "../../../../Hooks/useSetPageTitle";
import PageHeader from "../../../../Layout/Dashboard/PageHeader"; import PageHeader from "../../../../Layout/Dashboard/PageHeader";
import FilterLayout from "../../../../Layout/Dashboard/FilterLayout"; import FilterLayout from "../../../../Layout/Dashboard/FilterLayout";
import FormikForm from "../../../../Layout/Dashboard/FormikForm";
import { getInitialValues } from "./Model/formUtil";
const Table = lazy(() => import("./Table")); const Table = lazy(() => import("./Table"));
const TableHeader = () => { const TableHeader = () => {
@ -29,12 +27,8 @@ const TableHeader = () => {
filterTitle="page_header.permissions" filterTitle="page_header.permissions"
haveFilter={false} haveFilter={false}
/> />
<FormikForm
initialValues={getInitialValues}
handleSubmit={()=>(console.log(1))}>
<Table />
</FormikForm> <Table />
</Suspense> </Suspense>
</div> </div>
); );

View File

@ -1,25 +1,109 @@
import React from "react"; import React from "react";
import DataTable from "../../../../Layout/Dashboard/Table/DataTable";
import { useColumns } from "./useTableColumns";
import { useFilterState } from "../../../../Components/Utils/Filter/FilterState"; import { useFilterState } from "../../../../Components/Utils/Filter/FilterState";
import { useFilterStateState } from "../../../../zustand/Filter"; import { useFilterStateState } from "../../../../zustand/Filter";
import { useAddPermissions, useGetAllPermissions } from "../../../../api/Permissions";
import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../../../enums/params";
import { Form, Formik } from "formik";
import FormTable from "./FormTable";
import { useTranslation } from "react-i18next";
import { useGetAllRole } from "../../../../api/role"; import { useGetAllRole } from "../../../../api/role";
import { useGetAllTag } from "../../../../api/tags";
const App: React.FC = () => {
const App: React.FC = () => {
const { role_id } = useParams<ParamsEnum>();
const { filterState } = useFilterState(); const { filterState } = useFilterState();
const { Filter } = useFilterStateState(); const { Filter } = useFilterStateState();
const name = Filter?.name ; const name = Filter?.name;
const sort_by = Filter?.sort_by ; const sort_by = Filter?.sort_by;
const response = useGetAllTag({ const Data = [
"absence::delete",
"absence::index",
"absence::show",
"absence::store",
"absence::update",
"admin::delete",
"admin::index",
"admin::show",
"admin::update",
];
const response = useGetAllRole({
pagination: true, pagination: true,
show:role_id,
name, name,
sort_by, sort_by,
...filterState, ...filterState,
}); });
/// time complexity O(n) -_-
return <DataTable response={response} useColumns={useColumns} />; const changePermissionShape = (Data:string[])=>{
const newArray: Array<{ name: any; [key: string]: boolean }> = [];
const hashMap = new Map<string, number>();
for (let i = 0; i < Data.length; i++) {
const [permission, value] = Data[i].split("::");
const existingIndex = hashMap.get(permission);
if (existingIndex !== undefined) {
newArray[existingIndex][value] = true;
if(newArray[existingIndex]["index"] && newArray[existingIndex]["show"] && newArray[existingIndex]["store"] && newArray[existingIndex]["update"] && newArray[existingIndex]["delete"]){
newArray[existingIndex]["ALL"] = true;
}
} else {
const newObject = { name: permission, [value]: true } as any;
newArray.push(newObject);
hashMap.set(permission, newArray.length - 1);
}
}
return newArray
}
const newShapeArray = changePermissionShape(Data)
const [t] = useTranslation()
console.log(response,"response");
const reverseChangePermissionShape = (
newArray: Array<{ name: any; [key: string]: boolean }>
): string[] => {
const Data: string[] = [];
newArray.forEach((obj) => {
const permission = obj.name;
Object.keys(obj).forEach((key) => {
if (key !== "name" && key !== "ALL" && obj[key]) {
Data.push(`${permission}::${key}`);
}
});
});
return Data;
};
const {mutate} = useAddPermissions()
const handelSubmit = (values:any)=>{
const dataToSend = reverseChangePermissionShape(values);
mutate(dataToSend)
}
return (
<Formik initialValues={newShapeArray} onSubmit={handelSubmit} enableReinitialize>
{({handleSubmit})=>{
return (
<Form>
<FormTable response={response} />
<div className="permissions_submit_button">
<button className="button" onClick={()=> handleSubmit()
} type="submit" >{t("practical.submit")}</button>
</div>
</Form>
)
}}
</Formik>
);
}; };
export default App; export default App;

View File

@ -1,35 +1,94 @@
import { TableColumnsType } from "antd"; import { Checkbox, TableColumnsType } from "antd";
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { useModalState } from "../../../../zustand/Modal";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Role } from "../../../../types/App"; import { ABILITIES_VALUES_ENUM } from "../../../../enums/abilities";
import { ModalEnum } from "../../../../enums/Model"; import { useFormikContext } from "formik";
import ValidationField from "../../../../Components/ValidationField/ValidationField";
export const useColumns = () => { export const useColumns = () => {
const [t] = useTranslation(); const [t] = useTranslation();
const {values,setValues} = useFormikContext<any>()
const { setIsOpen } = useModalState((state) => state); const onChange = (type:any,index:any) => {
const cloneValue = JSON.parse(JSON.stringify(values))
const { setObjectToEdit } = useObjectToEdit((state) => state); if (!cloneValue[index]) {
const handleEdit = (record: any) => { cloneValue[index] = {};
setObjectToEdit(record); }
setIsOpen(ModalEnum?.ROLE_EDIT); cloneValue[index][type] = !cloneValue[index][type];
setValues(cloneValue)
}; };
const columns: TableColumnsType<Role> = [
// { const onChangeAll = (index:any) => {
// title: <ValidationField name="empty" type="Checkbox"/>, const cloneValue = JSON.parse(JSON.stringify(values))
// dataIndex: "id", if (!cloneValue[index]) {
// key: "id", cloneValue[index] = {};
// align: "center", }
// render: (_text) => { if(cloneValue[index]["ALL"]){
// return ( cloneValue[index] = {
// <ValidationField name="empty" type="Checkbox"/> name:cloneValue[index]?.name ,
// ); delete: false,
// }, index: false,
// }, show: false,
store: false,
update: false,
ALL: false
}
}else{
cloneValue[index] = {
name:cloneValue[index]?.name ,
delete: true,
index: true,
show: true,
store: true,
update: true,
ALL: true
}
}
setValues(cloneValue)
};
const CheckBoxFieldALL = ({record,index}:{record:any,index:any})=>{
const isChecked = record?.ALL ;
return <Checkbox onChange={()=>onChangeAll(index)} checked={isChecked} />;
}
const CheckBoxField = ({record,type,index}:{record:any,type:string,index:number})=>{
const isChecked = record?.[type] ;
return <Checkbox onChange={()=>onChange(type,index)} checked={isChecked} />;
}
const CheckBoxFieldALLPermissions = ()=>{
const cloneValue = JSON.parse(JSON.stringify(values)) ;
const IsAllValuesTrue = cloneValue?.every((item:any)=>{
return !!item?.index && !!item?.show && !!item?.store && !!item?.update && !!item?.delete
})
const onChangeAllPermissions = ()=>{
const newShape =cloneValue?.map((item:any)=>{
if(IsAllValuesTrue){
return {...item,delete: false,index: false,show: false,store: false,update: false,ALL: false}
}else{
return {...item,delete: true,index: true,show: true,store: true,update: true,ALL: true}
}
})
setValues(newShape)
}
return <Checkbox onChange={()=>onChangeAllPermissions()} checked={IsAllValuesTrue} />;
}
const columns: TableColumnsType<any> = [
{ {
title: t("columns.units"), title: <div className="df"> <CheckBoxFieldALLPermissions/> {t("columns.units")} </div>,
dataIndex: "name", dataIndex: "name",
key: "name", key: "name",
align: "center", align: "center",
@ -39,9 +98,9 @@ export const useColumns = () => {
dataIndex: "id", dataIndex: "id",
key: "id", key: "id",
align: "center", align: "center",
render: (_text) => { render: (_text,record,index) => {
return ( return (
<ValidationField name="empty" type="Checkbox"/> <CheckBoxField record={record} index={index} type={ABILITIES_VALUES_ENUM.STORE} />
); );
}, },
}, },
@ -50,9 +109,9 @@ export const useColumns = () => {
dataIndex: "id", dataIndex: "id",
key: "id", key: "id",
align: "center", align: "center",
render: (_text) => { render: (_text,record,index) => {
return ( return (
<ValidationField name="empty" type="Checkbox"/> <CheckBoxField record={record} index={index} type={ABILITIES_VALUES_ENUM.INDEX} />
); );
}, },
}, },
@ -61,9 +120,9 @@ export const useColumns = () => {
dataIndex: "id", dataIndex: "id",
key: "id", key: "id",
align: "center", align: "center",
render: (_text) => { render: (_text,record,index) => {
return ( return (
<ValidationField name="empty" type="Checkbox"/> <CheckBoxField record={record} index={index} type={ABILITIES_VALUES_ENUM.UPDATE} />
); );
}, },
}, },
@ -72,23 +131,36 @@ export const useColumns = () => {
dataIndex: "id", dataIndex: "id",
key: "id", key: "id",
align: "center", align: "center",
render: (_text) => { render: (_text,record,index) => {
return ( return (
<ValidationField name="empty" type="Checkbox"/> <CheckBoxField record={record} index={index} type={ABILITIES_VALUES_ENUM.DELETE} />
); );
}, },
}, },
{
title: t("columns.show"),
dataIndex: "id",
key: "id",
align: "center",
render: (_text,record,index) => {
return (
<CheckBoxField record={record} index={index} type={ABILITIES_VALUES_ENUM.SHOW} />
);
},
},
{ {
title: t("columns.allow_everyone"), title: t("columns.allow_everyone"),
dataIndex: "id", dataIndex: "id",
key: "id", key: "id",
align: "center", align: "center",
render: (_text) => { render: (_text,record,index) => {
return ( return (
<ValidationField name="empty" type="Checkbox"/> <CheckBoxFieldALL record={record} index={index} />
); );
}, },
}, },
]; ];
return columns; return columns;

View File

@ -1,5 +1,4 @@
import React from "react"; import React from "react";
import { useGetAllTag } from "../../../api/tags";
import DataTable from "../../../Layout/Dashboard/Table/DataTable"; import DataTable from "../../../Layout/Dashboard/Table/DataTable";
import { useColumns } from "./useTableColumns"; import { useColumns } from "./useTableColumns";
import { useFilterState } from "../../../Components/Utils/Filter/FilterState"; import { useFilterState } from "../../../Components/Utils/Filter/FilterState";

View File

@ -3,7 +3,7 @@ import { ModalEnum } from "../../../enums/Model";
import { useObjectToEdit } from "../../../zustand/ObjectToEditState"; import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
import { useModalState } from "../../../zustand/Modal"; import { useModalState } from "../../../zustand/Modal";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { canDeleteRole,canEditRole } from "../../../utils/hasAbilityFn"; import { canDeleteRole,canEditRole, canShowRole } from "../../../utils/hasAbilityFn";
import ActionButtons from "../../../Components/Table/ActionButtons"; import ActionButtons from "../../../Components/Table/ActionButtons";
import { Role } from "../../../types/App"; import { Role } from "../../../types/App";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@ -18,7 +18,7 @@ export const useColumns = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const handelShow = (record: Role) => { const handelShow = (record: Role) => {
navigate(`/${record?.id}`); navigate(`${record?.id}/${ABILITIES_ENUM?.PERMISSIONS}`);
}; };
const handelDelete = (record: any) => { const handelDelete = (record: any) => {
@ -61,9 +61,11 @@ export const useColumns = () => {
<ActionButtons <ActionButtons
canDelete={canEditRole} canDelete={canEditRole}
canEdit={canDeleteRole} canEdit={canDeleteRole}
canShow={canShowRole}
index={index} index={index}
onDelete={() => handelDelete(record)} onDelete={() => handelDelete(record)}
onEdit={() => handleEdit(record)} onEdit={() => handleEdit(record)}
onShow={()=>handelShow(record)}
/> />
); );
}, },

View File

@ -36,7 +36,6 @@ const DynamicTags = () => {
if (currentElement) { if (currentElement) {
currentElement.focus(); // Set focus on the element currentElement.focus(); // Set focus on the element
} }
console.log(currentElement,"currentElement");
}, [lastElementIndex]) }, [lastElementIndex])
// console.log(formik?.values); // console.log(formik?.values);

View File

@ -167,7 +167,6 @@ const DrapableTable: React.FC = () => {
const [t] = useTranslation(); const [t] = useTranslation();
const columns = useColumns(); const columns = useColumns();
const sortedDataSource = dataSource.sort((a, b) => a.order - b.order); const sortedDataSource = dataSource.sort((a, b) => a.order - b.order);
console.log(sortedDataSource, "sortedDataSource");
return ( return (
<DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}> <DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>

View File

@ -1,38 +1,26 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { Spin } from "antd";
import { import {
getInitialValues,
getValidationSchema,
getInitialValuesBase,
getValidationSchemaBase,
processTags, processTags,
} from "./formUtil"; } from "./formUtil";
import { useAddQuestion, useAddQuestionAsync } from "../../../api/Question"; import { useAddQuestion, useAddQuestionAsync } from "../../../api/Question";
import { useTranslation } from "react-i18next"; import { useParams } from "react-router-dom";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import { ParamsEnum } from "../../../enums/params"; import { ParamsEnum } from "../../../enums/params";
import { useObjectToEdit } from "../../../zustand/ObjectToEditState"; import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
import Header from "../../../Components/exercise/Header";
import { Question } from "../../../types/Item"; import { Question } from "../../../types/Item";
import BaseForm from "./Model/Malty/Form"; import BaseFormContainer from "./Model/AddForm/BaseForm";
import ModelForm from "./Model/ModelForm"; import FormContainer from "./Model/AddForm/Form";
import { toast } from "react-toastify"; import { handleValidateBaseQuestion, handleValidateSingleQuestion } from "./Model/AddForm/ValidationFn";
import { Form, Formik } from "formik"; import useUnsavedChangesWarning from "../../../Hooks/useUnsavedChangesWarning";
import { MdOutlineArrowForwardIos } from "react-icons/md"; import { useFormikContext } from "formik";
const AddPage: React.FC = () => { const AddPage: React.FC = () => {
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 } = const { isBseQuestion, setTagsSearch, setSuccess } = useObjectToEdit();
useObjectToEdit();
const [t] = useTranslation();
const { subject_id, lesson_id } = useParams<ParamsEnum>(); const { subject_id, lesson_id } = useParams<ParamsEnum>();
const handleFormSubmit = ( values: any) => { const handleFormSubmit = (values: any) => {
const DataToSend = structuredClone(values); const DataToSend = structuredClone(values);
setTagsSearch(null); setTagsSearch(null);
@ -100,215 +88,26 @@ const AddPage: React.FC = () => {
} }
}; };
const handleValidateSingleQuestion = (values:any,isValid:boolean,handleSubmit:any)=>{
const haveMoreThanOneAnswer = values?.answers?.length > 1;
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 content = values.content ;
const content_image = values.content_image ;
const haveContentOrContentImage = !!content || !!content_image ;
console.log(haveImageOrContent,"haveImageOrContent");
if(!haveContentOrContentImage){
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
return false;
}
if(!haveMoreThanOneAnswer){
toast.error(t("validation.it_should_have_more_than_one_answers")) ;
return false ;
}
if(!haveOneAnswerRight){
toast.error(t("validation.it_should_have_more_than_one_correct_answers")) ;
return false ;
}
if(haveImageOrContent){
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
return false
}
console.log(1);
if(isValid){
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_image = Question.content_image ;
const haveContentOrContentImage = !!content || !!content_image ;
if(!haveContentOrContentImage){
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
return false;
}
//// answers
const answers = Question?.answers;
const haveAnswers = answers?.length > 0;
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
const haveOneAnswerRight = haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true);
const haveImageOrContent = haveOneAnswerRight && answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
if (!haveAnswers) {
toast.error(t("validation.it_should_have_more_than_one_answers"));
return false;
}
if (!haveMoreThanOneAnswer) {
toast.error(t("validation.it_should_have_more_than_one_answers"));
return false;
}
if (!haveOneAnswerRight) {
toast.error(t("validation.it_should_have_more_than_one_correct_answers"));
return false;
}
if(haveImageOrContent){
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
return false
}
return true
});
console.log(1);
if(isValid && isValidate){
console.log(2);
handleSubmit(values)
}
};
const navigate = useNavigate();
const handleNavigateToPage = () => {
const cleanedUrl = location.pathname?.replace("/Question/add", "");
navigate(cleanedUrl);
};
const handleCancel = () => {
navigate(-1);
};
const Loading = LoadingAsync || isLoading; const Loading = LoadingAsync || isLoading;
useEffect(() => { useEffect(() => {
if (isSuccess) { if (isSuccess) {
setSuccess(true); setSuccess(true);
} }
}, [isSuccess]); }, [isSuccess]);
if (isBseQuestion) { if (isBseQuestion) {
return ( return (
<div className="QuestionPractical"> <BaseFormContainer Loading={Loading} handleFormSubmit={handleFormSubmit} handleValidateBaseQuestion={handleValidateBaseQuestion} />
<header>
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.add_new_question")}
</header>
<div className="exercise_add">
<Formik
onSubmit={handleFormSubmit}
initialValues={getInitialValuesBase({} as any)}
validationSchema={getValidationSchemaBase}
enableReinitialize
>
{({ values,isValid,handleSubmit }) => (
<Form className="w-100">
<main className="w-100 exercise_add_main">
<Header />
<BaseForm />
<div className="exercise_add_buttons">
<div onClick={handleCancel}>{t("practical.back")}</div>
<button disabled={Loading} className="relative" type="button"
onClick={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
onSubmit={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
>
{t("practical.add")}
{Loading && (
<span className="Spinier_Div">
<Spin />
</span>
)}
</button>
</div>
</main>
</Form>
)}
</Formik>
</div>
</div>
); );
} }
return ( return (
<div className="QuestionPractical"> <FormContainer Loading={Loading} handleFormSubmit={handleFormSubmit} handleValidateSingleQuestion={handleValidateSingleQuestion} />
<header>
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.add_new_question")}
</header>
<div className="exercise_add">
<Formik
enableReinitialize={true}
initialValues={getInitialValues({} as any)}
validationSchema={getValidationSchema}
validateOnMount={true}
onSubmit={(values) => {
handleFormSubmit(values);
}}
>
{({ values,isValid ,handleSubmit}) => (
<Form className="w-100">
<main className="w-100 exercise_add_main">
<Header />
<ModelForm />
<div className="exercise_add_buttons">
<div onClick={handleCancel}>{t("practical.back")}</div>
<div
className="relative"
onClick={()=>{ handleSubmit() }}
>
{t("practical.add")}
{Loading && (
<span className="Spinier_Div">
<Spin />
</span>
)}
</div>
</div>
</main>
</Form>
)}
</Formik>
</div>
</div>
); );
}; };

View File

@ -1,10 +1,5 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { Checkbox, Modal, Popover, Spin } from "antd";
import { import {
getInitialValues,
getValidationSchema,
getInitialValuesBase,
getValidationSchemaBase,
processTags, processTags,
} from "./formUtil"; } from "./formUtil";
import { import {
@ -19,25 +14,20 @@ import { ParamsEnum } from "../../../enums/params";
import { useObjectToEdit } from "../../../zustand/ObjectToEditState"; import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
import { removeStringKeys } from "../../../utils/removeStringKeys"; import { removeStringKeys } from "../../../utils/removeStringKeys";
import SpinContainer from "../../../Components/Layout/SpinContainer"; import SpinContainer from "../../../Components/Layout/SpinContainer";
import ModelForm from "./Model/ModelForm";
import BaseForm from "./Model/Malty/Form";
import { Question } from "../../../types/Item"; import { Question } from "../../../types/Item";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import { deletePathSegments } from "../../../utils/deletePathSegments"; import { deletePathSegments } from "../../../utils/deletePathSegments";
import { Form, Formik } from "formik"; import BaseFormContainer from "./Model/EditForm/BaseFormContainer";
import { MdOutlineArrowForwardIos } from "react-icons/md"; import FormContainer from "./Model/EditForm/FormContainer";
import { SettingFilled } from "@ant-design/icons";
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 , ShowLatexOption,setShowLatexOption } = const { isBseQuestion, setIsBseQuestion, setTagsSearch, DeletedQuestions, ShowHint, setShowHint, ShowLatexOption, setShowLatexOption } =
useObjectToEdit(); useObjectToEdit();
const { mutate, isSuccess, isLoading } = useUpdateQuestion(); const { mutate, isSuccess, isLoading } = useUpdateQuestion();
const { mutate: DeleteQuestion } = useDeleteQuestion(); const { mutate: DeleteQuestion } = useDeleteQuestion();
const { mutate: mutateAdd , isLoading:LoadingAsync } = useAddQuestion(); const { mutate: mutateAdd, isLoading: LoadingAsync } = useAddQuestion();
const { data, isLoading: dataLoading } = useGetAllQuestion({ const { data, isLoading: dataLoading } = useGetAllQuestion({
show: question_id, show: question_id,
@ -46,7 +36,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 isPaginated: false
}); });
const objectToEdit = { ...data?.data, Questions: Questions?.data }; const objectToEdit = { ...data?.data, Questions: Questions?.data };
@ -79,7 +69,7 @@ const EditPage: React.FC = () => {
console.log(DeletedQuestions, "DeletedQuestions"); console.log(DeletedQuestions, "DeletedQuestions");
console.log(UpdateBseQuestion); console.log(UpdateBseQuestion);
// mutate(UpdateBseQuestion); mutate(UpdateBseQuestion);
DeletedQuestions?.map((item: any) => { DeletedQuestions?.map((item: any) => {
DeleteQuestion({ id: item?.id }); DeleteQuestion({ id: item?.id });
@ -93,7 +83,7 @@ const EditPage: React.FC = () => {
if (item?.id) { if (item?.id) {
const itemToSend = structuredClone(item); const itemToSend = structuredClone(item);
const keysToRemove = ["content_image"]; const keysToRemove = ["content_image"];
console.log(itemToSend,"itemToSend"); console.log(itemToSend, "itemToSend");
const updatedObject = removeStringKeys(itemToSend, keysToRemove); const updatedObject = removeStringKeys(itemToSend, keysToRemove);
console.log(updatedObject, "updatedObject"); console.log(updatedObject, "updatedObject");
@ -102,13 +92,13 @@ const EditPage: React.FC = () => {
const oldAnswers = [] as any; const oldAnswers = [] as any;
const newAnswers = [] as any; const newAnswers = [] as any;
if(updatedObject?.content_image === null){ if (updatedObject?.content_image === null) {
updatedObject["content_image"] = "" updatedObject["content_image"] = ""
} }
updatedObject?.answers?.forEach((item: any) => { updatedObject?.answers?.forEach((item: any) => {
if (item?.id) { if (item?.id) {
if(item?.content_image === null){ if (item?.content_image === null) {
item["content_image"] = "" item["content_image"] = ""
} }
@ -126,15 +116,15 @@ const EditPage: React.FC = () => {
mutate({ mutate({
...updatedObject, ...updatedObject,
answers, answers,
tags:tagToSend, tags: tagToSend,
}); });
} else { } else {
console.log(values?.id); console.log(values?.id);
const tags = processTags(item); const tags = processTags(item);
console.log(item,"DataToSend"); console.log(item, "DataToSend");
console.log(tags,"tags"); console.log(tags, "tags");
mutateAdd({ mutateAdd({
...item, ...item,
subject_id: subject_id, subject_id: subject_id,
@ -158,12 +148,12 @@ const EditPage: React.FC = () => {
const newAnswers = [] as any; const newAnswers = [] as any;
updatedObject?.answers?.forEach((item: any) => { updatedObject?.answers?.forEach((item: any) => {
if (item?.id) { if (item?.id) {
console.log(item,"item"); console.log(item, "item");
const deletedImage = item?.content_image === null const deletedImage = item?.content_image === null
if(deletedImage){ if (deletedImage) {
oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0, content_image:"" }); oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0, content_image: "" });
}else{ } else {
oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0 }); oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0 });
} }
@ -187,50 +177,47 @@ const EditPage: React.FC = () => {
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const handleCancel = () => {
navigate(-1);
};
const handleValidateSingleQuestion = (values:any,isValid:boolean,handleSubmit: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")}`);
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;
} }
if(!haveOneAnswerRight){ if (!haveOneAnswerRight) {
toast.error(t("validation.it_should_have_more_than_one_correct_answers")) ; toast.error(t("validation.it_should_have_more_than_one_correct_answers"));
return false ; return false;
} }
if(haveImageOrContent){ if (haveImageOrContent) {
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer")) toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
return false return false
} }
console.log(1); console.log(1);
if(isValid){ if (isValid) {
handleSubmit(values) handleSubmit(values)
} }
} }
const handleValidateBaseQuestion = (values: any,isValid:boolean,handleSubmit: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); 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;
} }
@ -239,10 +226,10 @@ const handleValidateBaseQuestion = (values: any,isValid:boolean,handleSubmit:any
const isValidate = values?.Questions?.every((Question: any, QuestionsIndex: number) => { const isValidate = values?.Questions?.every((Question: any, QuestionsIndex: number) => {
const content = Question.content ; const content = Question.content;
const content_image = Question.content_image ; const content_image = Question.content_image;
const haveContentOrContentImage = !!content || !!content_image ; const haveContentOrContentImage = !!content || !!content_image;
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;
} }
@ -253,7 +240,7 @@ const handleValidateBaseQuestion = (values: any,isValid:boolean,handleSubmit:any
const haveAnswers = answers?.length > 0; const haveAnswers = answers?.length > 0;
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1; const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
const haveOneAnswerRight = haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true); const haveOneAnswerRight = 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))
@ -273,7 +260,7 @@ const handleValidateBaseQuestion = (values: any,isValid:boolean,handleSubmit:any
return false; return false;
} }
if(haveImageOrContent){ if (haveImageOrContent) {
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer")) toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
return false return false
} }
@ -283,17 +270,12 @@ const handleValidateBaseQuestion = (values: any,isValid:boolean,handleSubmit:any
console.log(1); console.log(1);
if(isValid && isValidate){ if (isValid && isValidate) {
console.log(2); console.log(2);
handleSubmit(values) handleSubmit(values)
} }
}; };
const handleNavigateToPage = () => {
const cleanedUrl = location.pathname.replace(/\/Question\/\d+$/, "");
navigate(cleanedUrl);
};
useEffect(() => { useEffect(() => {
if (isSuccess) { if (isSuccess) {
@ -302,31 +284,6 @@ const handleNavigateToPage = () => {
} }
}, [isSuccess]); }, [isSuccess]);
const onChangeHint: CheckboxProps['onChange'] = (e) => {
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 = (
<div>
<Checkbox checked={ShowHint} onChange={onChangeHint}>
{ t("header.show_hint")}
</Checkbox>
<Checkbox checked={ShowLatexOption} onChange={onChangeLatexOption}>
{ t("header.show_MMl")}
</Checkbox>
</div>
);
@ -337,119 +294,13 @@ const handleNavigateToPage = () => {
} }
if (objectToEdit?.isBase) { if (objectToEdit?.isBase) {
return ( return (
<BaseFormContainer t={t} Loading={Loading} handleSubmit={handleSubmit} handleValidateBaseQuestion={handleValidateBaseQuestion} objectToEdit={objectToEdit} />
<div className="QuestionPractical">
<header>
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.edit_question")}
</header>
<div className="exercise_add">
<Formik
onSubmit={handleSubmit}
initialValues={getInitialValuesBase(objectToEdit)}
validationSchema={getValidationSchemaBase}
enableReinitialize
>
{({ values,isValid,handleSubmit }) => (
<Form className="w-100">
<main className="w-100 exercise_add_main">
{/* <Header/> */}
<header className="exercise_add_header mb-4">
<div>
{t("practical.edit")} {t("models.exercise")}{" "}
</div>
<div className="SettingEdit">
<Popover trigger="click" content={contentSetting}>
<SettingFilled/>
</Popover>
<div>{t("header.exercise")}</div>
</div>
</header>
<BaseForm />
<div className="exercise_add_buttons">
<div onClick={handleCancel}>{t("practical.back")}</div>
<button disabled={Loading} className="relative" type="button"
onClick={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
onSubmit={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
> {t("practical.edit")}
{Loading && (
<span className="Spinier_Div">
<Spin />
</span>
)}
</button>
</div>
</main>
</Form>
)}
</Formik>
</div>
</div>
); );
} }
return ( return (
<FormContainer t={t} Loading={Loading} handleSubmit={handleSubmit} handleValidateSingleQuestion={handleValidateSingleQuestion} objectToEdit={objectToEdit} />
<div className="QuestionPractical">
<header>
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.edit_question")}
</header>
<div className="exercise_add">
<Formik
enableReinitialize={true}
initialValues={getInitialValues(objectToEdit)}
validationSchema={getValidationSchema}
onSubmit={(values) => {
handleSubmit(values);
}}
>
{({ values , dirty,isValid,handleSubmit }) => (
<Form className="w-100">
<main className="w-100 exercise_add_main">
{/* <Header/> */}
<header className="exercise_add_header mb-4">
<div>
{t("practical.edit")} {t("models.exercise")}{" "}
</div>
<div className="SettingEdit">
<Popover trigger="click" content={contentSetting}>
<SettingFilled/>
</Popover>
<div>{t("header.exercise")}</div>
</div>
</header>
<ModelForm />
<div className="exercise_add_buttons">
<div onClick={handleCancel}>{t("practical.back")}</div>
<div
className="relative"
onClick={()=>{ Loading ? ()=>{} : handleValidateSingleQuestion(values,isValid,handleSubmit) }}
> {t("practical.edit")}
{Loading && (
<span className="Spinier_Div">
<Spin />
</span>
)}
</div>
</div>
</main>
</Form>
)}
</Formik>
</div>
</div>
); );
}; };

View File

@ -0,0 +1,72 @@
import { Form, Formik, useFormikContext } from 'formik'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { MdOutlineArrowForwardIos } from 'react-icons/md'
import { getInitialValuesBase, getValidationSchemaBase } from '../../formUtil'
import Header from '../../../../../Components/exercise/Header'
import { useNavigate } from 'react-router-dom'
import { Spin } from 'antd'
import BaseForm from "../../Model/Malty/Form";
const BaseFormContainer = ({handleFormSubmit,Loading,handleValidateBaseQuestion}:{handleFormSubmit:any,Loading:any,handleValidateBaseQuestion:any}) => {
const [t] = useTranslation()
const navigate = useNavigate();
const handleNavigateToPage = () => {
const cleanedUrl = location.pathname?.replace("/Question/add", "");
navigate(cleanedUrl);
};
const handleCancel = () => {
navigate(-1);
};
return (
<div className="QuestionPractical">
<header>
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.add_new_question")}
</header>
<div className="exercise_add">
<Formik
onSubmit={handleFormSubmit}
initialValues={getInitialValuesBase({} as any)}
validationSchema={getValidationSchemaBase}
enableReinitialize
>
{({ values,isValid,handleSubmit ,dirty}) => (
<Form className="w-100">
<main className="w-100 exercise_add_main">
<Header />
<BaseForm />
<div className="exercise_add_buttons">
<div onClick={handleCancel}>{t("practical.back")}</div>
<button disabled={Loading} className={`relative ${dirty ? "" : "disabled"}`} type="button"
onClick={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit,t) }}
>
{t("practical.add")}
{Loading && (
<span className="Spinier_Div">
<Spin />
</span>
)}
</button>
</div>
</main>
</Form>
)}
</Formik>
</div>
</div>
)
}
export default BaseFormContainer

View File

@ -0,0 +1,72 @@
import { Form, Formik, useFormikContext } from 'formik'
import { useTranslation } from 'react-i18next'
import { MdOutlineArrowForwardIos } from 'react-icons/md'
import { getInitialValues, getValidationSchema } from '../../formUtil'
import Header from '../../../../../Components/exercise/Header'
import { useNavigate } from 'react-router-dom'
import { Spin } from 'antd'
import ModelForm from "../../Model/ModelForm";
const FormContainer = ({handleFormSubmit,Loading,handleValidateSingleQuestion}:{handleFormSubmit:any,Loading:any,handleValidateSingleQuestion:any}) => {
const [t] = useTranslation()
const navigate = useNavigate();
const handleNavigateToPage = () => {
const cleanedUrl = location.pathname?.replace("/Question/add", "");
navigate(cleanedUrl);
};
const handleCancel = () => {
navigate(-1);
};
return (
<div className="QuestionPractical">
<header>
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.add_new_question")}
</header>
<div className="exercise_add">
<Formik
enableReinitialize={true}
initialValues={getInitialValues({} as any)}
validationSchema={getValidationSchema}
validateOnMount={true}
onSubmit={(values) => {
handleFormSubmit(values);
}}
>
{({ values,isValid ,handleSubmit,dirty}) => (
<Form className="w-100">
<main className="w-100 exercise_add_main">
<Header />
<ModelForm />
<div className="exercise_add_buttons">
<div onClick={handleCancel}>{t("practical.back")}</div>
<div
className={`relative ${dirty ? "" : "disabled"}`}
onClick={()=>{ Loading ? ()=>{} : handleValidateSingleQuestion(values,isValid,handleSubmit,t) }}
>
{t("practical.add")}
{Loading && (
<span className="Spinier_Div">
<Spin />
</span>
)}
</div>
</div>
</main>
</Form>
)}
</Formik>
</div>
</div>
)
}
export default FormContainer

View File

@ -0,0 +1,100 @@
import { toast } from "react-toastify";
export const handleValidateSingleQuestion = (values:any,isValid:boolean,handleSubmit:any,t:any)=>{
const haveMoreThanOneAnswer = values?.answers?.length > 1;
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 content = values.content ;
const content_image = values.content_image ;
const haveContentOrContentImage = !!content || !!content_image ;
console.log(haveImageOrContent,"haveImageOrContent");
if(!haveContentOrContentImage){
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
return false;
}
if(!haveMoreThanOneAnswer){
toast.error(t("validation.it_should_have_more_than_one_answers")) ;
return false ;
}
if(!haveOneAnswerRight){
toast.error(t("validation.it_should_have_more_than_one_correct_answers")) ;
return false ;
}
if(haveImageOrContent){
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
return false
}
console.log(1);
if(isValid){
handleSubmit(values)
}
}
export const handleValidateBaseQuestion = (values: any,isValid:boolean,handleSubmit:any,t: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_image = Question.content_image ;
const haveContentOrContentImage = !!content || !!content_image ;
if(!haveContentOrContentImage){
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
return false;
}
//// answers
const answers = Question?.answers;
const haveAnswers = answers?.length > 0;
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
const haveOneAnswerRight = haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true);
const haveImageOrContent = haveOneAnswerRight && answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
if (!haveAnswers) {
toast.error(t("validation.it_should_have_more_than_one_answers"));
return false;
}
if (!haveMoreThanOneAnswer) {
toast.error(t("validation.it_should_have_more_than_one_answers"));
return false;
}
if (!haveOneAnswerRight) {
toast.error(t("validation.it_should_have_more_than_one_correct_answers"));
return false;
}
if(haveImageOrContent){
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
return false
}
return true
});
console.log(1);
if(isValid && isValidate){
console.log(2);
handleSubmit(values)
}
};

View File

@ -0,0 +1,108 @@
import { Form, Formik } from 'formik';
import React from 'react'
import { MdOutlineArrowForwardIos } from 'react-icons/md';
import { useLocation, useNavigate } from 'react-router-dom';
import { getInitialValuesBase, getValidationSchemaBase } from '../../formUtil';
import { Checkbox, Popover, Spin } from 'antd';
import { SettingFilled } from '@ant-design/icons';
import { CheckboxProps } from 'antd/lib';
import { LocalStorageEnum } from '../../../../../enums/LocalStorageEnum';
import { useObjectToEdit } from '../../../../../zustand/ObjectToEditState';
import ModelForm from "../../Model/Malty/Form";
const BaseFormContainer = ({objectToEdit,handleSubmit,Loading,handleValidateBaseQuestion,t}:{objectToEdit:any,handleSubmit:any,Loading:any,handleValidateBaseQuestion:any,t:any}) => {
const location = useLocation();
const navigate = useNavigate();
const { ShowHint,setShowHint , ShowLatexOption,setShowLatexOption } =
useObjectToEdit();
const handleCancel = () => {
navigate(-1);
};
const handleNavigateToPage = () => {
const cleanedUrl = location.pathname.replace(/\/Question\/\d+$/, "");
navigate(cleanedUrl);
};
const onChangeHint: CheckboxProps['onChange'] = (e) => {
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 = (
<div>
<Checkbox checked={ShowHint} onChange={onChangeHint}>
{ t("header.show_hint")}
</Checkbox>
<Checkbox checked={ShowLatexOption} onChange={onChangeLatexOption}>
{ t("header.show_MMl")}
</Checkbox>
</div>
);
return (
<div className="QuestionPractical">
<header>
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.edit_question")}
</header>
<div className="exercise_add">
<Formik
onSubmit={handleSubmit}
initialValues={getInitialValuesBase(objectToEdit)}
validationSchema={getValidationSchemaBase}
enableReinitialize
>
{({ values,isValid,handleSubmit,dirty }) => (
<Form className="w-100">
<main className="w-100 exercise_add_main">
{/* <Header/> */}
<header className="exercise_add_header mb-4">
<div>
{t("practical.edit")} {t("models.exercise")}{" "}
</div>
<div className="SettingEdit">
<Popover trigger="click" content={contentSetting}>
<SettingFilled/>
</Popover>
<div>{t("header.exercise")}</div>
</div>
</header>
<ModelForm />
<div className="exercise_add_buttons">
<div onClick={handleCancel}>{t("practical.back")}</div>
<button disabled={Loading} className={`relative ${dirty ? "" : "disabled"}`} type="button"
onClick={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
onSubmit={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
> {t("practical.edit")}
{Loading && (
<span className="Spinier_Div">
<Spin />
</span>
)}
</button>
</div>
</main>
</Form>
)}
</Formik>
</div>
</div>
)
}
export default BaseFormContainer

View File

@ -0,0 +1,110 @@
import { Form, Formik } from 'formik';
import React from 'react'
import { MdOutlineArrowForwardIos } from 'react-icons/md';
import { useLocation, useNavigate } from 'react-router-dom';
import { getInitialValues, getValidationSchema } from '../../formUtil';
import { Checkbox, Popover, Spin } from 'antd';
import { SettingFilled } from '@ant-design/icons';
import { CheckboxProps } from 'antd/lib';
import { LocalStorageEnum } from '../../../../../enums/LocalStorageEnum';
import { useObjectToEdit } from '../../../../../zustand/ObjectToEditState';
import ModelForm from "../../Model/ModelForm";
const FormContainer = ({objectToEdit,handleSubmit,Loading,handleValidateSingleQuestion,t}:{objectToEdit:any,handleSubmit:any,Loading:any,handleValidateSingleQuestion:any,t:any}) => {
const location = useLocation();
const navigate = useNavigate();
const { ShowHint,setShowHint , ShowLatexOption,setShowLatexOption } =
useObjectToEdit();
const handleCancel = () => {
navigate(-1);
};
const handleNavigateToPage = () => {
const cleanedUrl = location.pathname.replace(/\/Question\/\d+$/, "");
navigate(cleanedUrl);
};
const onChangeHint: CheckboxProps['onChange'] = (e) => {
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 = (
<div>
<Checkbox checked={ShowHint} onChange={onChangeHint}>
{ t("header.show_hint")}
</Checkbox>
<Checkbox checked={ShowLatexOption} onChange={onChangeLatexOption}>
{ t("header.show_MMl")}
</Checkbox>
</div>
);
return (
<div className="QuestionPractical">
<header>
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.edit_question")}
</header>
<div className="exercise_add">
<Formik
enableReinitialize={true}
initialValues={getInitialValues(objectToEdit)}
validationSchema={getValidationSchema}
onSubmit={(values) => {
handleSubmit(values);
}}
>
{({ values , dirty,isValid,handleSubmit }) => (
<Form className="w-100">
<main className="w-100 exercise_add_main">
{/* <Header/> */}
<header className="exercise_add_header mb-4">
<div>
{t("practical.edit")} {t("models.exercise")}{" "}
</div>
<div className="SettingEdit">
<Popover trigger="click" content={contentSetting}>
<SettingFilled/>
</Popover>
<div>{t("header.exercise")}</div>
</div>
</header>
<ModelForm />
<div className="exercise_add_buttons">
<div onClick={handleCancel}>{t("practical.back")}</div>
<div
className={`relative ${dirty ? "" : "disabled"}`}
onClick={()=>{ Loading ? ()=>{} : handleValidateSingleQuestion(values,isValid,handleSubmit,t) }}
> {t("practical.edit")}
{Loading && (
<span className="Spinier_Div">
<Spin />
</span>
)}
</div>
</div>
</main>
</Form>
)}
</Formik>
</div>
</div>
)
}
export default FormContainer

View File

@ -0,0 +1,100 @@
import { toast } from "react-toastify";
export const handleValidateSingleQuestion = (values:any,isValid:boolean,handleSubmit:any,t:any)=>{
const haveMoreThanOneAnswer = values?.answers?.length > 1;
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 content = values.content ;
const content_image = values.content_image ;
const haveContentOrContentImage = !!content || !!content_image ;
console.log(haveImageOrContent,"haveImageOrContent");
if(!haveContentOrContentImage){
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
return false;
}
if(!haveMoreThanOneAnswer){
toast.error(t("validation.it_should_have_more_than_one_answers")) ;
return false ;
}
if(!haveOneAnswerRight){
toast.error(t("validation.it_should_have_more_than_one_correct_answers")) ;
return false ;
}
if(haveImageOrContent){
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
return false
}
console.log(1);
if(isValid){
handleSubmit(values)
}
}
export const handleValidateBaseQuestion = (values: any,isValid:boolean,handleSubmit:any,t: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_image = Question.content_image ;
const haveContentOrContentImage = !!content || !!content_image ;
if(!haveContentOrContentImage){
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
return false;
}
//// answers
const answers = Question?.answers;
const haveAnswers = answers?.length > 0;
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
const haveOneAnswerRight = haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true);
const haveImageOrContent = haveOneAnswerRight && answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
if (!haveAnswers) {
toast.error(t("validation.it_should_have_more_than_one_answers"));
return false;
}
if (!haveMoreThanOneAnswer) {
toast.error(t("validation.it_should_have_more_than_one_answers"));
return false;
}
if (!haveOneAnswerRight) {
toast.error(t("validation.it_should_have_more_than_one_correct_answers"));
return false;
}
if(haveImageOrContent){
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
return false
}
return true
});
console.log(1);
if(isValid && isValidate){
console.log(2);
handleSubmit(values)
}
};

View File

@ -21,7 +21,6 @@ const ChoiceFields = React.memo(
setFieldValue:any; setFieldValue:any;
values:any values:any
}) => { }) => {
console.log(567)
const [t] = useTranslation(); const [t] = useTranslation();
const { ShowHint } = useObjectToEdit(); const { ShowHint } = useObjectToEdit();
const handleDeleteChoice = () => { const handleDeleteChoice = () => {
@ -120,7 +119,6 @@ const ChoiceFields = React.memo(
} }
, (prevProps, nextProps) => { , (prevProps, nextProps) => {
console.log(prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[prevProps?.index] === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[prevProps?.index]); 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]; return prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[prevProps?.index] === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[prevProps?.index];
}); });

View File

@ -113,8 +113,6 @@ const Choices = React.memo( ({setFieldValue ,values,parent_index }:any) => {
</> </>
); );
}, (prevProps, nextProps) => { }, (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; return prevProps.values?.Questions?.[prevProps?.parent_index]?.answers === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers;
}); });

View File

@ -10,6 +10,7 @@ import { CombinationKeyEnum } from "../../../../../enums/CombinationKeyEnum";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import MainInputs from "./components/MainInputs"; import MainInputs from "./components/MainInputs";
import Questions from "./components/Questions"; import Questions from "./components/Questions";
import useUnsavedChangesWarning from "../../../../../Hooks/useUnsavedChangesWarning";
const Form = () => { const Form = () => {
const formik = useFormikContext<any>(); const formik = useFormikContext<any>();
@ -64,6 +65,8 @@ const Form = () => {
const lastQuestions = formik?.values?.Questions?.length - 1; const lastQuestions = formik?.values?.Questions?.length - 1;
////////////// hooks
useKeyCombination( useKeyCombination(
{ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE }, { ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE },
() => { () => {
@ -77,8 +80,10 @@ const lastQuestions = formik?.values?.Questions?.length - 1;
handleAddQuestion(true); handleAddQuestion(true);
}, },
); );
useUnsavedChangesWarning(formik.dirty);
//////////////
useEffect(() => { useEffect(() => {
if (Success) { if (Success) {
formik.resetForm() formik.resetForm()

View File

@ -12,6 +12,7 @@ import { CombinationKeyEnum } from "../../../../enums/CombinationKeyEnum";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import LaTeXInputMemo from "../../../../Components/LatextInput/LaTeXInputMemo"; import LaTeXInputMemo from "../../../../Components/LatextInput/LaTeXInputMemo";
import ImageBoxFieldMemo from "../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo"; import ImageBoxFieldMemo from "../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo";
import useUnsavedChangesWarning from "../../../../Hooks/useUnsavedChangesWarning";
const Form = () => { const Form = () => {
const [t] = useTranslation(); const [t] = useTranslation();
@ -33,6 +34,10 @@ const Form = () => {
} }
}; };
////////////// hooks
useKeyCombination( useKeyCombination(
{ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE }, { ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE },
() => { () => {
@ -40,6 +45,10 @@ const Form = () => {
}, },
); );
useUnsavedChangesWarning(formik.dirty);
useEffect(() => { useEffect(() => {
if (Success) { if (Success) {
formik.resetForm() formik.resetForm()
@ -47,8 +56,6 @@ const Form = () => {
} }
}, [Success]); }, [Success]);
console.log(formik.errors);
return ( return (
<Row className="w-100 exercise_form_container"> <Row className="w-100 exercise_form_container">
@ -58,7 +65,6 @@ const Form = () => {
component={LaTeXInputMemo} component={LaTeXInputMemo}
label={t("input.answer_content")} label={t("input.answer_content")}
/> />
<Field <Field
component={ImageBoxFieldMemo} component={ImageBoxFieldMemo}
name="content_image" name="content_image"
@ -87,7 +93,6 @@ const Form = () => {
autoSize={{ minRows: 2, maxRows: 10 }} autoSize={{ minRows: 2, maxRows: 10 }}
/> />
} }
<SelectTag /> <SelectTag />
</div> </div>

View File

@ -13,7 +13,7 @@ const FormField = ({ isLoading }: FormFieldType) => {
return ( return (
<Form className="AuthForm"> <Form className="AuthForm">
{/* <Image style={{background:"#000"}} src="../App/Logo.png" /> */} {/* <Image style={{background:"#000"}} src="../App/Logo.svg" /> */}
<h2>{t("تسجيل الدخول إلى حسابك")}</h2> <h2>{t("تسجيل الدخول إلى حسابك")}</h2>
<ValidationField name="username" label="username" /> <ValidationField name="username" label="username" />

View File

@ -1,13 +1,15 @@
import { Formik,Form, Field } from "formik";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import LaTeXInputMemo from "./LaTeXInputMemo"; import MathMLPreview from "./MathMLPreview";
const Dummy = () => { const Dummy = () => {
const [t] = useTranslation(); const [t] = useTranslation();
return ( return (
<div className="DummyHomePage"> <div className="DummyHomePage">
<MathMLPreview/>
</div> </div>
); );

View File

@ -8,7 +8,7 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
const { setFieldValue } = form; const { setFieldValue } = form;
const [curCentValue, setCurrentValue] = useState(value) const [curCentValue, setCurrentValue] = useState(value)
const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => { const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
setFieldValue(name, e.target.value); // setFieldValue(name, e.target.value);
setCurrentValue(e.target.value) setCurrentValue(e.target.value)
}; };
console.log(name,"name"); console.log(name,"name");
@ -24,6 +24,7 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
</label> </label>
<div className='LaTeXInputArea'> <div className='LaTeXInputArea'>
<TextArea <TextArea
size="large" size="large"
showCount showCount

View File

@ -0,0 +1,31 @@
import React, { useState, useEffect } from 'react';
import { MathJax, MathJaxContext } from 'better-react-mathjax';
const MathMLPreview = () => {
const [mathML, setMathML] = useState('<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi><mo>=</mo><mn>5</mn></math>');
useEffect(() => {
// Any logic to handle input updates and preview refresh can be added here
}, [mathML]);
return (
<div>
<textarea
value={mathML}
onChange={(e) => setMathML(e.target.value)}
rows={5}
style={{ width: '100%' }}
/>
<MathJaxContext>
<div>
<h3>Preview:</h3>
<MathJax dynamic>
<div dangerouslySetInnerHTML={{ __html: mathML }} />
</MathJax>
</div>
</MathJaxContext>
</div>
);
};
export default MathMLPreview;

View File

@ -166,16 +166,16 @@ export const menuItems: TMenuItem[] = [
// abilities_value: ABILITIES_VALUES_ENUM.INDEX, // abilities_value: ABILITIES_VALUES_ENUM.INDEX,
// prevPath: 0, // prevPath: 0,
// }, // },
// { {
// header: "page_header.roles", header: "page_header.roles",
// element: <Roles />, element: <Roles />,
// icon: <FaUserShield />, icon: <FaUserShield />,
// text: "sidebar.role", text: "sidebar.role",
// path: `/${ABILITIES_ENUM?.ROLE}`, path: `/${ABILITIES_ENUM?.ROLE}`,
// abilities: ABILITIES_ENUM?.ROLE, abilities: ABILITIES_ENUM?.ROLE,
// abilities_value: ABILITIES_VALUES_ENUM.INDEX, abilities_value: ABILITIES_VALUES_ENUM.INDEX,
// prevPath: 0, prevPath: 0,
// }, },
/// RESELLER ///// /// RESELLER /////
@ -310,8 +310,8 @@ export const CrudRoute: TCrudRoute[] = [
{ {
header: "page_header.permissions", header: "page_header.permissions",
element: <Permissions />, element: <Permissions />,
path: `/${ABILITIES_ENUM?.PERMISSIONS}`, path: `/${ABILITIES_ENUM?.ROLE}/:${ParamsEnum?.ROLE_ID}/${ABILITIES_ENUM?.PERMISSIONS}`,
abilities: ABILITIES_ENUM?.PERMISSIONS, abilities: ABILITIES_ENUM?.ROLE,
abilities_value: ABILITIES_VALUES_ENUM.INDEX, abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 0, prevPath: 0,
}, },

View File

@ -115,3 +115,6 @@ svg{
.LaTeXRenderer{ .LaTeXRenderer{
direction: ltr; direction: ltr;
} }
.ant-input,.LaTeXInputArea,input{
}

View File

@ -1,5 +1,5 @@
:root { :root {
--primary: #3d5ee1; --primary: #0290d2;
--secondary: #303972; --secondary: #303972;
--field: #b0d9ff; --field: #b0d9ff;
--text: #202C4B; --text: #202C4B;

View File

@ -56,8 +56,7 @@
svg { svg {
font-size: 26px; font-size: 26px;
color: #fff; color: #fff;
} };
@include Flex;
width: 40px; width: 40px;
height: 40px; height: 40px;
border: 2px solid var(--borderColor); border: 2px solid var(--borderColor);
@ -66,6 +65,7 @@
img { img {
width: 1.5vw; width: 1.5vw;
} }
@include Flex;
} }
} }
} }

View File

@ -101,3 +101,8 @@
background: transparent !important; background: transparent !important;
color: #fff !important; color: #fff !important;
} }
.disabled{
pointer-events: none;
opacity: 0.6;
}

View File

@ -364,7 +364,7 @@
.LaTeXInput{ .LaTeXInput{
.text{ .text{
display: flex !important; // display: flex !important;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
.error_message{ .error_message{

View File

@ -153,3 +153,10 @@
.ant-pagination .ant-pagination-next .ant-pagination-item-link { .ant-pagination .ant-pagination-next .ant-pagination-item-link {
rotate: 180deg !important; rotate: 180deg !important;
} }
.permissions_submit_button{
display: flex;
justify-content: flex-end;
}

View File

@ -72,3 +72,14 @@
color: transparent; color: transparent;
} }
} }
.katex .msupsub{
text-align: end !important;
}
.mtight{
font-size: 10px !important;
}
.katex .delimcenter, .katex .op-symbol{
display: none;
}

21
src/api/Permissions.ts Normal file
View File

@ -0,0 +1,21 @@
import useAddMutation from "./helper/useAddMutation";
import useDeleteMutation from "./helper/useDeleteMutation";
import useGetQuery from "./helper/useGetQuery";
import useUpdateMutation from "./helper/useUpdateMutation";
const API = {
GET: "/permissions",
ADD: "/permissions",
DELETE: "/permissions",
UPDATE: "/permissions",
};
const KEY = "Permissions";
export const useGetAllPermissions = (params?: any, options?: any) =>
useGetQuery(KEY, API.GET, params, options);
export const useAddPermissions = () => useAddMutation(KEY, API.ADD);
export const useUpdatePermissions = (params?: any) =>
useUpdateMutation(KEY, API.GET);
export const useDeletePermissions = (params?: any) =>
useDeleteMutation(KEY, API.DELETE);

View File

@ -27,3 +27,6 @@ function useAddMutation(
} }
export default useAddMutation; export default useAddMutation;

View File

@ -68,10 +68,6 @@ export enum ABILITIES_VALUES_ENUM {
UPDATE = "update", UPDATE = "update",
DELETE = "delete", DELETE = "delete",
SHOW = "show", SHOW = "show",
ME = "me", PASS = "PASS"
IMPORT_STUDENT_DATA = "importStudentData",
MOVE_STUDENTS = "moveStudents",
IMPORT_STUDENTS = "importStudents",
OVERVIEW = "overview",
PRESENCE = "presence",
} }

View File

@ -52,7 +52,8 @@
"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 صالح" "that_is_not_a_valid_mml":"هذا ليس mml صالح",
"Are_you_sure_you_want_to_leave_Your_changes_may_not_be_saved":"هل أنت متأكد من أنك تريد المغادرة ؟ قد لا يتم حفظ التغييرات التي أجريتها"
}, },
"header": { "header": {
"register_students": "تسجيل الطلاب", "register_students": "تسجيل الطلاب",
@ -231,7 +232,8 @@
"edit":"تعديل", "edit":"تعديل",
"delete":"حذف", "delete":"حذف",
"read":"قراءة", "read":"قراءة",
"managers":"مدراء" "managers":"مدراء",
"show":"عرض"
}, },
"practical": { "practical": {
"to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال", "to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال",

View File

@ -16,7 +16,7 @@ export interface Response {
isLoading: boolean; isLoading: boolean;
} }
export interface DataTableProps { export interface DataTableProps extends TableProps {
response: any; response: any;
useColumns: any; useColumns: any;
dataSource?: any; dataSource?: any;

View File

@ -1,5 +1,9 @@
import { MathMLToLaTeX } from 'mathml-to-latex'; import { MathMLToLaTeX } from 'mathml-to-latex';
export function convertMathMLToLaTeX(mathml: string): string { export function convertMathMLToLaTeX(mathml: string): string {
console.log(MathMLToLaTeX.convert(mathml));
console.log(mathml);
return MathMLToLaTeX.convert(mathml); return MathMLToLaTeX.convert(mathml);
} }

View File

@ -132,6 +132,10 @@ export const canDeleteRole = hasAbility(
ABILITIES_VALUES_ENUM.DELETE, ABILITIES_VALUES_ENUM.DELETE,
); );
export const canShowRole = hasAbility(
ABILITIES_ENUM.ROLE,
ABILITIES_VALUES_ENUM.SHOW,
);
/// Payment /// Payment
export const canIndexPayment = hasAbility( export const canIndexPayment = hasAbility(