changed marketplace assets

This commit is contained in:
2025-04-01 14:27:08 +05:30
92 changed files with 4152 additions and 2071 deletions

View File

@@ -1,255 +1,255 @@
export function NotificationIcon() {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10 12.8335C10 13.3639 9.78927 13.8726 9.4142 14.2477C9.03913 14.6228 8.5304 14.8335 8 14.8335C7.4696 14.8335 6.96087 14.6228 6.58579 14.2477C6.21072 13.8726 6 13.3639 6 12.8335"
stroke="var(--text-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M3.72064 12.1667C3.39434 12.0974 3.10586 11.9084 2.91209 11.6369C2.71832 11.3653 2.63337 11.0311 2.67399 10.7L3.34066 5.29332C3.51087 4.18175 4.07672 3.16901 4.93414 2.44143C5.79156 1.71384 6.88287 1.32036 8.00734 1.33332C9.1318 1.32036 10.2231 1.71384 11.0805 2.44143C11.9379 3.16901 12.5038 4.18175 12.674 5.29332L13.3407 10.7C13.3815 11.0301 13.2975 11.3636 13.1051 11.635C12.9127 11.9063 12.6257 12.096 12.3007 12.1667C9.47907 12.8297 6.54222 12.8297 3.72064 12.1667Z"
stroke="var(--text-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
export function HomeIcon() {
return (
<svg
width="16"
height="17"
viewBox="0 0 16 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.91304 13.5V12.8333C6.91304 12.281 7.36076 11.8333 7.91304 11.8333H8.95652C9.50881 11.8333 9.95652 12.281 9.95652 12.8333V13.5C9.95652 14.0523 10.4042 14.5 10.9565 14.5H12C12.5523 14.5 13 14.0523 13 13.5V7.38889L8.21739 2.5L3 7.38889V13.5C3 14.0523 3.44772 14.5 4 14.5H5.91304C6.46533 14.5 6.91304 14.0523 6.91304 13.5Z"
stroke="var(--text-color)"
/>
</svg>
);
}
export function ProjectsIcon() {
return (
<svg
width="16"
height="17"
viewBox="0 0 16 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.1538 1.5H5.69231C5.20268 1.5 4.7331 1.68437 4.38688 2.01256C4.04066 2.34075 3.84615 2.78587 3.84615 3.25C3.35652 3.25 2.88695 3.43437 2.54073 3.76256C2.1945 4.09075 2 4.53587 2 5V13.75C2 14.2141 2.1945 14.6592 2.54073 14.9874C2.88695 15.3156 3.35652 15.5 3.84615 15.5H10.3077C10.7973 15.5 11.2669 15.3156 11.6131 14.9874C11.9593 14.6592 12.1538 14.2141 12.1538 13.75C12.6435 13.75 13.1131 13.5656 13.4593 13.2374C13.8055 12.9092 14 12.4641 14 12V3.25C14 2.78587 13.8055 2.34075 13.4593 2.01256C13.1131 1.68437 12.6435 1.5 12.1538 1.5ZM12.1538 12.875V5C12.1538 4.53587 11.9593 4.09075 11.6131 3.76256C11.2669 3.43437 10.7973 3.25 10.3077 3.25H4.76923C4.76923 3.01794 4.86648 2.79538 5.03959 2.63128C5.2127 2.46719 5.44749 2.375 5.69231 2.375H12.1538C12.3987 2.375 12.6334 2.46719 12.8066 2.63128C12.9797 2.79538 13.0769 3.01794 13.0769 3.25V12C13.0769 12.2321 12.9797 12.4546 12.8066 12.6187C12.6334 12.7828 12.3987 12.875 12.1538 12.875ZM2.92308 5C2.92308 4.76794 3.02033 4.54538 3.19344 4.38128C3.36655 4.21719 3.60134 4.125 3.84615 4.125H10.3077C10.5525 4.125 10.7873 4.21719 10.9604 4.38128C11.1335 4.54538 11.2308 4.76794 11.2308 5V13.75C11.2308 13.9821 11.1335 14.2046 10.9604 14.3687C10.7873 14.5328 10.5525 14.625 10.3077 14.625H3.84615C3.60134 14.625 3.36655 14.5328 3.19344 14.3687C3.02033 14.2046 2.92308 13.9821 2.92308 13.75V5Z"
fill="var(--text-color)"
/>
</svg>
);
}
export function TutorialsIcon() {
return (
<svg
width="16"
height="17"
viewBox="0 0 16 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="8.157"
cy="8.35866"
r="6.17928"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M7.31894 7.8336L7.30273 7.72125C10.0583 7.32407 11.5796 5.74901 12.1058 5.09033L12.1945 5.1612C11.6598 5.83032 10.1146 7.43067 7.31894 7.8336Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M7.3313 8.19434C7.56713 8.19434 7.7583 8.00316 7.7583 7.76734C7.7583 7.53151 7.56713 7.34033 7.3313 7.34033C7.09547 7.34033 6.9043 7.53151 6.9043 7.76734C6.9043 8.00316 7.09547 8.19434 7.3313 8.19434Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M12.134 5.56787C12.3699 5.56787 12.561 5.3767 12.561 5.14087C12.561 4.90504 12.3699 4.71387 12.134 4.71387C11.8982 4.71387 11.707 4.90504 11.707 5.14087C11.707 5.3767 11.8982 5.56787 12.134 5.56787Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M5.67763 13.0492C5.15009 12.385 4.31304 10.9992 4.63359 9.18018L4.74534 9.20001C4.43251 10.9751 5.25078 12.3292 5.76636 12.9785L5.67763 13.0492Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M4.68921 9.63867C4.92504 9.63867 5.11621 9.4475 5.11621 9.21167C5.11621 8.97584 4.92504 8.78467 4.68921 8.78467C4.45338 8.78467 4.26221 8.97584 4.26221 9.21167C4.26221 9.4475 4.45338 9.63867 4.68921 9.63867Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M5.70923 13.4238C5.94506 13.4238 6.13623 13.2327 6.13623 12.9968C6.13623 12.761 5.94506 12.5698 5.70923 12.5698C5.4734 12.5698 5.28223 12.761 5.28223 12.9968C5.28223 13.2327 5.4734 13.4238 5.70923 13.4238Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M12.4429 9.6101L12.3293 9.60692C12.369 8.18736 11.8263 6.82867 10.801 5.7813C9.73352 4.69047 8.2434 4.07147 6.70876 4.0804L6.70801 3.96684C8.27081 3.96078 9.79333 4.58917 10.8822 5.70181C11.9291 6.77143 12.4833 8.1595 12.4429 9.6101Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M12.3792 10.0142C12.615 10.0142 12.8062 9.82299 12.8062 9.58716C12.8062 9.35133 12.615 9.16016 12.3792 9.16016C12.1433 9.16016 11.9521 9.35133 11.9521 9.58716C11.9521 9.82299 12.1433 10.0142 12.3792 10.0142Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M6.72974 4.4585C6.96556 4.4585 7.15674 4.26732 7.15674 4.0315C7.15674 3.79567 6.96556 3.60449 6.72974 3.60449C6.49391 3.60449 6.30273 3.79567 6.30273 4.0315C6.30273 4.26732 6.49391 4.4585 6.72974 4.4585Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M8.93738 12.7561C5.51197 12.5871 3.18964 10.3443 2.15833 8.30167C1.40017 6.79989 1.28161 5.33657 1.84898 4.48256C2.21511 3.93139 2.7529 3.64179 3.57572 3.69903L3.45825 3.81649C2.67632 3.76183 2.28567 4.03042 1.94346 4.5454C1.39865 5.36549 1.51979 6.78505 2.25963 8.25049C3.27641 10.2647 5.56617 12.476 8.94298 12.6426L8.93738 12.7561Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M4.12372 13.5272C2.54078 13.2677 1.46328 11.9915 1.38697 10.4835C1.31368 9.03292 2.2066 7.3084 4.36675 6.72559L4.39628 6.83521C2.2973 7.40152 1.42936 9.07259 1.50053 10.4778C1.54767 11.4101 2.02721 12.4642 3.18398 12.9967C3.46147 13.1244 3.45807 13.0965 3.77132 13.2139L4.12372 13.5272Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M4.36157 7.21436C4.5974 7.21436 4.78858 7.02318 4.78858 6.78735C4.78858 6.55153 4.5974 6.36035 4.36157 6.36035C4.12575 6.36035 3.93457 6.55153 3.93457 6.78735C3.93457 7.02318 4.12575 7.21436 4.36157 7.21436Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M11.5155 15.1026C11.4663 15.1026 11.4165 15.1003 11.3659 15.0956C10.4065 15.0064 9.53752 14.1202 9.04102 12.7247L9.14807 12.6865C9.62928 14.0393 10.4622 14.8976 11.3764 14.9825C11.8685 15.0293 12.3041 14.8309 12.5152 14.4681C12.7337 14.0928 12.7265 13.7453 12.3977 13.2744L12.5152 13.1569C12.8703 13.6657 12.8548 14.1099 12.6133 14.5252C12.4016 14.8889 11.9895 15.1026 11.5155 15.1026Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M8.9187 13.1187C9.15453 13.1187 9.34571 12.9275 9.34571 12.6917C9.34571 12.4558 9.15453 12.2646 8.9187 12.2646C8.68287 12.2646 8.4917 12.4558 8.4917 12.6917C8.4917 12.9275 8.68287 13.1187 8.9187 13.1187Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M10.0987 3.65056L9.99072 3.61513C10.2487 2.83274 10.7045 2.32867 11.2414 2.23252C11.572 2.17286 11.8969 2.28566 12.0886 2.52597C12.2781 2.76339 12.4042 2.98817 12.2684 3.30782L12.1509 3.19035C12.2699 2.91023 12.1625 2.80064 12.0001 2.59683C11.8344 2.38923 11.5514 2.29248 11.2616 2.34441C10.7669 2.43284 10.3432 2.90906 10.0987 3.65056Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M10.0535 4.04004C10.2893 4.04004 10.4805 3.84887 10.4805 3.61304C10.4805 3.37721 10.2893 3.18604 10.0535 3.18604C9.81764 3.18604 9.62646 3.37721 9.62646 3.61304C9.62646 3.84887 9.81764 4.04004 10.0535 4.04004Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
</svg>
);
}
export function DocumentationIcon() {
return (
<svg
width="16"
height="17"
viewBox="0 0 16 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8 5.10589C7.2666 4.17245 6.13604 3.23901 3.33413 3.17051C3.15009 3.16602 3 3.3155 3 3.4996C3 4.86525 3 10.0354 3 11.5645C3 11.7486 3.1501 11.8932 3.33409 11.8992C6.13603 11.9908 7.2666 13.233 8 14.1665M8 5.10589C8.7334 4.17245 9.86393 3.23901 12.6659 3.17051C12.8499 3.16602 13 3.31214 13 3.49624C13 5.02281 13 10.0374 13 11.564C13 11.7481 12.8499 11.8932 12.6659 11.8992C9.864 11.9908 8.7334 13.233 8 14.1665M8 5.10589V14.1665"
stroke="var(--text-color)"
strokeLinejoin="round"
/>
<path
d="M12.8232 4.5H14.333C14.5171 4.5 14.6663 4.64924 14.6663 4.83333V13.526C14.6663 13.7957 14.3485 13.9749 14.102 13.8654C13.5719 13.6299 12.6873 13.3421 11.5291 13.3421C9.56827 13.3421 7.99967 14.5 7.99967 14.5C7.99967 14.5 6.43105 13.3421 4.47026 13.3421C3.31197 13.3421 2.42738 13.6299 1.89732 13.8654C1.65079 13.9749 1.33301 13.7957 1.33301 13.526V4.83333C1.33301 4.64924 1.48225 4.5 1.66634 4.5H3.17615"
stroke="var(--text-color)"
strokeLinejoin="round"
/>
</svg>
);
}
export function HelpIcon() {
return (
<svg
width="12"
height="13"
viewBox="0 0 12 13"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_764_1941)">
<path
d="M6 12.5C2.6862 12.5 0 9.8138 0 6.5C0 3.1862 2.6862 0.5 6 0.5C9.3138 0.5 12 3.1862 12 6.5C12 9.8138 9.3138 12.5 6 12.5ZM3.552 4.8404V4.9016C3.552 4.98117 3.58361 5.05747 3.63987 5.11373C3.69613 5.16999 3.77244 5.2016 3.852 5.2016H4.4502C4.48952 5.2016 4.52845 5.19386 4.56478 5.17881C4.6011 5.16376 4.63411 5.14171 4.66191 5.11391C4.68971 5.08611 4.71176 5.0531 4.72681 5.01678C4.74186 4.98045 4.7496 4.94152 4.7496 4.9022C4.7496 4.1282 5.3484 3.7148 6.1536 3.7148C6.9384 3.7148 7.4544 4.1282 7.4544 4.7168C7.4544 5.2736 7.1652 5.5322 6.4428 5.8628L6.2364 5.9552C5.6274 6.224 5.4 6.626 5.4 7.3286V7.4C5.4 7.47957 5.43161 7.55587 5.48787 7.61213C5.54413 7.66839 5.62044 7.7 5.7 7.7H6.2982C6.33752 7.7 6.37645 7.69226 6.41278 7.67721C6.4491 7.66216 6.48211 7.64011 6.50991 7.61231C6.53771 7.58451 6.55976 7.5515 6.57481 7.51518C6.58986 7.47885 6.5976 7.43992 6.5976 7.4006C6.5976 7.091 6.6804 6.9668 6.9276 6.8534L7.1346 6.7604C8.0016 6.368 8.652 5.852 8.652 4.7264V4.6646C8.652 3.4778 7.62 2.6 6.1536 2.6C4.6668 2.6 3.552 3.4568 3.552 4.8404ZM5.1 9.4946C5.1 10.0148 5.4954 10.4 5.9946 10.4C6.5046 10.4 6.9 10.0148 6.9 9.4946C6.9 8.9744 6.5046 8.6 5.9946 8.6C5.4954 8.6 5.1 8.9744 5.1 9.4946Z"
fill="var(--text-color)"
/>
</g>
<defs>
<clipPath id="clip0_764_1941">
<rect
width="12"
height="12"
fill="white"
transform="translate(0 0.5)"
/>
</clipPath>
</defs>
</svg>
);
}
export function LogoutIcon() {
return (
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4 3.5C4.00605 2.41248 4.05428 1.82353 4.43847 1.43934C4.87781 1 5.58489 1 6.99914 1H7.49914C8.91334 1 9.62044 1 10.0598 1.43934C10.4991 1.87868 10.4991 2.58578 10.4991 4V8C10.4991 9.4142 10.4991 10.1213 10.0598 10.5606C9.62044 11 8.91334 11 7.49914 11H6.99914C5.58489 11 4.87781 11 4.43847 10.5606C4.05428 10.1764 4.00605 9.5875 4 8.5"
stroke="var(--text-color)"
strokeLinecap="round"
/>
<path
opacity="0.5"
d="M4 9.75C2.82149 9.75 2.23223 9.75 1.86611 9.3839C1.5 9.01775 1.5 8.4285 1.5 7.25V4.75C1.5 3.57149 1.5 2.98224 1.86611 2.61612C2.23223 2.25 2.82149 2.25 4 2.25"
stroke="var(--text-color)"
/>
<path
d="M7.5 6H3M3 6L4 7M3 6L4 5"
stroke="var(--text-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
export function NotificationIcon() {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10 12.8335C10 13.3639 9.78927 13.8726 9.4142 14.2477C9.03913 14.6228 8.5304 14.8335 8 14.8335C7.4696 14.8335 6.96087 14.6228 6.58579 14.2477C6.21072 13.8726 6 13.3639 6 12.8335"
stroke="var(--text-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M3.72064 12.1667C3.39434 12.0974 3.10586 11.9084 2.91209 11.6369C2.71832 11.3653 2.63337 11.0311 2.67399 10.7L3.34066 5.29332C3.51087 4.18175 4.07672 3.16901 4.93414 2.44143C5.79156 1.71384 6.88287 1.32036 8.00734 1.33332C9.1318 1.32036 10.2231 1.71384 11.0805 2.44143C11.9379 3.16901 12.5038 4.18175 12.674 5.29332L13.3407 10.7C13.3815 11.0301 13.2975 11.3636 13.1051 11.635C12.9127 11.9063 12.6257 12.096 12.3007 12.1667C9.47907 12.8297 6.54222 12.8297 3.72064 12.1667Z"
stroke="var(--text-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
export function HomeIcon() {
return (
<svg
width="16"
height="17"
viewBox="0 0 16 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.91304 13.5V12.8333C6.91304 12.281 7.36076 11.8333 7.91304 11.8333H8.95652C9.50881 11.8333 9.95652 12.281 9.95652 12.8333V13.5C9.95652 14.0523 10.4042 14.5 10.9565 14.5H12C12.5523 14.5 13 14.0523 13 13.5V7.38889L8.21739 2.5L3 7.38889V13.5C3 14.0523 3.44772 14.5 4 14.5H5.91304C6.46533 14.5 6.91304 14.0523 6.91304 13.5Z"
stroke="var(--text-color)"
/>
</svg>
);
}
export function ProjectsIcon() {
return (
<svg
width="16"
height="17"
viewBox="0 0 16 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.1538 1.5H5.69231C5.20268 1.5 4.7331 1.68437 4.38688 2.01256C4.04066 2.34075 3.84615 2.78587 3.84615 3.25C3.35652 3.25 2.88695 3.43437 2.54073 3.76256C2.1945 4.09075 2 4.53587 2 5V13.75C2 14.2141 2.1945 14.6592 2.54073 14.9874C2.88695 15.3156 3.35652 15.5 3.84615 15.5H10.3077C10.7973 15.5 11.2669 15.3156 11.6131 14.9874C11.9593 14.6592 12.1538 14.2141 12.1538 13.75C12.6435 13.75 13.1131 13.5656 13.4593 13.2374C13.8055 12.9092 14 12.4641 14 12V3.25C14 2.78587 13.8055 2.34075 13.4593 2.01256C13.1131 1.68437 12.6435 1.5 12.1538 1.5ZM12.1538 12.875V5C12.1538 4.53587 11.9593 4.09075 11.6131 3.76256C11.2669 3.43437 10.7973 3.25 10.3077 3.25H4.76923C4.76923 3.01794 4.86648 2.79538 5.03959 2.63128C5.2127 2.46719 5.44749 2.375 5.69231 2.375H12.1538C12.3987 2.375 12.6334 2.46719 12.8066 2.63128C12.9797 2.79538 13.0769 3.01794 13.0769 3.25V12C13.0769 12.2321 12.9797 12.4546 12.8066 12.6187C12.6334 12.7828 12.3987 12.875 12.1538 12.875ZM2.92308 5C2.92308 4.76794 3.02033 4.54538 3.19344 4.38128C3.36655 4.21719 3.60134 4.125 3.84615 4.125H10.3077C10.5525 4.125 10.7873 4.21719 10.9604 4.38128C11.1335 4.54538 11.2308 4.76794 11.2308 5V13.75C11.2308 13.9821 11.1335 14.2046 10.9604 14.3687C10.7873 14.5328 10.5525 14.625 10.3077 14.625H3.84615C3.60134 14.625 3.36655 14.5328 3.19344 14.3687C3.02033 14.2046 2.92308 13.9821 2.92308 13.75V5Z"
fill="var(--text-color)"
/>
</svg>
);
}
export function TutorialsIcon() {
return (
<svg
width="16"
height="17"
viewBox="0 0 16 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="8.157"
cy="8.35866"
r="6.17928"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M7.31894 7.8336L7.30273 7.72125C10.0583 7.32407 11.5796 5.74901 12.1058 5.09033L12.1945 5.1612C11.6598 5.83032 10.1146 7.43067 7.31894 7.8336Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M7.3313 8.19434C7.56713 8.19434 7.7583 8.00316 7.7583 7.76734C7.7583 7.53151 7.56713 7.34033 7.3313 7.34033C7.09547 7.34033 6.9043 7.53151 6.9043 7.76734C6.9043 8.00316 7.09547 8.19434 7.3313 8.19434Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M12.134 5.56787C12.3699 5.56787 12.561 5.3767 12.561 5.14087C12.561 4.90504 12.3699 4.71387 12.134 4.71387C11.8982 4.71387 11.707 4.90504 11.707 5.14087C11.707 5.3767 11.8982 5.56787 12.134 5.56787Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M5.67763 13.0492C5.15009 12.385 4.31304 10.9992 4.63359 9.18018L4.74534 9.20001C4.43251 10.9751 5.25078 12.3292 5.76636 12.9785L5.67763 13.0492Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M4.68921 9.63867C4.92504 9.63867 5.11621 9.4475 5.11621 9.21167C5.11621 8.97584 4.92504 8.78467 4.68921 8.78467C4.45338 8.78467 4.26221 8.97584 4.26221 9.21167C4.26221 9.4475 4.45338 9.63867 4.68921 9.63867Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M5.70923 13.4238C5.94506 13.4238 6.13623 13.2327 6.13623 12.9968C6.13623 12.761 5.94506 12.5698 5.70923 12.5698C5.4734 12.5698 5.28223 12.761 5.28223 12.9968C5.28223 13.2327 5.4734 13.4238 5.70923 13.4238Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M12.4429 9.6101L12.3293 9.60692C12.369 8.18736 11.8263 6.82867 10.801 5.7813C9.73352 4.69047 8.2434 4.07147 6.70876 4.0804L6.70801 3.96684C8.27081 3.96078 9.79333 4.58917 10.8822 5.70181C11.9291 6.77143 12.4833 8.1595 12.4429 9.6101Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M12.3792 10.0142C12.615 10.0142 12.8062 9.82299 12.8062 9.58716C12.8062 9.35133 12.615 9.16016 12.3792 9.16016C12.1433 9.16016 11.9521 9.35133 11.9521 9.58716C11.9521 9.82299 12.1433 10.0142 12.3792 10.0142Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M6.72974 4.4585C6.96556 4.4585 7.15674 4.26732 7.15674 4.0315C7.15674 3.79567 6.96556 3.60449 6.72974 3.60449C6.49391 3.60449 6.30273 3.79567 6.30273 4.0315C6.30273 4.26732 6.49391 4.4585 6.72974 4.4585Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M8.93738 12.7561C5.51197 12.5871 3.18964 10.3443 2.15833 8.30167C1.40017 6.79989 1.28161 5.33657 1.84898 4.48256C2.21511 3.93139 2.7529 3.64179 3.57572 3.69903L3.45825 3.81649C2.67632 3.76183 2.28567 4.03042 1.94346 4.5454C1.39865 5.36549 1.51979 6.78505 2.25963 8.25049C3.27641 10.2647 5.56617 12.476 8.94298 12.6426L8.93738 12.7561Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M4.12372 13.5272C2.54078 13.2677 1.46328 11.9915 1.38697 10.4835C1.31368 9.03292 2.2066 7.3084 4.36675 6.72559L4.39628 6.83521C2.2973 7.40152 1.42936 9.07259 1.50053 10.4778C1.54767 11.4101 2.02721 12.4642 3.18398 12.9967C3.46147 13.1244 3.45807 13.0965 3.77132 13.2139L4.12372 13.5272Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M4.36157 7.21436C4.5974 7.21436 4.78858 7.02318 4.78858 6.78735C4.78858 6.55153 4.5974 6.36035 4.36157 6.36035C4.12575 6.36035 3.93457 6.55153 3.93457 6.78735C3.93457 7.02318 4.12575 7.21436 4.36157 7.21436Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M11.5155 15.1026C11.4663 15.1026 11.4165 15.1003 11.3659 15.0956C10.4065 15.0064 9.53752 14.1202 9.04102 12.7247L9.14807 12.6865C9.62928 14.0393 10.4622 14.8976 11.3764 14.9825C11.8685 15.0293 12.3041 14.8309 12.5152 14.4681C12.7337 14.0928 12.7265 13.7453 12.3977 13.2744L12.5152 13.1569C12.8703 13.6657 12.8548 14.1099 12.6133 14.5252C12.4016 14.8889 11.9895 15.1026 11.5155 15.1026Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M8.9187 13.1187C9.15453 13.1187 9.34571 12.9275 9.34571 12.6917C9.34571 12.4558 9.15453 12.2646 8.9187 12.2646C8.68287 12.2646 8.4917 12.4558 8.4917 12.6917C8.4917 12.9275 8.68287 13.1187 8.9187 13.1187Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M10.0987 3.65056L9.99072 3.61513C10.2487 2.83274 10.7045 2.32867 11.2414 2.23252C11.572 2.17286 11.8969 2.28566 12.0886 2.52597C12.2781 2.76339 12.4042 2.98817 12.2684 3.30782L12.1509 3.19035C12.2699 2.91023 12.1625 2.80064 12.0001 2.59683C11.8344 2.38923 11.5514 2.29248 11.2616 2.34441C10.7669 2.43284 10.3432 2.90906 10.0987 3.65056Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
<path
d="M10.0535 4.04004C10.2893 4.04004 10.4805 3.84887 10.4805 3.61304C10.4805 3.37721 10.2893 3.18604 10.0535 3.18604C9.81764 3.18604 9.62646 3.37721 9.62646 3.61304C9.62646 3.84887 9.81764 4.04004 10.0535 4.04004Z"
fill="var(--text-color)"
stroke="var(--text-color)"
strokeWidth="0.562865"
/>
</svg>
);
}
export function DocumentationIcon() {
return (
<svg
width="16"
height="17"
viewBox="0 0 16 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8 5.10589C7.2666 4.17245 6.13604 3.23901 3.33413 3.17051C3.15009 3.16602 3 3.3155 3 3.4996C3 4.86525 3 10.0354 3 11.5645C3 11.7486 3.1501 11.8932 3.33409 11.8992C6.13603 11.9908 7.2666 13.233 8 14.1665M8 5.10589C8.7334 4.17245 9.86393 3.23901 12.6659 3.17051C12.8499 3.16602 13 3.31214 13 3.49624C13 5.02281 13 10.0374 13 11.564C13 11.7481 12.8499 11.8932 12.6659 11.8992C9.864 11.9908 8.7334 13.233 8 14.1665M8 5.10589V14.1665"
stroke="var(--text-color)"
strokeLinejoin="round"
/>
<path
d="M12.8232 4.5H14.333C14.5171 4.5 14.6663 4.64924 14.6663 4.83333V13.526C14.6663 13.7957 14.3485 13.9749 14.102 13.8654C13.5719 13.6299 12.6873 13.3421 11.5291 13.3421C9.56827 13.3421 7.99967 14.5 7.99967 14.5C7.99967 14.5 6.43105 13.3421 4.47026 13.3421C3.31197 13.3421 2.42738 13.6299 1.89732 13.8654C1.65079 13.9749 1.33301 13.7957 1.33301 13.526V4.83333C1.33301 4.64924 1.48225 4.5 1.66634 4.5H3.17615"
stroke="var(--text-color)"
strokeLinejoin="round"
/>
</svg>
);
}
export function HelpIcon() {
return (
<svg
width="12"
height="13"
viewBox="0 0 12 13"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_764_1941)">
<path
d="M6 12.5C2.6862 12.5 0 9.8138 0 6.5C0 3.1862 2.6862 0.5 6 0.5C9.3138 0.5 12 3.1862 12 6.5C12 9.8138 9.3138 12.5 6 12.5ZM3.552 4.8404V4.9016C3.552 4.98117 3.58361 5.05747 3.63987 5.11373C3.69613 5.16999 3.77244 5.2016 3.852 5.2016H4.4502C4.48952 5.2016 4.52845 5.19386 4.56478 5.17881C4.6011 5.16376 4.63411 5.14171 4.66191 5.11391C4.68971 5.08611 4.71176 5.0531 4.72681 5.01678C4.74186 4.98045 4.7496 4.94152 4.7496 4.9022C4.7496 4.1282 5.3484 3.7148 6.1536 3.7148C6.9384 3.7148 7.4544 4.1282 7.4544 4.7168C7.4544 5.2736 7.1652 5.5322 6.4428 5.8628L6.2364 5.9552C5.6274 6.224 5.4 6.626 5.4 7.3286V7.4C5.4 7.47957 5.43161 7.55587 5.48787 7.61213C5.54413 7.66839 5.62044 7.7 5.7 7.7H6.2982C6.33752 7.7 6.37645 7.69226 6.41278 7.67721C6.4491 7.66216 6.48211 7.64011 6.50991 7.61231C6.53771 7.58451 6.55976 7.5515 6.57481 7.51518C6.58986 7.47885 6.5976 7.43992 6.5976 7.4006C6.5976 7.091 6.6804 6.9668 6.9276 6.8534L7.1346 6.7604C8.0016 6.368 8.652 5.852 8.652 4.7264V4.6646C8.652 3.4778 7.62 2.6 6.1536 2.6C4.6668 2.6 3.552 3.4568 3.552 4.8404ZM5.1 9.4946C5.1 10.0148 5.4954 10.4 5.9946 10.4C6.5046 10.4 6.9 10.0148 6.9 9.4946C6.9 8.9744 6.5046 8.6 5.9946 8.6C5.4954 8.6 5.1 8.9744 5.1 9.4946Z"
fill="var(--text-color)"
/>
</g>
<defs>
<clipPath id="clip0_764_1941">
<rect
width="12"
height="12"
fill="white"
transform="translate(0 0.5)"
/>
</clipPath>
</defs>
</svg>
);
}
export function LogoutIcon() {
return (
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4 3.5C4.00605 2.41248 4.05428 1.82353 4.43847 1.43934C4.87781 1 5.58489 1 6.99914 1H7.49914C8.91334 1 9.62044 1 10.0598 1.43934C10.4991 1.87868 10.4991 2.58578 10.4991 4V8C10.4991 9.4142 10.4991 10.1213 10.0598 10.5606C9.62044 11 8.91334 11 7.49914 11H6.99914C5.58489 11 4.87781 11 4.43847 10.5606C4.05428 10.1764 4.00605 9.5875 4 8.5"
stroke="var(--text-color)"
strokeLinecap="round"
/>
<path
opacity="0.5"
d="M4 9.75C2.82149 9.75 2.23223 9.75 1.86611 9.3839C1.5 9.01775 1.5 8.4285 1.5 7.25V4.75C1.5 3.57149 1.5 2.98224 1.86611 2.61612C2.23223 2.25 2.82149 2.25 4 2.25"
stroke="var(--text-color)"
/>
<path
d="M7.5 6H3M3 6L4 7M3 6L4 5"
stroke="var(--text-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}

View File

@@ -1,25 +1,25 @@
import React from "react";
import { KebabIcon } from "../../icons/ExportCommonIcons";
import img from "../../../assets/image/image.png"
const DashboardCard:React.FC = () => {
return (
<div className="dashboard-card-container">
<div className="preview-container">
<img src={img} alt="" />
</div>
<div className="project-details-container">
<div className="project-details">
<div className="project-name">Untitled</div>
<div className="project-data">24-12-2025</div>
</div>
<div className="users-list-container">
<div className="user-profile">V</div>
<KebabIcon />
</div>
</div>
</div>
);
};
export default DashboardCard;
import React from "react";
import { KebabIcon } from "../../icons/ExportCommonIcons";
import img from "../../../assets/image/image.png"
const DashboardCard:React.FC = () => {
return (
<div className="dashboard-card-container">
<div className="preview-container">
<img src={img} alt="" />
</div>
<div className="project-details-container">
<div className="project-details">
<div className="project-name">Untitled</div>
<div className="project-data">24-12-2025</div>
</div>
<div className="users-list-container">
<div className="user-profile">V</div>
<KebabIcon />
</div>
</div>
</div>
);
};
export default DashboardCard;

View File

@@ -1,21 +1,21 @@
import React from "react";
import DashboardCard from "./DashboardCard";
import DashboardNavBar from "./DashboardNavBar";
import MarketPlaceBanner from "./MarketPlaceBanner";
const DashboardHome: React.FC = () => {
return (
<div className="dashboard-home-container">
<DashboardNavBar page={"home"} />
<MarketPlaceBanner />
<div className="container">
<div className="header">Recents</div>
<div className="cards-container">
<DashboardCard />
</div>
</div>
</div>
);
};
export default DashboardHome;
import React from "react";
import DashboardCard from "./DashboardCard";
import DashboardNavBar from "./DashboardNavBar";
import MarketPlaceBanner from "./MarketPlaceBanner";
const DashboardHome: React.FC = () => {
return (
<div className="dashboard-home-container">
<DashboardNavBar page={"home"} />
<MarketPlaceBanner />
<div className="container">
<div className="header">Recents</div>
<div className="cards-container">
<DashboardCard />
</div>
</div>
</div>
);
};
export default DashboardHome;

View File

@@ -1,21 +1,21 @@
import React from "react";
import { CartIcon } from "../../icons/ExportModuleIcons";
import Search from "../../ui/inputs/Search";
interface DashboardNavBarProps {
page: React.ReactNode;
}
const DashboardNavBar: React.FC<DashboardNavBarProps> = ({ page }) => {
return (
<div className="dashboard-navbar-container">
<div className="title">{page}</div>
<div className="market-place-button">
<CartIcon isActive /> Market Place
</div>
<Search onChange={() => {}} />
</div>
);
};
export default DashboardNavBar;
import React from "react";
import { CartIcon } from "../../icons/ExportModuleIcons";
import Search from "../../ui/inputs/Search";
interface DashboardNavBarProps {
page: React.ReactNode;
}
const DashboardNavBar: React.FC<DashboardNavBarProps> = ({ page }) => {
return (
<div className="dashboard-navbar-container">
<div className="title">{page}</div>
<div className="market-place-button">
<CartIcon isActive /> Market Place
</div>
<Search onChange={() => {}} />
</div>
);
};
export default DashboardNavBar;

View File

@@ -1,44 +1,44 @@
import React from "react";
import banner from "../../../assets/image/banner.png";
const MarketPlaceBanner = () => {
return (
<div className="market-place-banner-container">
{/* market place banner */}
<img src={banner} alt="" />
<div className="hero-text">
NEW
<br /> FALL
<br /> COLLECTION
</div>
<div className="context">Unlock Creativity with Premium 3D Assets!</div>
<div className="arrow-context">
<svg
width="169"
height="120"
viewBox="0 0 169 120"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M167.189 2C154.638 36.335 104.466 106.204 4.18872 111"
stroke="white"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M10.662 118.326L1.59439 111.524L9.47334 103.374"
stroke="white"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
<div className="explore-button">Explore Now</div>
</div>
);
};
export default MarketPlaceBanner;
import React from "react";
import banner from "../../../assets/image/banner.png";
const MarketPlaceBanner = () => {
return (
<div className="market-place-banner-container">
{/* market place banner */}
<img src={banner} alt="" />
<div className="hero-text">
NEW
<br /> FALL
<br /> COLLECTION
</div>
<div className="context">Unlock Creativity with Premium 3D Assets!</div>
<div className="arrow-context">
<svg
width="169"
height="120"
viewBox="0 0 169 120"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M167.189 2C154.638 36.335 104.466 106.204 4.18872 111"
stroke="white"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M10.662 118.326L1.59439 111.524L9.47334 103.374"
stroke="white"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
<div className="explore-button">Explore Now</div>
</div>
);
};
export default MarketPlaceBanner;

View File

@@ -1,69 +1,69 @@
import React from "react";
import {
DocumentationIcon,
HelpIcon,
HomeIcon,
LogoutIcon,
NotificationIcon,
ProjectsIcon,
TutorialsIcon,
} from "../../icons/DashboardIcon";
import { SettingsIcon, TrashIcon } from "../../icons/ExportCommonIcons";
const SidePannel: React.FC = () => {
const userName = localStorage.getItem("userName") || "Anonymous";
return (
<div className="side-pannel-container">
<div className="side-pannel-header">
<div className="user-container">
<div className="user-profile">{userName[0]}</div>
<div className="user-name">{userName}</div>
</div>
<div className="notifications-container">
<NotificationIcon />
</div>
</div>
<div className="new-project-button">+ New project</div>
<div className="side-bar-content-container">
<div className="side-bar-options-container">
<div className="option-list active">
<HomeIcon />
Home
</div>
<div className="option-list" title="coming soon">
<ProjectsIcon />
Projects
</div>
<div className="option-list" title="coming soon">
<TrashIcon />
Trash
</div>
<div className="option-list" title="coming soon">
<TutorialsIcon />
Tutorials
</div>
<div className="option-list" title="coming soon">
<DocumentationIcon />
Documentation
</div>
</div>
<div className="side-bar-options-container" title="coming soon">
<div className="option-list">
<SettingsIcon />
Settings
</div>
<div className="option-list" style={{cursor: "pointer"}}>
<LogoutIcon />
Log out
</div>
<div className="option-list">
<HelpIcon />
Help & Feedback
</div>
</div>
</div>
</div>
);
};
export default SidePannel;
import React from "react";
import {
DocumentationIcon,
HelpIcon,
HomeIcon,
LogoutIcon,
NotificationIcon,
ProjectsIcon,
TutorialsIcon,
} from "../../icons/DashboardIcon";
import { SettingsIcon, TrashIcon } from "../../icons/ExportCommonIcons";
const SidePannel: React.FC = () => {
const userName = localStorage.getItem("userName") || "Anonymous";
return (
<div className="side-pannel-container">
<div className="side-pannel-header">
<div className="user-container">
<div className="user-profile">{userName[0]}</div>
<div className="user-name">{userName}</div>
</div>
<div className="notifications-container">
<NotificationIcon />
</div>
</div>
<div className="new-project-button">+ New project</div>
<div className="side-bar-content-container">
<div className="side-bar-options-container">
<div className="option-list active">
<HomeIcon />
Home
</div>
<div className="option-list" title="coming soon">
<ProjectsIcon />
Projects
</div>
<div className="option-list" title="coming soon">
<TrashIcon />
Trash
</div>
<div className="option-list" title="coming soon">
<TutorialsIcon />
Tutorials
</div>
<div className="option-list" title="coming soon">
<DocumentationIcon />
Documentation
</div>
</div>
<div className="side-bar-options-container" title="coming soon">
<div className="option-list">
<SettingsIcon />
Settings
</div>
<div className="option-list" style={{cursor: "pointer"}}>
<LogoutIcon />
Log out
</div>
<div className="option-list">
<HelpIcon />
Help & Feedback
</div>
</div>
</div>
</div>
);
};
export default SidePannel;

View File

@@ -10,6 +10,7 @@ import arch from "../../../assets/gltf-glb/arch.glb";
import door from "../../../assets/gltf-glb/door.glb";
import window from "../../../assets/gltf-glb/window.glb";
import { fetchAssets } from "../../../services/marketplace/fetchAssets";
import { useSelectedItem } from "../../../store/store";
interface AssetProp {
filename: string;
thumbnail?: string;
@@ -24,6 +25,7 @@ interface AssetProp {
CreatedBy?: String;
}
const Assets: React.FC = () => {
const { setSelectedItem } = useSelectedItem();
const [searchValue, setSearchValue] = useState<string>("");
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const [categoryAssets, setCategoryAssets] = useState<AssetProp[]>([]);
@@ -32,9 +34,17 @@ const Assets: React.FC = () => {
const handleSearchChange = (value: string) => {
setSearchValue(value);
setSelectedCategory(null);
const filteredModels = filtereredAssets?.filter((model) =>
model.filename.toLowerCase().includes(value.toLowerCase())
);
const searchTerm = value.toLowerCase(); // Convert input to lowercase
const filteredModels = filtereredAssets?.filter((model) => {
if (!model?.tags || !model?.filename) return false;
if (searchTerm.startsWith(":") && searchTerm.length > 1) {
const tagSearchTerm = searchTerm.slice(1);
return model.tags.toLowerCase().includes(tagSearchTerm);
} else if (!searchTerm.startsWith(":")) {
return model.filename.toLowerCase().includes(searchTerm);
}
return false;
});
setCategoryAssets(filteredModels);
};
@@ -105,12 +115,11 @@ const Assets: React.FC = () => {
} else {
try {
const res = await getCategoryAsset(asset);
setCategoryAssets(res || []); // Ensure it's always an array
setFiltereredAssets(res || []);
setCategoryAssets(res);
setFiltereredAssets(res);
} catch (error) {}
}
};
return (
<div className="assets-container">
<Search onChange={handleSearchChange} />
@@ -149,36 +158,38 @@ const Assets: React.FC = () => {
{/* Back Button */}
<div
className="back-button"
onClick={() => {
setSelectedCategory(null);
setCategoryAssets([]);
}}
onClick={() => setSelectedCategory(null)}
>
Back
</div>
<h2>{selectedCategory}</h2>
<div className="assets-container">
{searchValue ||
(categoryAssets &&
categoryAssets?.map((asset: any, index: number) => (
<div key={index} className="assets">
<img
src={asset?.thumbnail}
alt={asset.filename}
className="asset-image"
/>
{categoryAssets &&
categoryAssets?.map((asset: any, index: number) => (
<div key={index} className="assets">
<img
src={asset?.thumbnail}
alt={asset.filename}
className="asset-image"
onPointerDown={() =>
setSelectedItem({
name: asset.filename,
id: asset.modelfileID,
})
}
/>
<div className="asset-name">
{asset.filename
.split("_")
.map(
(word: any) =>
word.charAt(0).toUpperCase() + word.slice(1)
)
.join(" ")}
</div>
<div className="asset-name">
{asset.filename
.split("_")
.map(
(word: any) =>
word.charAt(0).toUpperCase() + word.slice(1)
)
.join(" ")}
</div>
)))}
</div>
))}
</div>
</div>
) : (

View File

@@ -1,25 +1,76 @@
import { useEffect } from "react";
import { useDroppedObjectsStore } from "../../../../store/useDroppedObjectsStore";
import useTemplateStore from "../../../../store/useTemplateStore";
import { useSelectedZoneStore } from "../../../../store/useZoneStore";
import { getTemplateData } from "../../../../services/realTimeVisulization/zoneData/getTemplate";
import { deleteTemplateApi } from "../../../../services/realTimeVisulization/zoneData/deleteTemplate";
import { loadTempleteApi } from "../../../../services/realTimeVisulization/zoneData/loadTemplate";
const Templates = () => {
const { templates, removeTemplate } = useTemplateStore();
const { setSelectedZone } = useSelectedZoneStore();
const { setTemplates } = useTemplateStore();
const { setSelectedZone, selectedZone } = useSelectedZoneStore();
const handleDeleteTemplate = (id: string) => {
removeTemplate(id);
useEffect(() => {
async function templateData() {
try {
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
let response = await getTemplateData(organization);
setTemplates(response);
} catch (error) {
console.error("Error fetching template data:", error);
}
}
templateData();
}, []);
const handleDeleteTemplate = async (id: string) => {
try {
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
let response = await deleteTemplateApi(id, organization);
if (response.message === "Template deleted successfully") {
removeTemplate(id);
}
} catch (error) {
console.error("Error deleting template:", error);
}
};
const handleLoadTemplate = (template: any) => {
setSelectedZone((prev) => ({
...prev,
panelOrder: template.panelOrder,
activeSides: Array.from(
new Set([...prev.activeSides, ...template.panelOrder])
),
widgets: template.widgets,
}));
const handleLoadTemplate = async (template: any) => {
try {
if (selectedZone.zoneName === "") return;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
let response = await loadTempleteApi(template.id, selectedZone.zoneId, organization);
if (response.message === "Template placed in Zone") {
setSelectedZone({
panelOrder: template.panelOrder,
activeSides: Array.from(new Set(template.panelOrder)), // No merging with previous `activeSides`
widgets: template.widgets,
});
useDroppedObjectsStore.getState().setZone(selectedZone.zoneName, selectedZone.zoneId);
if (Array.isArray(template.floatingWidget)) {
template.floatingWidget.forEach((val: any) => {
useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, val);
});
}
}
} catch (error) {
console.error("Error loading template:", error);
}
};
return (
<div
className="template-list"
@@ -41,7 +92,7 @@ const Templates = () => {
transition: "box-shadow 0.3s ease",
}}
>
{template.snapshot && (
{template?.snapshot && (
<div style={{ position: "relative", paddingBottom: "56.25%" }}>
{" "}
{/* 16:9 aspect ratio */}
@@ -122,3 +173,4 @@ const Templates = () => {
};
export default Templates;

View File

@@ -13,7 +13,7 @@ const Header: React.FC = () => {
const guestUsers: ActiveUser[] = activeUsers.filter(
(user: ActiveUser) => user.userName !== userName
);
const [userManagement, setUserManagement] = useState(false);
return (
@@ -31,9 +31,9 @@ const Header: React.FC = () => {
>
Share
</div>
<div className="app-docker-button">
{/* <div className="app-docker-button">
<AppDockIcon />
</div>
</div> */}
</div>
<div className="split"></div>
<div className="users-container">
@@ -52,12 +52,7 @@ const Header: React.FC = () => {
))}
</div>
<div className="user-profile-container">
<div
className="user-profile"
style={{ background: "var(--accent-color)" }}
>
{userName[0]}
</div>
<div className="user-profile">{userName[0]}</div>
<div className="user-organization">
<img src={orgImg} alt="" />
</div>

View File

@@ -1,23 +1,32 @@
import React from "react";
import { EyeDroperIcon } from "../../../icons/ExportCommonIcons";
interface PositionInputProps {
label?: string; // Optional label for the input
onChange: (value: string) => void; // Callback for value change
placeholder?: string; // Optional placeholder
type?: string; // Input type (e.g., text, number, email)
value1?: number;
value2?: number;
disabled?: boolean; // Optional disabled property
isEyedrop?: boolean; // Optional eyedrop property
handleEyeDropClick?: () => void; // Optional function for eye drop click
}
const PositionInput: React.FC<PositionInputProps> = ({
onChange,
label = "Position", // Default label
placeholder = "Enter value", // Default placeholder
type = "number", // Default type
value1 = "number",
value2 = "number",
disabled = false, // Default disabled value
isEyedrop = false, // Default isEyedrop value
handleEyeDropClick = () => { }, // Default function for eye drop click
}) => {
return (
<div className="custom-input-container">
<div className="header">Position</div>
<div className="header">{label}</div>
<div className="inputs-container">
<div className="input-container">
<div className="custom-input-label">X : </div>
@@ -26,7 +35,8 @@ const PositionInput: React.FC<PositionInputProps> = ({
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
value={value2}
value={value1}
disabled={disabled} // Apply disabled prop
/>
</div>
<div className="input-container">
@@ -36,10 +46,16 @@ const PositionInput: React.FC<PositionInputProps> = ({
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
value={value1}
value={value2}
disabled={disabled} // Apply disabled prop
/>
</div>
</div>
{isEyedrop && (
<div className="eye-picker-button" onClick={handleEyeDropClick}>
<EyeDroperIcon isActive={false} />
</div>
)}
</div>
);
};

View File

@@ -9,9 +9,13 @@ import RenameInput from "../../../ui/inputs/RenameInput";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
import { handleResize } from "../../../../functions/handleResizePannel";
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from "../../../../store/store";
import * as THREE from 'three';
import * as Types from '../../../../types/world/worldTypes';
import {
useSelectedActionSphere,
useSelectedPath,
useSimulationPaths,
} from "../../../../store/store";
import * as THREE from "three";
import * as Types from "../../../../types/world/worldTypes";
import InputToggle from "../../../ui/inputs/InputToggle";
const ConveyorMechanics: React.FC = () => {
@@ -25,7 +29,9 @@ const ConveyorMechanics: React.FC = () => {
const selectedPoint = useMemo(() => {
if (!selectedActionSphere) return null;
return simulationPaths
.filter((path): path is Types.ConveyorEventsSchema => path.type === "Conveyor")
.filter(
(path): path is Types.ConveyorEventsSchema => path.type === "Conveyor"
)
.flatMap((path) => path.points)
.find((point) => point.uuid === selectedActionSphere.point.uuid);
}, [selectedActionSphere, simulationPaths]);
@@ -43,11 +49,11 @@ const ConveyorMechanics: React.FC = () => {
const newAction = {
uuid: THREE.MathUtils.generateUUID(),
name: `Action ${actionIndex + 1}`,
type: 'Inherit',
material: 'Inherit',
delay: 'Inherit',
spawnInterval: 'Inherit',
isUsed: false
type: "Inherit",
material: "Inherit",
delay: "Inherit",
spawnInterval: "Inherit",
isUsed: false,
};
return { ...point, actions: [...point.actions, newAction] };
@@ -68,13 +74,18 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.filter(
(action) => action.uuid !== uuid
),
}
: point
),
}
: path
);
@@ -87,26 +98,33 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid
? {
...action,
type: actionType,
material: actionType === 'Spawn' || actionType === 'Swap' ? 'Inherit' : action.material,
delay: actionType === 'Delay' ? 'Inherit' : action.delay,
spawnInterval: actionType === 'Spawn' ? 'Inherit' : action.spawnInterval
}
: action
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid
? {
...action,
type: actionType,
material:
actionType === "Spawn" || actionType === "Swap"
? "Inherit"
: action.material,
delay:
actionType === "Delay" ? "Inherit" : action.delay,
spawnInterval:
actionType === "Spawn"
? "Inherit"
: action.spawnInterval,
}
: action
),
}
: point
),
}
: path
);
@@ -115,15 +133,17 @@ const ConveyorMechanics: React.FC = () => {
// Update the selected item to reflect changes
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
const updatedAction = updatedPaths
.filter((path): path is Types.ConveyorEventsSchema => path.type === "Conveyor")
.flatMap(path => path.points)
.find(p => p.uuid === selectedActionSphere.point.uuid)
?.actions.find(a => a.uuid === uuid);
.filter(
(path): path is Types.ConveyorEventsSchema => path.type === "Conveyor"
)
.flatMap((path) => path.points)
.find((p) => p.uuid === selectedActionSphere.point.uuid)
?.actions.find((a) => a.uuid === uuid);
if (updatedAction) {
setSelectedItem({
type: "action",
item: updatedAction
item: updatedAction,
});
}
}
@@ -136,21 +156,21 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid &&
(action.type === 'Spawn' || action.type === 'Swap')
? { ...action, material }
: action
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid &&
(action.type === "Spawn" || action.type === "Swap")
? { ...action, material }
: action
),
}
: point
),
}
: path
);
@@ -162,8 +182,8 @@ const ConveyorMechanics: React.FC = () => {
...selectedItem,
item: {
...selectedItem.item,
material
}
material,
},
});
}
};
@@ -174,42 +194,47 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, delay } : action
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, delay } : action
),
}
: point
),
}
: path
);
setSimulationPaths(updatedPaths);
};
const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
const handleSpawnIntervalChange = (
uuid: string,
spawnInterval: number | string
) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid ? { ...action, spawnInterval } : action
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) =>
action.uuid === uuid
? { ...action, spawnInterval }
: action
),
}
: point
),
}
: path
);
@@ -233,23 +258,23 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) => {
if (point.uuid === selectedActionSphere.point.uuid) {
const triggerIndex = point.triggers.length;
const newTrigger = {
uuid: THREE.MathUtils.generateUUID(),
name: `Trigger ${triggerIndex + 1}`,
type: '',
bufferTime: 0,
isUsed: false
};
...path,
points: path.points.map((point) => {
if (point.uuid === selectedActionSphere.point.uuid) {
const triggerIndex = point.triggers.length;
const newTrigger = {
uuid: THREE.MathUtils.generateUUID(),
name: `Trigger ${triggerIndex + 1}`,
type: "",
bufferTime: 0,
isUsed: false,
};
return { ...point, triggers: [...point.triggers, newTrigger] };
}
return point;
}),
}
return { ...point, triggers: [...point.triggers, newTrigger] };
}
return point;
}),
}
: path
);
@@ -262,13 +287,18 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.filter(
(trigger) => trigger.uuid !== uuid
),
}
: point
),
}
: path
);
@@ -281,18 +311,20 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid
? { ...trigger, type: triggerType }
: trigger
),
}
: point
),
}
: path
);
@@ -309,26 +341,25 @@ const ConveyorMechanics: React.FC = () => {
}
};
// Update the toggle handlers to immediately update the selected item
const handleActionToggle = (uuid: string) => {
if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) => ({
...action,
isUsed: action.uuid === uuid ? !action.isUsed : false,
})),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
actions: point.actions.map((action) => ({
...action,
isUsed: action.uuid === uuid ? !action.isUsed : false,
})),
}
: point
),
}
: path
);
@@ -340,8 +371,8 @@ const ConveyorMechanics: React.FC = () => {
...selectedItem,
item: {
...selectedItem.item,
isUsed: !selectedItem.item.isUsed
}
isUsed: !selectedItem.item.isUsed,
},
});
}
};
@@ -353,19 +384,19 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) => ({
...trigger,
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
})),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) => ({
...trigger,
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
})),
}
: point
),
}
: path
);
@@ -377,8 +408,8 @@ const ConveyorMechanics: React.FC = () => {
...selectedItem,
item: {
...selectedItem.item,
isUsed: !selectedItem.item.isUsed
}
isUsed: !selectedItem.item.isUsed,
},
});
}
};
@@ -389,18 +420,20 @@ const ConveyorMechanics: React.FC = () => {
const updatedPaths = simulationPaths.map((path) =>
path.type === "Conveyor"
? {
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid ? { ...trigger, bufferTime } : trigger
),
}
: point
),
}
...path,
points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid
? {
...point,
triggers: point.triggers.map((trigger) =>
trigger.uuid === uuid
? { ...trigger, bufferTime }
: trigger
),
}
: point
),
}
: path
);
@@ -412,13 +445,16 @@ const ConveyorMechanics: React.FC = () => {
...selectedItem,
item: {
...selectedItem.item,
bufferTime
}
bufferTime,
},
});
}
};
const [selectedItem, setSelectedItem] = useState<{ type: "action" | "trigger"; item: any; } | null>(null);
const [selectedItem, setSelectedItem] = useState<{
type: "action" | "trigger";
item: any;
} | null>(null);
useEffect(() => {
setSelectedItem(null);
@@ -426,21 +462,20 @@ const ConveyorMechanics: React.FC = () => {
return (
<div className="machine-mechanics-container">
{!selectedPath &&
{!selectedPath && (
<div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "point name not found"}
</div>
}
{selectedPath &&
)}
{selectedPath && (
<div className="machine-mechanics-header">
{selectedPath.path.modelName || "path name not found"}
</div>
}
)}
<div className="machine-mechanics-content-container">
{!selectedPath &&
{!selectedPath && (
<>
<div className="actions">
<div className="header">
@@ -458,16 +493,20 @@ const ConveyorMechanics: React.FC = () => {
{selectedPoint?.actions.map((action) => (
<div
key={action.uuid}
className={`list-item ${selectedItem?.type === "action" &&
className={`list-item ${
selectedItem?.type === "action" &&
selectedItem.item?.uuid === action.uuid
? "active"
: ""
}`}
? "active"
: ""
}`}
>
<div
className="value"
onClick={() => setSelectedItem({ type: "action", item: action })}
onClick={() =>
setSelectedItem({ type: "action", item: action })
}
>
<input type="radio" name="action" id="action" defaultChecked={action.isUsed}/>
<RenameInput value={action.name} />
</div>
<div
@@ -504,16 +543,20 @@ const ConveyorMechanics: React.FC = () => {
{selectedPoint?.triggers.map((trigger) => (
<div
key={trigger.uuid}
className={`list-item ${selectedItem?.type === "trigger" &&
className={`list-item ${
selectedItem?.type === "trigger" &&
selectedItem.item?.uuid === trigger.uuid
? "active"
: ""
}`}
? "active"
: ""
}`}
>
<div
className="value"
onClick={() => setSelectedItem({ type: "trigger", item: trigger })}
onClick={() =>
setSelectedItem({ type: "trigger", item: trigger })
}
>
<input type="radio" name="trigger" id="trigger" defaultChecked={trigger.isUsed} />
<RenameInput value={trigger.name} />
</div>
<div
@@ -535,7 +578,7 @@ const ConveyorMechanics: React.FC = () => {
</div>
</div>
</>
}
)}
<div className="selected-properties-container">
{selectedItem && (
@@ -553,48 +596,69 @@ const ConveyorMechanics: React.FC = () => {
<LabledDropdown
defaultOption={selectedItem.item.type}
options={["Inherit", "Spawn", "Swap", "Despawn", "Delay"]}
onSelect={(option) => handleActionSelect(selectedItem.item.uuid, option)}
onSelect={(option) =>
handleActionSelect(selectedItem.item.uuid, option)
}
/>
{/* Only show material dropdown for Spawn/Swap actions */}
{(selectedItem.item.type === 'Spawn' || selectedItem.item.type === 'Swap') && (
{(selectedItem.item.type === "Spawn" ||
selectedItem.item.type === "Swap") && (
<LabledDropdown
label={selectedItem.item.type === 'Spawn' ? 'Spawn Material' : 'Swap Material'}
label={
selectedItem.item.type === "Spawn"
? "Spawn Material"
: "Swap Material"
}
defaultOption={selectedItem.item.material}
options={["Inherit", "Crate", "Box"]}
onSelect={(option) => handleMaterialSelect(selectedItem.item.uuid, option)}
onSelect={(option) =>
handleMaterialSelect(selectedItem.item.uuid, option)
}
/>
)}
{/* Only show delay input for Delay actions */}
{selectedItem.item.type === 'Delay' && (
{selectedItem.item.type === "Delay" && (
<InputWithDropDown
label="Delay Time"
value={selectedItem.item.delay === 'Inherit'
? undefined
: selectedItem.item.delay}
value={
selectedItem.item.delay === "Inherit"
? undefined
: selectedItem.item.delay
}
onChange={(value) => {
const numValue = parseInt(value);
handleDelayChange(
selectedItem.item.uuid,
!value ? 'Inherit' : numValue
!value ? "Inherit" : numValue
);
}}
/>
)}
{/* Only show spawn interval for Spawn actions */}
{selectedItem.item.type === 'Spawn' && (
{selectedItem.item.type === "Spawn" && (
<InputWithDropDown
label="Spawn Interval"
min={0}
defaultValue={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()}
value={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()}
defaultValue={
selectedItem.item.spawnInterval === "Inherit"
? ""
: selectedItem.item.spawnInterval.toString()
}
value={
selectedItem.item.spawnInterval === "Inherit"
? ""
: selectedItem.item.spawnInterval.toString()
}
onChange={(value) => {
handleSpawnIntervalChange(selectedItem.item.uuid, (value === "") ? "Inherit" : parseInt(value));
handleSpawnIntervalChange(
selectedItem.item.uuid,
value === "" ? "Inherit" : parseInt(value)
);
}}
/>
)}
</>
)}
@@ -609,9 +673,13 @@ const ConveyorMechanics: React.FC = () => {
/>
<LabledDropdown
defaultOption={selectedItem.item.type || "Select Trigger Type"}
defaultOption={
selectedItem.item.type || "Select Trigger Type"
}
options={["On-Hit", "Buffer"]}
onSelect={(option) => handleTriggerSelect(selectedItem.item.uuid, option)}
onSelect={(option) =>
handleTriggerSelect(selectedItem.item.uuid, option)
}
/>
{selectedItem.item.type === "Buffer" && (
@@ -619,23 +687,34 @@ const ConveyorMechanics: React.FC = () => {
label="Buffer Time"
value={selectedItem.item.bufferTime.toString()}
onChange={(value) => {
handleTriggerBufferTimeChange(selectedItem.item.uuid, parseInt(value));
handleTriggerBufferTimeChange(
selectedItem.item.uuid,
parseInt(value)
);
}}
/>
)}
</>
)}
</>
)}
{selectedPath && !selectedItem && (
<div key={selectedPath?.path.modeluuid || "none"} className="speed-control">
<div
key={selectedPath?.path.modeluuid || "none"}
className="speed-control"
>
<InputWithDropDown
label="Conveyor Speed"
min={0}
value={selectedPath.path.speed === "Inherit" ? "" : selectedPath.path.speed.toString()}
onChange={(value) => handleSpeedChange((value === "") ? "Inherit" : parseInt(value))}
value={
selectedPath.path.speed === "Inherit"
? ""
: selectedPath.path.speed.toString()
}
onChange={(value) =>
handleSpeedChange(value === "" ? "Inherit" : parseInt(value))
}
/>
</div>
)}
@@ -657,4 +736,4 @@ const ConveyorMechanics: React.FC = () => {
);
};
export default ConveyorMechanics;
export default ConveyorMechanics;

View File

@@ -1,13 +1,16 @@
import React, { useRef, useMemo } from "react";
import { InfoIcon } from "../../../icons/ExportCommonIcons";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import { useSelectedActionSphere, useSimulationPaths } from "../../../../store/store";
import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationPaths } from "../../../../store/store";
import * as Types from '../../../../types/world/worldTypes';
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
import PositionInput from "../customInput/PositionInputs";
const VehicleMechanics: React.FC = () => {
const { selectedActionSphere } = useSelectedActionSphere();
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
const { editingPoint, setEditingPoint } = useEditingPoint();
const { previewPosition, setPreviewPosition } = usePreviewPosition();
const propertiesContainerRef = useRef<HTMLDivElement>(null);
@@ -59,12 +62,10 @@ const VehicleMechanics: React.FC = () => {
setSimulationPaths(updatedPaths);
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
const handleStartPointChange = React.useCallback((uuid: string) => {
handleActionUpdate({ start: uuid });
const handleStartPointChange = React.useCallback((position: { x: number, y: number }) => {
}, [handleActionUpdate]);
const handleEndPointChange = React.useCallback((uuid: string) => {
handleActionUpdate({ end: uuid });
const handleEndPointChange = React.useCallback((position: { x: number, y: number }) => {
}, [handleActionUpdate]);
const handleHitCountChange = React.useCallback((hitCount: number) => {
@@ -94,6 +95,16 @@ const VehicleMechanics: React.FC = () => {
setSimulationPaths(updatedPaths);
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
const handleStartEyeDropClick = () => {
setEditingPoint('start');
setEyeDropMode(true);
};
const handleEndEyeDropClick = () => {
setEditingPoint('end');
setEyeDropMode(true);
};
return (
<div className="machine-mechanics-container" key={selectedPoint?.uuid}>
<div className="machine-mechanics-header">
@@ -106,20 +117,49 @@ const VehicleMechanics: React.FC = () => {
{selectedPoint && (
<>
<LabledDropdown
key={`start-${selectedPoint.uuid}`}
<PositionInput
label="Start Point"
defaultOption={selectedPoint.actions.start || "Select start point"}
options={connectedPointUuids}
onSelect={handleStartPointChange}
onChange={() => { }}
disabled={true}
value1={
editingPoint === 'start' && previewPosition
? parseFloat(previewPosition.x.toFixed(4))
: selectedPoint.actions.start && 'x' in selectedPoint.actions.start
? parseFloat(selectedPoint.actions.start.x.toFixed(4))
: 0
}
value2={
editingPoint === 'start' && previewPosition
? parseFloat(previewPosition.y.toFixed(4))
: selectedPoint.actions.start && 'y' in selectedPoint.actions.start
? parseFloat(selectedPoint.actions.start.y.toFixed(4))
: 0
}
isEyedrop={true}
handleEyeDropClick={handleStartEyeDropClick}
/>
<LabledDropdown
key={`end-${selectedPoint.uuid}`}
<PositionInput
label="End Point"
defaultOption={selectedPoint.actions.end || "Select end point"}
options={connectedPointUuids}
onSelect={handleEndPointChange}
onChange={() => { }}
disabled={true}
value1={
editingPoint === 'end' && previewPosition
? parseFloat(previewPosition.x.toFixed(4))
: selectedPoint.actions.end && 'x' in selectedPoint.actions.end
? parseFloat(selectedPoint.actions.end.x.toFixed(4))
: 0
}
value2={
editingPoint === 'end' && previewPosition
? parseFloat(previewPosition.y.toFixed(4))
: selectedPoint.actions.end && 'y' in selectedPoint.actions.end
? parseFloat(selectedPoint.actions.end.y.toFixed(4))
: 0
}
isEyedrop={true}
handleEyeDropClick={handleEndEyeDropClick}
/>
<InputWithDropDown

View File

@@ -49,8 +49,6 @@ const AssetProperties: React.FC = () => {
{/* Name */}
<div className="header">{selectedFloorItem.userData.name}</div>
<div className="split"></div>
<PositionInput
onChange={() => {}}
value1={selectedFloorItem.position.x.toFixed(5)}

View File

@@ -20,17 +20,16 @@ const ZoneProperties: React.FC = () => {
try {
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
let zonesdata = {
zoneId: selectedZone.zoneId,
viewPortposition: zonePosition,
viewPortCenter: zoneTarget
};
let response = await zoneCameraUpdate(zonesdata, organization);
console.log('response: ', response);
setEdit(false);
} catch (error) {
console.error("Error in handleSetView:", error);

View File

@@ -0,0 +1,177 @@
import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import useChartStore from "../../../../../store/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
type Props = {};
const FlotingWidgetInput = (props: Props) => {
const [widgetName, setWidgetName] = useState('Widget');
const { setMeasurements, updateDuration, updateName } = useChartStore();
const [duration, setDuration] = useState('1h')
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
const { selectedZone } = useSelectedZoneStore();
const { selectedChartId } = useWidgetStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get(`http://${iotApiUrl}/getinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
console.error("There was an error!", error);
}
};
fetchZoneData();
}, []);
useEffect(() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`);
if (response.status === 200) {
setSelections(response.data.Data.measurements)
setDuration(response.data.Data.duration)
setWidgetName(response.data.widgetName)
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
console.error("There was an error!", error);
}
}
}
fetchSavedInputes();
}, [selectedChartId.id]);
// Sync Zustand state when component mounts
useEffect(() => {
setMeasurements(selections);
updateDuration(duration);
updateName(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
try {
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/floatwidget/save`, {
organization: organization,
zoneId: selectedZone.zoneId,
widget: {
id: selectedChartId.id,
panel: selectedChartId.panel,
widgetName: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration
}
}
} as any);
if (response.status === 200) {
return true
} else {
console.log("Unexpected response:", response);
return false
}
} catch (error) {
console.error("There was an error!", error);
return false
}
}
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
// sendInputes(newSelections, duration); // Send data to server
// return newSelections;
// };
};
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
// setDuration(option);
};
const handleNameChange = async (name:any) => {
console.log('name change requested',name);
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
}
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput value={selectedChartId?.title || "untited"} onRename={handleNameChange}/>
</div>
{[...Array(6)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
<div key={index} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropdown
data={dropDowndata}
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
onUnselect={() => handleSelect(inputKey, null)}
selectedValue={selections[inputKey]} // Load from Zustand
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
<div>
<div className="datas">
<div className="datas__label">Duration</div>
<div className="datas__class">
<RegularDropDown
header={duration}
options={["1h", "2h", "12h"]}
onSelect={handleSelectDuration}
search={false}
/>
</div>
</div>
</div>
</>
);
};
export default FlotingWidgetInput;

View File

@@ -58,11 +58,11 @@
// name: string;
// fields: string;
// }
// interface InputData {
// [key: string]: Measurement;
// }
// const extractMeasurements = (input: InputData): Measurement[] => {
// return Object.values(input);
// };
@@ -71,7 +71,7 @@
// const measurementsData = extractMeasurements(selections);
// setMeasurements(measurementsData);
// }, [selections]);
// return (
// <>
@@ -125,20 +125,22 @@ import useChartStore from "../../../../../store/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
type Props = {};
const LineGrapInput = (props: Props) => {
const { setMeasurements, updateDuration } = useChartStore();
const [widgetName, setWidgetName] = useState('Widget');
const { setMeasurements, updateDuration, updateName } = useChartStore();
const [duration, setDuration] = useState('1h')
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
const { selectedZone } = useSelectedZoneStore();
const { selectedChartId } = useWidgetStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]
useEffect(() => {
const fetchZoneData = async () => {
try {
@@ -157,13 +159,14 @@ const LineGrapInput = (props: Props) => {
}, []);
useEffect(() => {
const fetchSavedInputes = async() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`);
if (response.status === 200) {
setSelections(response.data.Data.measurements)
setDuration(response.data.Data.duration)
setWidgetName(response.data.widgetName)
} else {
console.log("Unexpected response:", response);
}
@@ -181,17 +184,19 @@ const LineGrapInput = (props: Props) => {
useEffect(() => {
setMeasurements(selections);
updateDuration(duration);
}, [selections, duration]);
updateName(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async(inputMeasurement: any, inputDuration: any) => {
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
try {
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`,{
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, {
organization: organization,
zoneId: selectedZone.zoneId,
widget:{
widget: {
id: selectedChartId.id,
panel: selectedChartId.panel,
widgetName: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration
@@ -210,35 +215,47 @@ const LineGrapInput = (props: Props) => {
}
}
const handleSelect = async(inputKey: string, selectedData: { name: string; fields: string } | null) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
console.log(newSelections);
if ( await sendInputes(newSelections, duration)) {
setSelections(newSelections);
}
// sendInputes(newSelections, duration); // Send data to server
// return newSelections;
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
// sendInputes(newSelections, duration); // Send data to server
// return newSelections;
// };
};
const handleSelectDuration = async(option: string) => {
if ( await sendInputes(selections, option)) {
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
// setDuration(option);
};
const handleNameChange = async (name:any) => {
console.log('name change requested',name);
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
}
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput value={selectedChartId?.title || "untited"} onRename={handleNameChange}/>
</div>
{[...Array(6)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (

View File

@@ -3,6 +3,7 @@ import { useWidgetStore } from "../../../../../store/useWidgetStore";
import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons";
import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown";
import LineGrapInput from "../IotInputCards/LineGrapInput";
import RenameInput from "../../../../ui/inputs/RenameInput";
// Define the data structure for demonstration purposes
const DATA_STRUCTURE = {
@@ -107,27 +108,36 @@ const Data = () => {
[selectedChartId.id]: currentChartData.map((group) =>
group.id === groupId
? {
...group,
children: group.children.filter(
(child) => child.id !== childId
),
}
...group,
children: group.children.filter(
(child) => child.id !== childId
),
}
: group
),
};
});
};
console.log("selectedChartId", selectedChartId);
return (
<div className="dataSideBar">
{selectedChartId?.title && (
{/* {selectedChartId?.title && (
<div className="sideBarHeader">{selectedChartId?.title}</div>
)}
)} */}
{/* <RenameInput value={selectedChartId?.title || "untited"} /> */}
{/* Render groups dynamically */}
{
chartDataGroups[selectedChartId?.id] && <LineGrapInput />
chartDataGroups[selectedChartId?.id] &&
<>
<div className="sideBarHeader">2D Widget Input</div>
<LineGrapInput />
</>
}
{/* Info Box */}
<div className="infoBox">
<span className="infoIcon">i</span>

View File

@@ -1,12 +1,24 @@
import React from "react";
import React, { useState } from "react";
import RenameInput from "./inputs/RenameInput";
import { ArrowIcon } from "../icons/ExportCommonIcons";
import MenuBar from "./menu/menu";
const FileMenu: React.FC = () => {
const [openMenu, setOpenMenu] = useState(false);
return (
<div className="project-dropdowm-container">
<div className="project-name">
<RenameInput value="untitled" />
</div>
<div
className="more-options-button"
onClick={() => {
setOpenMenu(!openMenu);
}}
>
<ArrowIcon />
{openMenu && <MenuBar setOpenMenu={setOpenMenu} />}
</div>
</div>
);
};

View File

@@ -14,7 +14,7 @@ import {
ZoneIcon,
} from "../icons/ExportToolsIcons";
import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons";
import useModuleStore from "../../store/useModuleStore";
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
import { handleSaveTemplate } from "../../modules/visualization/handleSaveTemplate";
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
import useTemplateStore from "../../store/useTemplateStore";
@@ -32,12 +32,13 @@ import {
useTransformMode,
} from "../../store/store";
import useToggleStore from "../../store/useUIToggleStore";
import { use3DWidget, useFloatingWidget } from "../../store/useDroppedObjectsStore";
const Tools: React.FC = () => {
const { templates } = useTemplateStore();
const [activeSubTool, setActiveSubTool] = useState("cursor");
const [toggleThreeD, setToggleThreeD] = useState(true);
const { toggleUI, setToggleUI } = useToggleStore();
const { toggleThreeD, setToggleThreeD } = useThreeDStore();
const { setToggleUI } = useToggleStore();
const dropdownRef = useRef<HTMLDivElement>(null);
const [openDrop, setOpenDrop] = useState(false);
@@ -46,6 +47,8 @@ const Tools: React.FC = () => {
const { isPlaying, setIsPlaying } = usePlayButtonStore();
const { addTemplate } = useTemplateStore();
const { selectedZone } = useSelectedZoneStore();
const { floatingWidget } = useFloatingWidget()
const { widgets3D } = use3DWidget()
// wall options
const { toggleView, setToggleView } = useToggleView();
@@ -68,7 +71,7 @@ const Tools: React.FC = () => {
: true
);
}, []);
useEffect(() => {}, [activeModule]);
useEffect(() => { }, [activeModule]);
useEffect(() => {
setActiveTool(activeSubTool);
setActiveSubTool(activeSubTool);
@@ -210,9 +213,8 @@ const Tools: React.FC = () => {
<div className="activeDropicon">
{activeSubTool == "cursor" && (
<div
className={`tool-button ${
activeTool === "cursor" ? "active" : ""
}`}
className={`tool-button ${activeTool === "cursor" ? "active" : ""
}`}
onClick={() => {
setActiveTool("cursor");
}}
@@ -222,9 +224,8 @@ const Tools: React.FC = () => {
)}
{activeSubTool == "free-hand" && (
<div
className={`tool-button ${
activeTool === "free-hand" ? "active" : ""
}`}
className={`tool-button ${activeTool === "free-hand" ? "active" : ""
}`}
onClick={() => {
setActiveTool("free-hand");
}}
@@ -234,9 +235,8 @@ const Tools: React.FC = () => {
)}
{activeSubTool == "delete" && (
<div
className={`tool-button ${
activeTool === "delete" ? "active" : ""
}`}
className={`tool-button ${activeTool === "delete" ? "active" : ""
}`}
onClick={() => {
setActiveTool("delete");
}}
@@ -308,9 +308,8 @@ const Tools: React.FC = () => {
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${
activeTool === "draw-wall" ? "active" : ""
}`}
className={`tool-button ${activeTool === "draw-wall" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-wall");
}}
@@ -319,9 +318,8 @@ const Tools: React.FC = () => {
<WallIcon isActive={activeTool === "draw-wall"} />
</div>
<div
className={`tool-button ${
activeTool === "draw-zone" ? "active" : ""
}`}
className={`tool-button ${activeTool === "draw-zone" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-zone");
}}
@@ -330,9 +328,8 @@ const Tools: React.FC = () => {
<ZoneIcon isActive={activeTool === "draw-zone"} />
</div>
<div
className={`tool-button ${
activeTool === "draw-aisle" ? "active" : ""
}`}
className={`tool-button ${activeTool === "draw-aisle" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-aisle");
}}
@@ -341,9 +338,8 @@ const Tools: React.FC = () => {
<AsileIcon isActive={activeTool === "draw-aisle"} />
</div>
<div
className={`tool-button ${
activeTool === "draw-floor" ? "active" : ""
}`}
className={`tool-button ${activeTool === "draw-floor" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-floor");
}}
@@ -359,9 +355,8 @@ const Tools: React.FC = () => {
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${
activeTool === "measure" ? "active" : ""
}`}
className={`tool-button ${activeTool === "measure" ? "active" : ""
}`}
onClick={() => {
setActiveTool("measure");
}}
@@ -377,9 +372,8 @@ const Tools: React.FC = () => {
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${
activeTool === "pen" ? "active" : ""
}`}
className={`tool-button ${activeTool === "pen" ? "active" : ""
}`}
onClick={() => {
setActiveTool("pen");
}}
@@ -395,13 +389,17 @@ const Tools: React.FC = () => {
<div className="draw-tools">
<div
className={`tool-button`}
onClick={() =>
onClick={() => {
handleSaveTemplate({
addTemplate,
floatingWidget,
widgets3D,
selectedZone,
templates,
})
}
}
>
<SaveTemplateIcon isActive={false} />
</div>
@@ -411,9 +409,8 @@ const Tools: React.FC = () => {
<div className="split"></div>
<div className="general-options">
<div
className={`tool-button ${
activeTool === "comment" ? "active" : ""
}`}
className={`tool-button ${activeTool === "comment" ? "active" : ""
}`}
onClick={() => {
setActiveTool("comment");
}}
@@ -422,9 +419,8 @@ const Tools: React.FC = () => {
</div>
{toggleThreeD && (
<div
className={`tool-button ${
activeTool === "play" ? "active" : ""
}`}
className={`tool-button ${activeTool === "play" ? "active" : ""
}`}
onClick={() => {
setIsPlaying(!isPlaying);
}}
@@ -433,20 +429,23 @@ const Tools: React.FC = () => {
</div>
)}
</div>
<div className="split"></div>
<div
className={`toggle-threed-button${
toggleThreeD ? " toggled" : ""
}`}
onClick={toggleSwitch}
>
<div className={`toggle-option${!toggleThreeD ? " active" : ""}`}>
2d
</div>
<div className={`toggle-option${toggleThreeD ? " active" : ""}`}>
3d
</div>
</div>
{activeModule === "builder" && (
<>
<div className="split"></div>
<div
className={`toggle-threed-button${toggleThreeD ? " toggled" : ""
}`}
onClick={toggleSwitch}
>
<div className={`toggle-option${!toggleThreeD ? " active" : ""}`}>
2d
</div>
<div className={`toggle-option${toggleThreeD ? " active" : ""}`}>
3d
</div>
</div>
</>
)}
</div>
</>
) : (

View File

@@ -119,7 +119,6 @@ const AddButtons: React.FC<ButtonsProps> = ({
};
// Delete the selectedZone state
setSelectedZone(updatedZone);
} else {
const updatePanelData = async () => {

View File

@@ -2,9 +2,10 @@ import React, { useEffect, useRef, useState, useCallback } from "react";
import { Widget } from "../../../store/useWidgetStore";
import { MoveArrowLeft, MoveArrowRight } from "../../icons/SimulationIcons";
import { InfoIcon } from "../../icons/ExportCommonIcons";
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
import { useDroppedObjectsStore, useFloatingWidget } from "../../../store/useDroppedObjectsStore";
import { getSelect2dZoneData } from "../../../services/realTimeVisulization/zoneData/getSelect2dZoneData";
import { getFloatingZoneData } from "../../../services/realTimeVisulization/zoneData/getFloatingData";
import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData";
// Define the type for `Side`
type Side = "top" | "bottom" | "left" | "right";
@@ -72,6 +73,7 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
// State to track overflow visibility
const [showLeftArrow, setShowLeftArrow] = useState(false);
const [showRightArrow, setShowRightArrow] = useState(false);
const { floatingWidget, setFloatingWidget } = useFloatingWidget()
// Function to calculate overflow state
const updateOverflowState = useCallback(() => {
@@ -150,14 +152,16 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
async function handleSelect2dZoneData(zoneId: string, zoneName: string) {
try {
if (selectedZone?.zoneId === zoneId) {
console.log("Zone is already selected:", zoneName);
return;
}
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
// Fetch data from backend
let response = await getSelect2dZoneData(zoneId, organization);
console.log('response: ', response);
let res = await getFloatingZoneData(zoneId, organization);
setFloatingWidget(res)
// Set the selected zone in the store
useDroppedObjectsStore.getState().setZone(zoneName, zoneId);
if (Array.isArray(res)) {
@@ -177,8 +181,8 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
zoneViewPortPosition: response.viewPortposition || {},
});
} catch (error) {
console.log('error: ', error);
}
}
@@ -186,9 +190,8 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
return (
<div
ref={containerRef}
className={`zone-wrapper ${
selectedZone?.activeSides?.includes("bottom") && "bottom"
}`}
className={`zone-wrapper ${selectedZone?.activeSides?.includes("bottom") && "bottom"
}`}
>
{/* Left Arrow */}
{showLeftArrow && (

View File

@@ -0,0 +1,93 @@
import React from "react";
interface DistanceLinesProps {
obj: {
position: {
top?: number | "auto";
left?: number | "auto";
right?: number | "auto";
bottom?: number | "auto";
};
};
activeEdges: {
vertical: "top" | "bottom";
horizontal: "left" | "right";
} | null;
}
const DistanceLines: React.FC<DistanceLinesProps> = ({ obj, activeEdges }) => {
if (!activeEdges) return null;
return (
<>
{activeEdges.vertical === "top" && typeof obj.position.top === "number" && (
<div
className="distance-line top"
style={{
top: 0,
left:
activeEdges.horizontal === "left"
? `${(obj.position.left as number) + 125}px`
: `calc(100% - ${(obj.position.right as number) + 125}px)`,
height: `${obj.position.top}px`,
}}
>
<span className="distance-label">{obj.position.top.toFixed()}px</span>
</div>
)}
{activeEdges.vertical === "bottom" &&
typeof obj.position.bottom === "number" && (
<div
className="distance-line bottom"
style={{
bottom: 0,
left:
activeEdges.horizontal === "left"
? `${(obj.position.left as number) + 125}px`
: `calc(100% - ${(obj.position.right as number) + 125}px)`,
height: `${obj.position.bottom}px`,
}}
>
<span className="distance-label">{obj.position.bottom.toFixed()}px</span>
</div>
)}
{activeEdges.horizontal === "left" &&
typeof obj.position.left === "number" && (
<div
className="distance-line left"
style={{
left: 0,
top:
activeEdges.vertical === "top"
? `${(obj.position.top as number) + 41.5}px`
: `calc(100% - ${(obj.position.bottom as number) + 41.5}px)`,
width: `${obj.position.left}px`,
}}
>
<span className="distance-label">{obj.position.left.toFixed()}px</span>
</div>
)}
{activeEdges.horizontal === "right" &&
typeof obj.position.right === "number" && (
<div
className="distance-line right"
style={{
right: 0,
top:
activeEdges.vertical === "top"
? `${(obj.position.top as number) + 41.5}px`
: `calc(100% - ${(obj.position.bottom as number) + 41.5}px)`,
width: `${obj.position.right}px`,
}}
>
<span className="distance-label">{obj.position.right.toFixed()}px</span>
</div>
)}
</>
);
};
export default DistanceLines;

View File

@@ -0,0 +1,93 @@
import React from "react";
interface DistanceLinesProps {
obj: {
position: {
top?: number | "auto";
left?: number | "auto";
right?: number | "auto";
bottom?: number | "auto";
};
};
activeEdges: {
vertical: "top" | "bottom";
horizontal: "left" | "right";
} | null;
}
const DistanceLines: React.FC<DistanceLinesProps> = ({ obj, activeEdges }) => {
if (!activeEdges) return null;
return (
<>
{activeEdges.vertical === "top" && typeof obj.position.top === "number" && (
<div
className="distance-line top"
style={{
top: 0,
left:
activeEdges.horizontal === "left"
? `${(obj.position.left as number) + 125}px`
: `calc(100% - ${(obj.position.right as number) + 125}px)`,
height: `${obj.position.top}px`,
}}
>
<span className="distance-label">{obj.position.top}px</span>
</div>
)}
{activeEdges.vertical === "bottom" &&
typeof obj.position.bottom === "number" && (
<div
className="distance-line bottom"
style={{
bottom: 0,
left:
activeEdges.horizontal === "left"
? `${(obj.position.left as number) + 125}px`
: `calc(100% - ${(obj.position.right as number) + 125}px)`,
height: `${obj.position.bottom}px`,
}}
>
<span className="distance-label">{obj.position.bottom}px</span>
</div>
)}
{activeEdges.horizontal === "left" &&
typeof obj.position.left === "number" && (
<div
className="distance-line left"
style={{
left: 0,
top:
activeEdges.vertical === "top"
? `${(obj.position.top as number) + 41.5}px`
: `calc(100% - ${(obj.position.bottom as number) + 41.5}px)`,
width: `${obj.position.left}px`,
}}
>
<span className="distance-label">{obj.position.left}px</span>
</div>
)}
{activeEdges.horizontal === "right" &&
typeof obj.position.right === "number" && (
<div
className="distance-line right"
style={{
right: 0,
top:
activeEdges.vertical === "top"
? `${(obj.position.top as number) + 41.5}px`
: `calc(100% - ${(obj.position.bottom as number) + 41.5}px)`,
width: `${obj.position.right}px`,
}}
>
<span className="distance-label">{obj.position.right}px</span>
</div>
)}
</>
);
};
export default DistanceLines;

View File

@@ -306,34 +306,20 @@ export const DraggableWidget = ({
)}
{widget.type === "doughnut" && (
<DoughnutGraphComponent
id={widget.id}
type={widget.type}
title={widget.title}
fontSize={widget.fontSize}
fontWeight={widget.fontWeight}
data={{
measurements: [
{ name: "testDevice", fields: "powerConsumption" },
{ name: "furnace", fields: "powerConsumption" },
],
interval: 1000,
duration: "1h",
}}
/>
)}
{widget.type === "polarArea" && (
<PolarAreaGraphComponent
id={widget.id}
type={widget.type}
title={widget.title}
fontSize={widget.fontSize}
fontWeight={widget.fontWeight}
data={{
measurements: [
{ name: "testDevice", fields: "powerConsumption" },
{ name: "furnace", fields: "powerConsumption" },
],
interval: 1000,
duration: "1h",
}}
/>
)}
</div>

View File

@@ -10,79 +10,138 @@ import ProductionCapacity from "../../layout/3D-cards/cards/ProductionCapacity";
import ReturnOfInvestment from "../../layout/3D-cards/cards/ReturnOfInvestment";
import StateWorking from "../../layout/3D-cards/cards/StateWorking";
import { useSelectedZoneStore } from "../../../store/useZoneStore";
import { generateUniqueId } from "../../../functions/generateUniqueId";
import { adding3dWidgets } from "../../../services/realTimeVisulization/zoneData/add3dWidget";
import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData";
import { use3DWidget } from "../../../store/useDroppedObjectsStore";
export default function Dropped3dWidgets() {
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
const { widgetSelect } = useAsset3dWidget();
const { activeModule } = useModuleStore();
const { raycaster, gl, scene }: ThreeState = useThree();
const { selectedZone } = useSelectedZoneStore(); // Get currently selected zone
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption()
// 🔥 Store widget positions per zone
const [zoneWidgets, setZoneWidgets] = useState<Record<
string, // Zone ID
Record<string, [number, number, number][]> // Widget type -> Positions array
>>({});
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
const { selectedZone } = useSelectedZoneStore(); // Get the currently active zone
// 🔥 Store widget data (id, type, position) based on the selected zone
const [zoneWidgetData, setZoneWidgetData] = useState<
Record<string, { id: string; type: string; position: [number, number, number] }[]>
>({});
const { setWidgets3D } = use3DWidget()
useEffect(() => {
if (activeModule !== "visualization") return
if (selectedZone.zoneName === "") return;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
async function get3dWidgetData() {
let result = await get3dWidgetZoneData(selectedZone.zoneId, organization);
setWidgets3D(result)
// Ensure the extracted data has id, type, and position correctly mapped
const formattedWidgets = result.map((widget: any) => ({
id: widget.id,
type: widget.type,
position: widget.position,
}));
setZoneWidgetData((prev) => ({
...prev,
[selectedZone.zoneId]: formattedWidgets,
}));
}
get3dWidgetData();
}, [selectedZone.zoneId,activeModule]);
// useEffect(() => {
// // ✅ Set data only for the selected zone, keeping existing state structure
// setZoneWidgetData((prev) => ({
// ...prev,
// [selectedZone.zoneId]: [
// {
// "id": "1743322674626-50mucpb1c",
// "type": "ui-Widget 1",
// "position": [120.94655021768133, 4.142360029666558, 124.39283546121099]
// },
// {
// "id": "1743322682086-je2h9x33v",
// "type": "ui-Widget 2",
// "position": [131.28751045879255, 0.009999999999970264, 133.92059801984362]
// }
// ]
// }));
// }, [selectedZone.zoneId]); // ✅ Only update when the zone changes
useEffect(() => {
if (widgetSubOption === "Floating") return
// if (activeModule !== "visualization") return;
if (activeModule !== "visualization") return;
if (widgetSubOption === "Floating") return;
if (selectedZone.zoneName === "") return
const canvasElement = gl.domElement;
const onDrop = (event: DragEvent) => {
const onDrop = async (event: DragEvent) => {
event.preventDefault(); // Prevent default browser behavior
if (widgetSubOption === "3D") {
if (selectedZone.zoneName === "") return
if (!widgetSelect?.startsWith("ui")) return;
const group1 = scene.getObjectByName("itemsGroup");
if (!group1) return;
const Assets = group1.children
.map((val) => scene.getObjectByProperty("uuid", val.uuid))
.filter(Boolean) as THREE.Object3D[];
const intersects = raycaster.intersectObjects(scene.children, true).filter(
(intersect) =>
!intersect.object.name.includes("Roof") &&
!intersect.object.name.includes("agv-collider") &&
!intersect.object.name.includes("MeasurementReference") &&
!intersect.object.userData.isPathObject &&
!(intersect.object.type === "GridHelper")
);
if (intersects.length > 0) {
const { x, y, z } = intersects[0].point;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
if (!widgetSelect.startsWith("ui")) return;
const group1 = scene.getObjectByName("itemsGroup");
if (!group1) return;
const intersects = raycaster.intersectObjects(scene.children, true).filter(
(intersect) =>
!intersect.object.name.includes("Roof") &&
!intersect.object.name.includes("agv-collider") &&
!intersect.object.name.includes("MeasurementReference") &&
!intersect.object.userData.isPathObject &&
!(intersect.object.type === "GridHelper")
);
if (intersects.length > 0) {
const { x, y, z } = intersects[0].point;
setZoneWidgets((prev) => ({
...prev,
[selectedZone.zoneId]: {
...(prev[selectedZone.zoneId] || {}),
[widgetSelect]: [...(prev[selectedZone.zoneId]?.[widgetSelect] || []), [x, y, z]],
},
}));
}
// ✅ Explicitly define position as a tuple
const newWidget: { id: string; type: string; position: [number, number, number] } = {
id: generateUniqueId(),
type: widgetSelect,
position: [x, y, z], // Ensures TypeScript recognizes it as a tuple
};
let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget)
// ✅ Store widgets uniquely for each zone
setZoneWidgetData((prev) => ({
...prev,
[selectedZone.zoneId]: [...(prev[selectedZone.zoneId] || []), newWidget],
}));
}
};
canvasElement.addEventListener("drop", onDrop);
return () => {
canvasElement.removeEventListener("drop", onDrop)
// setWidgetSelect()
canvasElement.removeEventListener("drop", onDrop);
};
}, [widgetSelect, activeModule, widgetSubOption]);
}, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption]);
// Get widgets for the currently active zone
const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || [];
return (
<>
{zoneWidgets[selectedZone.zoneId]?.["ui-Widget 1"]?.map((pos, index) => (
<ProductionCapacity key={`Widget1-${index}`} position={pos} />
))}
{zoneWidgets[selectedZone.zoneId]?.["ui-Widget 2"]?.map((pos, index) => (
<ReturnOfInvestment key={`Widget2-${index}`} position={pos} />
))}
{zoneWidgets[selectedZone.zoneId]?.["ui-Widget 3"]?.map((pos, index) => (
<StateWorking key={`Widget3-${index}`} position={pos} />
))}
{zoneWidgets[selectedZone.zoneId]?.["ui-Widget 4"]?.map((pos, index) => (
<Throughput key={`Widget4-${index}`} position={pos} />
))}
{activeZoneWidgets.map(({ id, type, position }) => {
switch (type) {
case "ui-Widget 1":
return <ProductionCapacity key={id} position={position} />;
case "ui-Widget 2":
return <ReturnOfInvestment key={id} position={position} />;
case "ui-Widget 3":
return <StateWorking key={id} position={position} />;
case "ui-Widget 4":
return <Throughput key={id} position={position} />;
default:
return null;
}
})}
</>
);
}

View File

@@ -1,6 +1,6 @@
import { WalletIcon } from "../../icons/3dChartIcons";
import { useEffect, useRef, useState } from "react";
import { Line } from "react-chartjs-2";
import {
useDroppedObjectsStore,
Zones,
@@ -9,29 +9,102 @@ import useModuleStore from "../../../store/useModuleStore";
import { determinePosition } from "./functions/determinePosition";
import { getActiveProperties } from "./functions/getActiveProperties";
import { addingFloatingWidgets } from "../../../services/realTimeVisulization/zoneData/addFloatingWidgets";
import {
DublicateIcon,
KebabIcon,
DeleteIcon,
} from "../../icons/ExportCommonIcons";
import DistanceLines from "./DistanceLines"; // Import the DistanceLines component
import { deleteFloatingWidgetApi } from "../../../services/realTimeVisulization/zoneData/deleteFloatingWidget";
import TotalCardComponent from "../realTimeVis/floating/TotalCardComponent";
import WarehouseThroughputComponent from "../realTimeVis/floating/WarehouseThroughputComponent";
import FleetEfficiencyComponent from "../realTimeVis/floating/FleetEfficiencyComponent";
import { useWidgetStore } from "../../../store/useWidgetStore";
interface DraggingState {
zone: string;
index: number;
initialPosition: {
top: number | "auto";
left: number | "auto";
right: number | "auto";
bottom: number | "auto";
};
}
interface DraggingState {
zone: string;
index: number;
initialPosition: {
top: number | "auto";
left: number | "auto";
right: number | "auto";
bottom: number | "auto";
};
}
const DroppedObjects: React.FC = () => {
const zones = useDroppedObjectsStore((state) => state.zones);
const [openKebabId, setOpenKebabId] = useState<string | null>(null);
const updateObjectPosition = useDroppedObjectsStore(
(state) => state.updateObjectPosition
);
const [draggingIndex, setDraggingIndex] = useState<{
zone: string;
index: number;
} | null>(null);
const deleteObject = useDroppedObjectsStore((state) => state.deleteObject);
const duplicateObject = useDroppedObjectsStore((state) => state.duplicateObject);
const [draggingIndex, setDraggingIndex] = useState<DraggingState | null>(
null
);
const [offset, setOffset] = useState<[number, number] | null>(null);
const positionRef = useRef<[number, number] | null>(null);
const { setSelectedChartId } = useWidgetStore();
const [activeEdges, setActiveEdges] = useState<{
vertical: "top" | "bottom";
horizontal: "left" | "right";
} | null>(null); // State to track active edges for distance lines
const [currentPosition, setCurrentPosition] = useState<{
top: number | "auto";
left: number | "auto";
right: number | "auto";
bottom: number | "auto";
} | null>(null); // State to track the current position during drag
const animationRef = useRef<number | null>(null);
const { activeModule } = useModuleStore();
// Get the first zone and its objects
const zoneEntries = Object.entries(zones);
if (zoneEntries.length === 0) return null; // No zone, nothing to render
const [zoneName, zone] = zoneEntries[0]; // Only render the first zone
// Clean up animation frame on unmount
useEffect(() => {
return () => {
if (animationRef.current) {
cancelAnimationFrame(animationRef.current);
}
};
}, []);
// Handle pointer down event
function handlePointerDown(event: React.PointerEvent, index: number) {
const zoneEntries = Object.entries(zones);
if (zoneEntries.length === 0) return null;
const [zoneName, zone] = zoneEntries[0];
function handleDuplicate(zoneName: string, index: number) {
setOpenKebabId(null)
duplicateObject(zoneName, index); // Call the duplicateObject method from the store
}
async function handleDelete(zoneName: string, id: string, index: number) {
try {
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
let res = await deleteFloatingWidgetApi(id, organization);
console.log('res: ', res);
if (res.message === "FloatingWidget deleted successfully") {
deleteObject(zoneName, index); // Call the deleteObject method from the store
}
} catch (error) {
console.error("Error deleting floating widget:", error);
}
}
const handlePointerDown = (event: React.PointerEvent, index: number) => {
const obj = zone.objects[index];
const container = document.getElementById("real-time-vis-canvas");
if (!container) return;
@@ -40,41 +113,41 @@ const DroppedObjects: React.FC = () => {
const relativeX = event.clientX - rect.left;
const relativeY = event.clientY - rect.top;
// Determine which properties are active for this object
// Determine active properties for the initial position
const [activeProp1, activeProp2] = getActiveProperties(obj.position);
// Calculate the offset based on the active properties
// Set active edges for distance lines
const vertical = activeProp1 === "top" ? "top" : "bottom";
const horizontal = activeProp2 === "left" ? "left" : "right";
setActiveEdges({ vertical, horizontal });
// Store the initial position strategy and active edges
setDraggingIndex({
zone: zoneName,
index,
initialPosition: { ...obj.position },
});
// Calculate offset from mouse to object edges
let offsetX = 0;
let offsetY = 0;
if (activeProp1 === "top") {
offsetY =
relativeY -
(typeof obj.position.top === "number" ? obj.position.top : 0);
} else if (activeProp1 === "bottom") {
offsetY =
rect.height -
relativeY -
(typeof obj.position.bottom === "number" ? obj.position.bottom : 0);
offsetY = relativeY - (obj.position.top as number);
} else {
offsetY = rect.height - relativeY - (obj.position.bottom as number);
}
if (activeProp2 === "left") {
offsetX =
relativeX -
(typeof obj.position.left === "number" ? obj.position.left : 0);
} else if (activeProp2 === "right") {
offsetX =
rect.width -
relativeX -
(typeof obj.position.right === "number" ? obj.position.right : 0);
offsetX = relativeX - (obj.position.left as number);
} else {
offsetX = rect.width - relativeX - (obj.position.right as number);
}
setDraggingIndex({ zone: zoneName, index });
setOffset([offsetY, offsetX]);
}
};
// Handle pointer move event
function handlePointerMove(event: React.PointerEvent) {
const handlePointerMove = (event: React.PointerEvent) => {
if (!draggingIndex || !offset) return;
const container = document.getElementById("real-time-vis-canvas");
@@ -84,91 +157,194 @@ const DroppedObjects: React.FC = () => {
const relativeX = event.clientX - rect.left;
const relativeY = event.clientY - rect.top;
// Determine which properties are active for the dragged object
const obj = zone.objects[draggingIndex.index];
const [activeProp1, activeProp2] = getActiveProperties(obj.position);
// Dynamically determine the current position strategy
const newPositionStrategy = determinePosition(rect, relativeX, relativeY);
const [activeProp1, activeProp2] = getActiveProperties(newPositionStrategy);
// Calculate the new position based on the active properties
let newX = 0;
// Update active edges for distance lines
const vertical = activeProp1 === "top" ? "top" : "bottom";
const horizontal = activeProp2 === "left" ? "left" : "right";
setActiveEdges({ vertical, horizontal });
// Calculate new position based on the active properties
let newY = 0;
if (activeProp2 === "left") {
newX = relativeX - offset[1];
} else if (activeProp2 === "right") {
newX = rect.width - (relativeX + offset[1]);
}
let newX = 0;
if (activeProp1 === "top") {
newY = relativeY - offset[0];
} else if (activeProp1 === "bottom") {
} else {
newY = rect.height - (relativeY + offset[0]);
}
// Ensure the object stays within the canvas boundaries
if (activeProp2 === "left") {
newX = relativeX - offset[1];
} else {
newX = rect.width - (relativeX + offset[1]);
}
// Apply boundaries
newX = Math.max(0, Math.min(rect.width - 50, newX));
newY = Math.max(0, Math.min(rect.height - 50, newY));
// Update the position reference
positionRef.current = [newY, newX];
// Create new position object
const newPosition = {
...newPositionStrategy,
[activeProp1]: newY,
[activeProp2]: newX,
// Clear opposite properties
[activeProp1 === "top" ? "bottom" : "top"]: "auto",
[activeProp2 === "left" ? "right" : "left"]: "auto",
};
// Update the current position state for DistanceLines
setCurrentPosition(newPosition);
// Update the object's position using requestAnimationFrame for smoother animations
if (!animationRef.current) {
animationRef.current = requestAnimationFrame(() => {
if (positionRef.current) {
updateObjectPosition(zoneName, draggingIndex.index, {
...obj.position,
[activeProp1]: positionRef.current[0],
[activeProp2]: positionRef.current[1],
});
}
updateObjectPosition(zoneName, draggingIndex.index, newPosition);
animationRef.current = null;
});
}
}
};
// Handle pointer up event
async function handlePointerUp(event: React.MouseEvent<HTMLDivElement>) {
const handlePointerUp = async (event: React.PointerEvent<HTMLDivElement>) => {
try {
if (!draggingIndex || !offset) return;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const container = document.getElementById("real-time-vis-canvas");
if (!container) throw new Error("Canvas container not found");
if (!container) return;
const rect = container.getBoundingClientRect();
const relativeX = event.clientX - rect.left;
const relativeY = event.clientY - rect.top;
// Recalculate the position using determinePosition
const newPosition = determinePosition(rect, relativeX, relativeY);
// Only now determine the final position strategy
const finalPosition = determinePosition(rect, relativeX, relativeY);
const [activeProp1, activeProp2] = getActiveProperties(finalPosition);
// Validate the dragging index and get the object
if (!zone.objects[draggingIndex.index]) {
throw new Error("Dragged object not found in the zone");
// Calculate final position using the new strategy
let finalY = 0;
let finalX = 0;
if (activeProp1 === "top") {
finalY = relativeY - offset[0];
} else {
finalY = rect.height - (relativeY + offset[0]);
}
const obj = { ...zone.objects[draggingIndex.index], position: newPosition };
let response = await addingFloatingWidgets(zone.zoneId, organization, obj);
if (activeProp2 === "left") {
finalX = relativeX - offset[1];
} else {
finalX = rect.width - (relativeX + offset[1]);
}
// Apply boundaries
finalX = Math.max(0, Math.min(rect.width - 50, finalX));
finalY = Math.max(0, Math.min(rect.height - 50, finalY));
const boundedPosition = {
...finalPosition,
[activeProp1]: finalY,
[activeProp2]: finalX,
};
// Save to backend
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const response = await addingFloatingWidgets(zone.zoneId, organization, {
...zone.objects[draggingIndex.index],
position: boundedPosition,
});
if (response.message === "Widget updated successfully") {
updateObjectPosition(zoneName, draggingIndex.index, newPosition);
updateObjectPosition(zoneName, draggingIndex.index, boundedPosition);
}
// Reset states
// Clean up
setDraggingIndex(null);
setOffset(null);
setActiveEdges(null); // Clear active edges
setCurrentPosition(null); // Reset current position
if (animationRef.current) {
cancelAnimationFrame(animationRef.current);
animationRef.current = null;
}
} catch (error) {
console.error("Error in handlePointerUp:", error);
}
}
};
const handleKebabClick = (id: string, event: React.MouseEvent) => {
event.stopPropagation();
setOpenKebabId((prevId) => (prevId === id ? null : id));
};
const renderObjectContent = (obj: any) => {
switch (obj.className) {
case "floating total-card":
return (
<>
<div className="header-wrapper">
<div className="header">{obj.header}</div>
<div className="data-values">
<div className="value">{obj.value}</div>
<div className="per">{obj.per}</div>
</div>
</div>
<div className="icon">
<WalletIcon />
</div>
</>
);
case "warehouseThroughput floating":
return (
<>
<div className="header">
<h2>Warehouse Throughput</h2>
<p>
<span>(+5) more</span> in 2025
</p>
</div>
<div className="lineGraph" style={{ height: "100%" }}>
{/* <Line data={lineGraphData} options={lineGraphOptions} /> */}
</div>
</>
);
case "fleetEfficiency floating":
return (
<>
<h2 className="header">Fleet Efficiency</h2>
<div className="progressContainer">
<div className="progress">
<div className="barOverflow">
<div
className="bar"
style={{ transform: `rotate(${obj.value}deg)` }}
></div>
</div>
</div>
</div>
<div className="scaleLabels">
<span>0%</span>
<div className="centerText">
<div className="percentage">{obj.per}%</div>
<div className="status">Optimal</div>
</div>
<span>100%</span>
</div>
</>
);
default:
return null;
}
};
return (
<div onPointerMove={handlePointerMove} onPointerUp={handlePointerUp}>
<div
onPointerMove={handlePointerMove}
onPointerUp={handlePointerUp}
className="floating-wrapper"
>
{zone.objects.map((obj, index) => (
<div
key={`${zoneName}-${index}`}
@@ -176,77 +352,104 @@ const DroppedObjects: React.FC = () => {
style={{
position: "absolute",
top:
typeof obj.position.top !== "string"
typeof obj.position.top === "number"
? `${obj.position.top}px`
: "auto",
left:
typeof obj.position.left !== "string"
typeof obj.position.left === "number"
? `${obj.position.left}px`
: "auto",
right:
typeof obj.position.right !== "string"
typeof obj.position.right === "number"
? `${obj.position.right}px`
: "auto",
bottom:
typeof obj.position.bottom !== "string"
typeof obj.position.bottom === "number"
? `${obj.position.bottom}px`
: "auto",
// transition: draggingIndex?.index === index ? "none" : "transform 0.1s ease-out",
}}
onPointerDown={(event) => handlePointerDown(event, index)}
onClick={() => {
setSelectedChartId(obj)
}}
>
{obj.className === "floating total-card" ? (
<>
<div className="header-wrapper">
<div className="header">{obj.header}</div>
<div className="data-values">
<div className="value">{obj.value}</div>
<div className="per">{obj.per}</div>
</div>
</div>
<div className="icon">
<WalletIcon />
</div>
<TotalCardComponent object={obj} />
</>
) : obj.className === "warehouseThroughput floating" ? (
<>
<div className="header">
<h2>Warehouse Throughput</h2>
<p>
<span>(+5) more</span> in 2025
</p>
</div>
<div className="lineGraph" style={{ height: "100%" }}>
{/* <Line data={lineGraphData} options={lineGraphOptions} /> */}
</div>
<WarehouseThroughputComponent />
</>
) : obj.className === "fleetEfficiency floating" ? (
<>
<h2 className="header">Fleet Efficiency</h2>
<div className="progressContainer">
<div className="progress">
<div className="barOverflow">
<div
className="bar"
style={{ transform: `rotate(${obj.value}deg)` }}
></div>
</div>
</div>
</div>
<div className="scaleLabels">
<span>0%</span>
<div className="centerText">
<div className="percentage">{obj.per}%</div>
<div className="status">Optimal</div>
</div>
<span>100%</span>
</div>
<FleetEfficiencyComponent object={obj} />
</>
) : null}
{renderObjectContent(obj)}
<div
className="icon kebab"
onClick={(event) => handleKebabClick(obj.id, event)}
>
<KebabIcon />
</div>
{openKebabId === obj.id && (
<div className="kebab-options">
<div className="dublicate btn" onClick={(event) => {
event.stopPropagation();
handleDuplicate(zoneName, index); // Call the duplicate handler
}}>
<div className="icon">
<DublicateIcon />
</div>
<div className="label">Duplicate</div>
</div>
<div className="edit btn" onClick={(event) => {
event.stopPropagation();
handleDelete(zoneName, obj.id, index); // Call the delete handler
}}>
<div className="icon">
<DeleteIcon />
</div>
<div className="label">Delete</div>
</div>
</div>
)}
</div>
))}
{/* Render DistanceLines component during drag */}
{draggingIndex !== null &&
activeEdges !== null &&
currentPosition !== null && (
<DistanceLines
obj={{
position: {
top:
currentPosition.top !== "auto"
? currentPosition.top
: undefined,
bottom:
currentPosition.bottom !== "auto"
? currentPosition.bottom
: undefined,
left:
currentPosition.left !== "auto"
? currentPosition.left
: undefined,
right:
currentPosition.right !== "auto"
? currentPosition.right
: undefined,
},
}}
activeEdges={activeEdges}
/>
)}
</div>
);
};
export default DroppedObjects;

View File

@@ -63,6 +63,8 @@ const RealTimeVisulization: React.FC = () => {
const organization = email?.split("@")[1]?.split(".")[0];
try {
const response = await getZone2dData(organization);
console.log('response: ', response);
if (!Array.isArray(response)) {
return;
}
@@ -83,7 +85,7 @@ const RealTimeVisulization: React.FC = () => {
);
setZonesData(formattedData);
} catch (error) {
console.log("error: ", error);
}
}
@@ -109,7 +111,7 @@ const RealTimeVisulization: React.FC = () => {
});
}, [selectedZone]);
useEffect(() => {}, [floatingWidgets]);
// useEffect(() => {}, [floatingWidgets]);
const handleDrop = async (event: React.DragEvent<HTMLDivElement>) => {
try {
@@ -135,6 +137,7 @@ const RealTimeVisulization: React.FC = () => {
id: generateUniqueId(),
position: determinePosition(canvasRect, relativeX, relativeY),
};
console.log('newObject: ', newObject);
let response = await addingFloatingWidgets(
selectedZone.zoneId,
@@ -171,7 +174,7 @@ const RealTimeVisulization: React.FC = () => {
],
},
}));
} catch (error) {}
} catch (error) { }
};
return (
@@ -198,7 +201,8 @@ const RealTimeVisulization: React.FC = () => {
>
<Scene />
</div>
<DroppedObjects />
{activeModule === "visualization" && selectedZone.zoneName !== "" && <DroppedObjects />}
{/* <DroppedObjects /> */}
{activeModule === "visualization" && (
<>
<DisplayZone

View File

@@ -1,3 +1,70 @@
// export function determinePosition(
// canvasRect: DOMRect,
// relativeX: number,
// relativeY: number
// ): {
// top: number | "auto";
// left: number | "auto";
// right: number | "auto";
// bottom: number | "auto";
// } {
// // Calculate the midpoints of the canvas
// const centerX = canvasRect.width / 2;
// const centerY = canvasRect.height / 2;
// // Initialize position with default values
// let position: {
// top: number | "auto";
// left: number | "auto";
// right: number | "auto";
// bottom: number | "auto";
// };
// if (relativeY < centerY) {
// // Top half
// if (relativeX < centerX) {
// // Left side
// position = {
// top: relativeY,
// left: relativeX,
// right: "auto",
// bottom: "auto",
// };
// } else {
// // Right side
// position = {
// top: relativeY,
// right: canvasRect.width - relativeX,
// left: "auto",
// bottom: "auto",
// };
// }
// } else {
// // Bottom half
// if (relativeX < centerX) {
// // Left side
// position = {
// bottom: canvasRect.height - relativeY,
// left: relativeX,
// right: "auto",
// top: "auto",
// };
// } else {
// // Right side
// position = {
// bottom: canvasRect.height - relativeY,
// right: canvasRect.width - relativeX,
// left: "auto",
// top: "auto",
// };
// }
// }
// return position;
// }
export function determinePosition(
canvasRect: DOMRect,
relativeX: number,
@@ -8,11 +75,9 @@ export function determinePosition(
right: number | "auto";
bottom: number | "auto";
} {
// Calculate the midpoints of the canvas
const centerX = canvasRect.width / 2;
const centerY = canvasRect.height / 2;
// Initialize position with default values
let position: {
top: number | "auto";
left: number | "auto";
@@ -21,9 +86,8 @@ export function determinePosition(
};
if (relativeY < centerY) {
// Top half
if (relativeX < centerX) {
// Left side
console.log("Top-left");
position = {
top: relativeY,
left: relativeX,
@@ -31,7 +95,7 @@ export function determinePosition(
bottom: "auto",
};
} else {
// Right side
console.log("Top-right");
position = {
top: relativeY,
right: canvasRect.width - relativeX,
@@ -40,9 +104,8 @@ export function determinePosition(
};
}
} else {
// Bottom half
if (relativeX < centerX) {
// Left side
console.log("Bottom-left");
position = {
bottom: canvasRect.height - relativeY,
left: relativeX,
@@ -50,7 +113,7 @@ export function determinePosition(
top: "auto",
};
} else {
// Right side
console.log("Bottom-right");
position = {
bottom: canvasRect.height - relativeY,
right: canvasRect.width - relativeX,
@@ -61,4 +124,4 @@ export function determinePosition(
}
return position;
}
}

View File

@@ -1,17 +1,11 @@
export const getActiveProperties = (position: {
top: number | "auto";
left: number | "auto";
right: number | "auto";
bottom: number | "auto";
}) => {
let activeProps: ["top", "left"] | ["bottom", "right"] = ["top", "left"]; // Default to top-left
if (
typeof position.bottom !== "string" &&
typeof position.right !== "string"
) {
activeProps = ["bottom", "right"];
export function getActiveProperties(position: any): [string, string] {
if (position.top !== "auto" && position.left !== "auto") {
return ["top", "left"]; // Top-left
} else if (position.top !== "auto" && position.right !== "auto") {
return ["top", "right"]; // Top-right
} else if (position.bottom !== "auto" && position.left !== "auto") {
return ["bottom", "left"]; // Bottom-left
} else {
return ["bottom", "right"]; // Bottom-right
}
return activeProps;
};
}

View File

@@ -0,0 +1,29 @@
// import { useSelectedZoneStore } from "../../../store/useZoneStore";
// type HandleDropTemplateProps = {
// templateId: string;
// };
// export const handleDropTemplate = ({ templateId }: HandleDropTemplateProps): void => {
// const { getTemplate } = useTemplateStore.getState();
// const { setSelectedZone } = useSelectedZoneStore.getState();
// // Find the template by ID
// const template: Template | undefined = getTemplate(templateId);
// if (!template) {
// console.error("Template not found!");
// return;
// }
// // Update the selected zone with the template data
// setSelectedZone((prev) => ({
// ...prev,
// panelOrder: template.panelOrder,
// activeSides: Array.from(new Set([...prev.activeSides, ...template.panelOrder])),
// widgets: template.widgets, // Keep widget structure the same
// }));
// console.log("Dropped template applied:", template);
// };

View File

@@ -1,6 +1,12 @@
import React, { useState } from "react";
import { ArrowIcon } from "../../icons/ExportCommonIcons";
import { toggleTheme } from "../../../utils/theme";
const MenuBar = () => {
interface MenuBarProps {
setOpenMenu: (isOpen: boolean) => void; // Function to update menu state
}
const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
const [activeMenu, setActiveMenu] = useState<string | null>(null);
const [activeSubMenu, setActiveSubMenu] = useState<string | null>(null);
@@ -17,8 +23,20 @@ const MenuBar = () => {
}));
};
function handleThemeChange(){
toggleTheme();
window.location.reload();
}
const savedTheme: string | null = localStorage.getItem("theme") || "light";
return (
<div className="menu-bar">
<div
className="menu-bar"
onPointerLeave={() => {
setOpenMenu(false);
}}
>
{/* Top-level menu buttons */}
<div className="menu-buttons">
{/* File Menu */}
@@ -32,7 +50,9 @@ const MenuBar = () => {
>
<div className="menu-button">
File
<span className="dropdown-icon"></span>
<span className="dropdown-icon">
<ArrowIcon />
</span>
</div>
{/* File Dropdown */}
@@ -44,10 +64,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("New File")}
>
<div className="menu-item">
<span>
{selectedItems["New File"] && "✓ "}
New File
</span>
<span>New File</span>
<div className="menu-item-right">
<span className="shortcut">Ctrl + N</span>
</div>
@@ -60,10 +77,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Open Local File")}
>
<div className="menu-item">
<span>
{selectedItems["Open Local File"] && "✓ "}
Open Local File
</span>
<span>Open Local File</span>
<div className="menu-item-right">
<span className="shortcut">Ctrl + O</span>
</div>
@@ -76,10 +90,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Save Version")}
>
<div className="menu-item">
<span>
{selectedItems["Save Version"] && "✓ "}
Save Version
</span>
<span>Save Version</span>
</div>
<div className="split"></div>
</div>
@@ -90,10 +101,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Make a Copy")}
>
<div className="menu-item">
<span>
{selectedItems["Make a Copy"] && "✓ "}
Make a Copy
</span>
<span>Make a Copy</span>
</div>
</div>
@@ -103,10 +111,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Share")}
>
<div className="menu-item">
<span>
{selectedItems["Share"] && "✓ "}
Share
</span>
<span>Share</span>
</div>
</div>
@@ -116,10 +121,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Rename")}
>
<div className="menu-item">
<span>
{selectedItems["Rename"] && "✓ "}
Rename
</span>
<span>Rename</span>
</div>
<div className="split"></div>
</div>
@@ -130,10 +132,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Import")}
>
<div className="menu-item">
<span>
{selectedItems["Import"] && "✓ "}
Import
</span>
<span>Import</span>
</div>
</div>
@@ -143,10 +142,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Close File")}
>
<div className="menu-item">
<span>
{selectedItems["Close File"] && "✓ "}
Close File
</span>
<span>Close File</span>
</div>
</div>
</div>
@@ -164,7 +160,9 @@ const MenuBar = () => {
>
<div className="menu-button">
Edit
<span className="dropdown-icon"></span>
<span className="dropdown-icon">
<ArrowIcon />
</span>
</div>
{/* Edit Dropdown */}
@@ -176,10 +174,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Undo")}
>
<div className="menu-item">
<span>
{selectedItems["Undo"] && "✓ "}
Undo
</span>
<span>Undo</span>
<div className="menu-item-right">
<span className="shortcut">Ctrl + Z</span>
</div>
@@ -192,10 +187,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Redo")}
>
<div className="menu-item">
<span>
{selectedItems["Redo"] && "✓ "}
Redo
</span>
<span>Redo</span>
<div className="menu-item-right">
<span className="shortcut">Ctrl + Shift + Z</span>
</div>
@@ -209,10 +201,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Undo History")}
>
<div className="menu-item">
<span>
{selectedItems["Undo History"] && "✓ "}
Undo History
</span>
<span>Undo History</span>
</div>
</div>
@@ -222,10 +211,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Redo History")}
>
<div className="menu-item">
<span>
{selectedItems["Redo History"] && "✓ "}
Redo History
</span>
<span>Redo History</span>
</div>
<div className="split"></div>
</div>
@@ -236,10 +222,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Find")}
>
<div className="menu-item">
<span>
{selectedItems["Find"] && "✓ "}
Find
</span>
<span>Find</span>
<div className="menu-item-right">
<span className="shortcut">Ctrl + F</span>
</div>
@@ -252,10 +235,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Delete")}
>
<div className="menu-item">
<span>
{selectedItems["Delete"] && "✓ "}
Delete
</span>
<span>Delete</span>
</div>
</div>
@@ -265,10 +245,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Select by...")}
>
<div className="menu-item">
<span>
{selectedItems["Select by..."] && "✓ "}
Select by...
</span>
<span>Select by...</span>
</div>
</div>
@@ -278,10 +255,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Keymap")}
>
<div className="menu-item">
<span>
{selectedItems["Keymap"] && "✓ "}
Keymap
</span>
<span>Keymap</span>
</div>
</div>
</div>
@@ -299,7 +273,9 @@ const MenuBar = () => {
>
<div className="menu-button">
View
<span className="dropdown-icon"></span>
<span className="dropdown-icon">
<ArrowIcon />
</span>
</div>
{/* View Dropdown */}
@@ -311,10 +287,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Grid")}
>
<div className="menu-item">
<span>
{selectedItems["Grid"] && "✓ "}
Grid
</span>
<span>Grid</span>
</div>
</div>
@@ -325,11 +298,10 @@ const MenuBar = () => {
onMouseLeave={() => setActiveSubMenu(null)}
>
<div className="menu-item">
<span>
{selectedItems["Gizmo"] && "✓ "}
Gizmo
<span>Gizmo</span>
<span className="dropdown-icon">
<ArrowIcon />
</span>
<span className="icon"></span>
</div>
<div className="split"></div>
@@ -346,16 +318,14 @@ const MenuBar = () => {
Visibility
</span>
</div>
<div className="split"></div>
{/* Cube view */}
<div
className="submenu-item"
onClick={() => toggleSelection("Cube view")}
>
<span>
{selectedItems["Cube view"] && "✓ "}
Cube view
</span>
<span>Cube view</span>
</div>
{/* Sphere view */}
@@ -363,21 +333,7 @@ const MenuBar = () => {
className="submenu-item"
onClick={() => toggleSelection("Sphere view")}
>
<span>
{selectedItems["Sphere view"] && "✓ "}
Sphere view
</span>
</div>
{/* Custom settings */}
<div
className="submenu-item"
onClick={() => toggleSelection("Custom settings")}
>
<span>
{selectedItems["Custom settings"] && "✓ "}
Custom settings
</span>
<span>Sphere view</span>
</div>
</div>
)}
@@ -389,10 +345,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Zoom")}
>
<div className="menu-item">
<span>
{selectedItems["Zoom"] && "✓ "}
Zoom
</span>
<span>Zoom</span>
</div>
</div>
@@ -402,10 +355,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Full Screen")}
>
<div className="menu-item">
<span>
{selectedItems["Full Screen"] && "✓ "}
Full Screen
</span>
<span>Full Screen</span>
<div className="menu-item-right">
<span className="shortcut">F11</span>
</div>
@@ -424,11 +374,7 @@ const MenuBar = () => {
setActiveSubMenu(null);
}}
>
<div className="menu-button">
Version history
</div>
<div className="menu-button">Version history</div>
</div>
{/* Export As Menu */}
@@ -440,14 +386,27 @@ const MenuBar = () => {
setActiveSubMenu(null);
}}
>
<div className="menu-button">
Export as...
</div>
<div className="menu-button">Export as...</div>
</div>
<div
className="menu-button-container"
onMouseEnter={() => setActiveMenu("theme")}
onMouseLeave={() => {
setActiveMenu(null);
setActiveSubMenu(null);
}}
onClick={() => {
handleThemeChange();
}}
>
<div className="menu-button">
Theme <div className="value">{savedTheme}</div>
</div>
</div>
{/* Apps Menu */}
<div
{/* <div
className="menu-button-container"
onMouseEnter={() => setActiveMenu("Apps")}
onMouseLeave={() => {
@@ -457,68 +416,64 @@ const MenuBar = () => {
>
<div className="menu-button">
Apps
<span className="dropdown-icon"></span>
<span className="dropdown-icon">
<ArrowIcon />
</span>
</div>
{/* Apps Dropdown */}
{activeMenu === "Apps" && (
<div className="dropdown-menu">
{/* New App */}
<div
className="menu-item-container"
onClick={() => toggleSelection("New App")}
>
<div className="menu-item">
<span>
{selectedItems["New App"] && "✓ "}
New App
</span>
</div>
<div className="split"></div>
</div>
{/* Work-flow Monitor */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Work-flow Monitor")}
>
<div className="menu-item">
<span>
{selectedItems["Work-flow Monitor"] && "✓ "}
Work-flow Monitor
</span>
</div>
</div>
{/* Temperature Visualizer */}
<div
className="menu-item-container"
onClick={() => toggleSelection("Temperature Visualizer")}
>
<div className="menu-item">
<span>
{selectedItems["Temperature Visualizer"] && "✓ "}
Temperature Visualizer
</span>
</div>
</div>
{/* View all */}
<div
className="menu-item-container"
onClick={() => toggleSelection("View all")}
>
<div className="menu-item">
<span>
{selectedItems["View all"] && "✓ "}
View all
</span>
</div>
</div>
</div>
)}
</div>
</div> */}
{/* Help Menu */}
<div
@@ -531,7 +486,9 @@ const MenuBar = () => {
>
<div className="menu-button">
Help
<span className="dropdown-icon"></span>
<span className="dropdown-icon">
<ArrowIcon />
</span>
</div>
{/* Help Dropdown */}
@@ -543,10 +500,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Shortcuts")}
>
<div className="menu-item">
<span>
{selectedItems["Shortcuts"] && "✓ "}
Shortcuts
</span>
<span>Shortcuts</span>
<div className="menu-item-right">
<span className="shortcut">Ctrl + Shift + ?</span>
</div>
@@ -559,10 +513,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Manual")}
>
<div className="menu-item">
<span>
{selectedItems["Manual"] && "✓ "}
Manual
</span>
<span>Manual</span>
</div>
</div>
@@ -572,10 +523,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Video Tutorials")}
>
<div className="menu-item">
<span>
{selectedItems["Video Tutorials"] && "✓ "}
Video Tutorials
</span>
<span>Video Tutorials</span>
</div>
</div>
@@ -585,10 +533,7 @@ const MenuBar = () => {
onClick={() => toggleSelection("Report a bug")}
>
<div className="menu-item">
<span>
{selectedItems["Report a bug"] && "✓ "}
Report a bug
</span>
<span>Report a bug</span>
</div>
</div>
</div>
@@ -600,5 +545,3 @@ const MenuBar = () => {
};
export default MenuBar;

View File

@@ -211,9 +211,10 @@ const BarGraphComponent = ({
fontWeight = "Regular",
}: ChartComponentProps) => {
const { themeColor } = useThemeStore();
const { measurements: chartMeasurements, duration: chartDuration } = useChartStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState<any>({});
const [duration, setDuration] = useState("1h")
const [name, setName] = useState("Widget")
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
labels: [],
datasets: [],
@@ -236,6 +237,10 @@ const BarGraphComponent = ({
],
};
useEffect(() => {
console.log("titleeeeeeeeeeeeeeeeeee",title);
},[])
// Memoize Theme Colors
const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
@@ -270,7 +275,7 @@ const BarGraphComponent = ({
plugins: {
title: {
display: true,
text: title,
text: name,
font: chartFontStyle,
},
legend: {
@@ -285,7 +290,7 @@ const BarGraphComponent = ({
},
},
}),
[title, chartFontStyle]
[title, chartFontStyle, name]
);
// useEffect(() => {console.log(measurements);
@@ -304,15 +309,12 @@ const BarGraphComponent = ({
const startStream = () => {
console.log("inputtttttttttt",inputData);
socket.emit("lineInput", inputData);
};
socket.on("connect", startStream);
socket.on("lineOutput", (response) => {
console.log("responce dataaaaaaaaa",response.data);
const responseData = response.data;
// Extract timestamps and values
@@ -347,6 +349,7 @@ const BarGraphComponent = ({
if (response.status === 200) {
setmeasurements(response.data.Data.measurements)
setDuration(response.data.Data.duration)
setName(response.data.widgetName)
} else {
console.log("Unexpected response:", response);
}
@@ -365,7 +368,7 @@ const BarGraphComponent = ({
fetchSavedInputes();
}
}
,[chartMeasurements, chartDuration])
,[chartMeasurements, chartDuration, widgetName])
return <Bar data={Object.keys(measurements).length > 0 ? chartData : defaultData} options={options} />;
};

View File

@@ -1,22 +1,64 @@
import { useMemo } from "react";
import { Doughnut, Line } from "react-chartjs-2";
import React, { useEffect, useMemo, useState } from "react";
import { Doughnut } from "react-chartjs-2";
import io from "socket.io-client";
import { useThemeStore } from "../../../../store/useThemeStore";
import useChartStore from "../../../../store/useChartStore";
import { useWidgetStore } from "../../../../store/useWidgetStore";
import axios from "axios";
interface ChartComponentProps {
id: string;
type: any;
title: string;
fontFamily?: string;
fontSize?: string;
fontWeight?: "Light" | "Regular" | "Bold";
data: any;
}
const DoughnutGraphComponent = ({
id,
type,
title,
fontFamily,
fontSize,
fontWeight = "Regular",
}: ChartComponentProps) => {
// Memoize Font Weight Mapping
const { themeColor } = useThemeStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState<any>({});
const [duration, setDuration] = useState("1h")
const [name, setName] = useState("Widget")
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
labels: [],
datasets: [],
});
const { selectedChartId } = useWidgetStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]
const defaultData = {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [
{
label: "Dataset",
data: [12, 19, 3, 5, 2, 3],
backgroundColor: ["#6f42c1"],
borderColor: "#b392f0",
borderWidth: 1,
},
],
};
useEffect(() => {
console.log("titleeeeeeeeeeeeeeeeeee",title);
},[])
// Memoize Theme Colors
const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
// Memoize Font Styling
const chartFontWeightMap = useMemo(
() => ({
Light: "lighter" as const,
@@ -26,19 +68,9 @@ const DoughnutGraphComponent = ({
[]
);
// Parse and Memoize Font Size
const fontSizeValue = useMemo(
() => (fontSize ? parseInt(fontSize) : 12),
[fontSize]
);
const fontSizeValue = useMemo(() => (fontSize ? parseInt(fontSize) : 12), [fontSize]);
const fontWeightValue = useMemo(() => chartFontWeightMap[fontWeight], [fontWeight, chartFontWeightMap]);
// Determine and Memoize Font Weight
const fontWeightValue = useMemo(
() => chartFontWeightMap[fontWeight],
[fontWeight, chartFontWeightMap]
);
// Memoize Chart Font Style
const chartFontStyle = useMemo(
() => ({
family: fontFamily || "Arial",
@@ -48,46 +80,110 @@ const DoughnutGraphComponent = ({
[fontFamily, fontSizeValue, fontWeightValue]
);
const options = useMemo(
() => ({
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: title,
font: chartFontStyle,
},
legend: {
display: false,
},
},
scales: {
x: {
ticks: {
display: false, // This hides the x-axis labels
// Memoize Chart Options
const options = useMemo(
() => ({
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: name,
font: chartFontStyle,
},
legend: {
display: false,
},
},
},
}),
[title, chartFontStyle]
);
scales: {
// x: {
// ticks: {
// display: true, // This hides the x-axis labels
// },
// },
},
}),
[title, chartFontStyle, name]
);
const chartData = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
label: "My First Dataset",
data: [65, 59, 80, 81, 56, 55, 40],
backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple)
borderColor: "#ffffff", // Keeping border color white
borderWidth: 2,
fill: false,
},
],
};
// useEffect(() => {console.log(measurements);
// },[measurements])
return <Doughnut data={chartData} options={options} />;
useEffect(() => {
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
const socket = io(`http://${iotApiUrl}`);
const inputData = {
measurements,
duration,
interval: 1000,
};
const startStream = () => {
socket.emit("lineInput", inputData);
};
socket.on("connect", startStream);
socket.on("lineOutput", (response) => {
const responseData = response.data;
// Extract timestamps and values
const labels = responseData.time;
const datasets = Object.keys(measurements).map((key) => {
const measurement = measurements[key];
const datasetKey = `${measurement.name}.${measurement.fields}`;
return {
label: datasetKey,
data: responseData[datasetKey]?.values ?? [],
backgroundColor: "#6f42c1",
borderColor: "#b392f0",
borderWidth: 1,
};
});
setChartData({ labels, datasets });
});
return () => {
socket.off("lineOutput");
socket.emit("stop_stream"); // Stop streaming when component unmounts
socket.disconnect();
};
}, [measurements, duration, iotApiUrl]);
const fetchSavedInputes = async() => {
if (id !== "") {
try {
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${id}/${organization}`);
if (response.status === 200) {
setmeasurements(response.data.Data.measurements)
setDuration(response.data.Data.duration)
setName(response.data.widgetName)
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
console.error("There was an error!", error);
}
}
}
useEffect(() => {
fetchSavedInputes();
}, []);
useEffect(() => {
if (selectedChartId?.id === id) {
fetchSavedInputes();
}
}
,[chartMeasurements, chartDuration, widgetName])
return <Doughnut data={Object.keys(measurements).length > 0 ? chartData : defaultData} options={options} />;
};
export default DoughnutGraphComponent;
export default DoughnutGraphComponent;

View File

@@ -24,9 +24,10 @@ const LineGraphComponent = ({
fontWeight = "Regular",
}: ChartComponentProps) => {
const { themeColor } = useThemeStore();
const { measurements: chartMeasurements, duration: chartDuration } = useChartStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState<any>({});
const [duration, setDuration] = useState("1h")
const [name, setName] = useState("Widget")
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
labels: [],
datasets: [],
@@ -49,6 +50,10 @@ const LineGraphComponent = ({
],
};
useEffect(() => {
console.log("titleeeeeeeeeeeeeeeeeee",title);
},[])
// Memoize Theme Colors
const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
@@ -83,7 +88,7 @@ const LineGraphComponent = ({
plugins: {
title: {
display: true,
text: title,
text: name,
font: chartFontStyle,
},
legend: {
@@ -98,7 +103,7 @@ const LineGraphComponent = ({
},
},
}),
[title, chartFontStyle]
[title, chartFontStyle, name]
);
// useEffect(() => {console.log(measurements);
@@ -157,6 +162,7 @@ const LineGraphComponent = ({
if (response.status === 200) {
setmeasurements(response.data.Data.measurements)
setDuration(response.data.Data.duration)
setName(response.data.widgetName)
} else {
console.log("Unexpected response:", response);
}
@@ -175,7 +181,7 @@ const LineGraphComponent = ({
fetchSavedInputes();
}
}
,[chartMeasurements, chartDuration])
,[chartMeasurements, chartDuration, widgetName])
return <Line data={Object.keys(measurements).length > 0 ? chartData : defaultData} options={options} />;
};

View File

@@ -210,9 +210,10 @@ const PieChartComponent = ({
fontWeight = "Regular",
}: ChartComponentProps) => {
const { themeColor } = useThemeStore();
const { measurements: chartMeasurements, duration: chartDuration } = useChartStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState<any>({});
const [duration, setDuration] = useState("1h")
const [name, setName] = useState("Widget")
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
labels: [],
datasets: [],
@@ -235,6 +236,10 @@ const PieChartComponent = ({
],
};
useEffect(() => {
console.log("titleeeeeeeeeeeeeeeeeee",title);
},[])
// Memoize Theme Colors
const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
@@ -269,7 +274,7 @@ const PieChartComponent = ({
plugins: {
title: {
display: true,
text: title,
text: name,
font: chartFontStyle,
},
legend: {
@@ -284,7 +289,7 @@ const PieChartComponent = ({
// },
},
}),
[title, chartFontStyle]
[title, chartFontStyle, name]
);
// useEffect(() => {console.log(measurements);
@@ -343,6 +348,7 @@ const PieChartComponent = ({
if (response.status === 200) {
setmeasurements(response.data.Data.measurements)
setDuration(response.data.Data.duration)
setName(response.data.widgetName)
} else {
console.log("Unexpected response:", response);
}
@@ -361,7 +367,7 @@ const PieChartComponent = ({
fetchSavedInputes();
}
}
,[chartMeasurements, chartDuration])
,[chartMeasurements, chartDuration, widgetName])
return <Pie data={Object.keys(measurements).length > 0 ? chartData : defaultData} options={options} />;
};

View File

@@ -1,22 +1,64 @@
import { useMemo } from "react";
import { Line, PolarArea } from "react-chartjs-2";
import React, { useEffect, useMemo, useState } from "react";
import { PolarArea } from "react-chartjs-2";
import io from "socket.io-client";
import { useThemeStore } from "../../../../store/useThemeStore";
import useChartStore from "../../../../store/useChartStore";
import { useWidgetStore } from "../../../../store/useWidgetStore";
import axios from "axios";
interface ChartComponentProps {
id: string;
type: any;
title: string;
fontFamily?: string;
fontSize?: string;
fontWeight?: "Light" | "Regular" | "Bold";
data: any;
}
const PolarAreaGraphComponent = ({
id,
type,
title,
fontFamily,
fontSize,
fontWeight = "Regular",
}: ChartComponentProps) => {
// Memoize Font Weight Mapping
const { themeColor } = useThemeStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState<any>({});
const [duration, setDuration] = useState("1h")
const [name, setName] = useState("Widget")
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
labels: [],
datasets: [],
});
const { selectedChartId } = useWidgetStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]
const defaultData = {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [
{
label: "Dataset",
data: [12, 19, 3, 5, 2, 3],
backgroundColor: ["#6f42c1"],
borderColor: "#b392f0",
borderWidth: 1,
},
],
};
useEffect(() => {
console.log("titleeeeeeeeeeeeeeeeeee",title);
},[])
// Memoize Theme Colors
const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
// Memoize Font Styling
const chartFontWeightMap = useMemo(
() => ({
Light: "lighter" as const,
@@ -26,19 +68,9 @@ const PolarAreaGraphComponent = ({
[]
);
// Parse and Memoize Font Size
const fontSizeValue = useMemo(
() => (fontSize ? parseInt(fontSize) : 12),
[fontSize]
);
const fontSizeValue = useMemo(() => (fontSize ? parseInt(fontSize) : 12), [fontSize]);
const fontWeightValue = useMemo(() => chartFontWeightMap[fontWeight], [fontWeight, chartFontWeightMap]);
// Determine and Memoize Font Weight
const fontWeightValue = useMemo(
() => chartFontWeightMap[fontWeight],
[fontWeight, chartFontWeightMap]
);
// Memoize Chart Font Style
const chartFontStyle = useMemo(
() => ({
family: fontFamily || "Arial",
@@ -48,46 +80,110 @@ const PolarAreaGraphComponent = ({
[fontFamily, fontSizeValue, fontWeightValue]
);
const options = useMemo(
() => ({
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: title,
font: chartFontStyle,
},
legend: {
display: false,
},
},
scales: {
x: {
ticks: {
display: false, // This hides the x-axis labels
// Memoize Chart Options
const options = useMemo(
() => ({
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: name,
font: chartFontStyle,
},
legend: {
display: false,
},
},
},
}),
[title, chartFontStyle]
);
scales: {
// x: {
// ticks: {
// display: true, // This hides the x-axis labels
// },
// },
},
}),
[title, chartFontStyle, name]
);
const chartData = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
label: "My First Dataset",
data: [65, 59, 80, 81, 56, 55, 40],
backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple)
borderColor: "#ffffff", // Keeping border color white
borderWidth: 2,
fill: false,
},
],
};
// useEffect(() => {console.log(measurements);
// },[measurements])
return <PolarArea data={chartData} options={options} />;
useEffect(() => {
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
const socket = io(`http://${iotApiUrl}`);
const inputData = {
measurements,
duration,
interval: 1000,
};
const startStream = () => {
socket.emit("lineInput", inputData);
};
socket.on("connect", startStream);
socket.on("lineOutput", (response) => {
const responseData = response.data;
// Extract timestamps and values
const labels = responseData.time;
const datasets = Object.keys(measurements).map((key) => {
const measurement = measurements[key];
const datasetKey = `${measurement.name}.${measurement.fields}`;
return {
label: datasetKey,
data: responseData[datasetKey]?.values ?? [],
backgroundColor: "#6f42c1",
borderColor: "#b392f0",
borderWidth: 1,
};
});
setChartData({ labels, datasets });
});
return () => {
socket.off("lineOutput");
socket.emit("stop_stream"); // Stop streaming when component unmounts
socket.disconnect();
};
}, [measurements, duration, iotApiUrl]);
const fetchSavedInputes = async() => {
if (id !== "") {
try {
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${id}/${organization}`);
if (response.status === 200) {
setmeasurements(response.data.Data.measurements)
setDuration(response.data.Data.duration)
setName(response.data.widgetName)
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
console.error("There was an error!", error);
}
}
}
useEffect(() => {
fetchSavedInputes();
}, []);
useEffect(() => {
if (selectedChartId?.id === id) {
fetchSavedInputes();
}
}
,[chartMeasurements, chartDuration, widgetName])
return <PolarArea data={Object.keys(measurements).length > 0 ? chartData : defaultData} options={options} />;
};
export default PolarAreaGraphComponent;
export default PolarAreaGraphComponent;

View File

@@ -0,0 +1,33 @@
import React from 'react'
type Props = {}
const FleetEfficiencyComponent = ({
object
}: any) => {
return (
<>
<h2 className="header">Fleet Efficiency</h2>
<div className="progressContainer">
<div className="progress">
<div className="barOverflow">
<div
className="bar"
style={{ transform: `rotate(${object.value}deg)` }}
></div>
</div>
</div>
</div>
<div className="scaleLabels">
<span>0%</span>
<div className="centerText">
<div className="percentage">{object.per}%</div>
<div className="status">Optimal</div>
</div>
<span>100%</span>
</div>
</>
)
}
export default FleetEfficiencyComponent

View File

@@ -0,0 +1,29 @@
import React from 'react'
import { WalletIcon } from '../../../icons/3dChartIcons'
import { useWidgetStore } from '../../../../store/useWidgetStore';
const TotalCardComponent = ({
object
}: any) => {
const { setSelectedChartId } =
useWidgetStore();
return (
<>
<div className="header-wrapper" onClick={() => {
setSelectedChartId(object.id)
}}>
<div className="header">{object.header}</div>
<div className="data-values">
<div className="value">{object.value}</div>
<div className="per">{object.per}</div>
</div>
</div>
<div className="icon">
<WalletIcon />
</div>
</>
)
}
export default TotalCardComponent

View File

@@ -0,0 +1,132 @@
import React, { useState } from 'react'
import { Line } from 'react-chartjs-2'
import axios from 'axios';
const WarehouseThroughputComponent = ({
object
}: any) => {
const [measurements, setmeasurements] = useState<any>({});
const [duration, setDuration] = useState("1h")
const lineGraphData = {
labels: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
], // Months of the year
datasets: [
{
label: "Throughput (units/month)",
data: [500, 400, 300, 450, 350, 250, 200, 300, 250, 150, 100, 150], // Example monthly data
borderColor: "#6f42c1", // Use the desired color for the line (purple)
backgroundColor: "rgba(111, 66, 193, 0.2)", // Use a semi-transparent purple for the fill
borderWidth: 2, // Line thickness
fill: true, // Enable fill for this dataset
pointRadius: 0, // Remove dots at each data point
tension: 0.5, // Smooth interpolation for the line
},
],
};
// Line graph options
const lineGraphOptions = {
responsive: true,
maintainAspectRatio: false, // Allow custom height/width adjustments
plugins: {
legend: {
display: false, // Hide legend
},
title: {
display: false, // No chart title needed
},
tooltip: {
callbacks: {
label: (context: any) => {
const value = context.parsed.y;
return `${value} units`; // Customize tooltip to display "units"
},
},
},
},
scales: {
x: {
grid: {
display: false, // Hide x-axis grid lines
},
ticks: {
maxRotation: 0, // Prevent label rotation
autoSkip: false, // Display all months
font: {
size: 8, // Adjust font size for readability
color: "#ffffff", // Light text color for labels
},
},
},
y: {
display: true, // Show y-axis
grid: {
drawBorder: false, // Remove border line
color: "rgba(255, 255, 255, 0.2)", // Light gray color for grid lines
borderDash: [5, 5], // Dotted line style (array defines dash and gap lengths)
},
ticks: {
font: {
size: 8, // Adjust font size for readability
color: "#ffffff", // Light text color for ticks
},
},
},
},
elements: {
line: {
tension: 0.5, // Smooth interpolation for the line
},
},
};
// const fetchSavedInputes = async() => {
// if (object.id !== "") {
// try {
// const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}/api/v2/WidgetData/${id}/${organization}`);
// if (response.status === 200) {
// setmeasurements(response.data.Data.measurements)
// setDuration(response.data.Data.duration)
// setName(response.data.widgetName)
// } else {
// console.log("Unexpected response:", response);
// }
// } catch (error) {
// console.error("There was an error!", error);
// }
// }
// }
return (
<>
<div className="header">
<h2>Warehouse Throughput</h2>
<p>
<span>(+5) more</span> in 2025
</p>
</div>
<div className="lineGraph" style={{ height: "100%" }}>
<Line data={lineGraphData} options={lineGraphOptions} />
</div>
</>
)
}
export default WarehouseThroughputComponent