Update styles, add marketplace components, and enhance drag-and-drop functionality

This commit is contained in:
Jerald-Golden-B 2025-03-27 15:14:29 +05:30
parent a7ec4720a4
commit 3de7eedb80
51 changed files with 24774 additions and 809 deletions

2
app/.gitignore vendored
View File

@ -2,7 +2,7 @@
# dependencies
/node_modules
/package-lock.json
# /package-lock.json
/.pnp
.pnp.js

22120
app/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,8 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@react-three/csg": "^3.2.0",
"@react-three/drei": "^9.113.0",
"@react-three/fiber": "^8.17.7",
@ -65,6 +67,7 @@
"devDependencies": {
"@types/node": "^22.9.1",
"@types/three": "^0.169.0",
"axios": "^1.8.4",
"cypress": "^13.14.2",
"dotenv": "^16.4.5",
"husky": "^9.1.6",

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -8,8 +8,8 @@ export function ThroughputIcon() {
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M10.124 7.90083L10.4726 8.94104L10.7027 9.64579C11.3046 11.5148 11.5973 12.6497 11.5973 13.1545C11.5973 14.3435 10.6334 15.3073 9.44448 15.3073C8.25553 15.3073 7.2917 14.3435 7.2917 13.1545C7.2917 12.5891 7.65886 11.2334 8.41633 8.94104L8.76493 7.90083C8.98524 7.25142 9.90372 7.25142 10.124 7.90083ZM9.44448 2.39062C13.4076 2.39062 16.6204 5.6034 16.6204 9.56655C16.6204 11.0058 16.1951 12.3836 15.4109 13.5546C15.1904 13.884 14.7447 13.9722 14.4154 13.7516C14.0861 13.5311 13.9979 13.0854 14.2184 12.7561C14.8456 11.8196 15.1852 10.7193 15.1852 9.56655C15.1852 6.39603 12.615 3.82581 9.44448 3.82581C6.27396 3.82581 3.70374 6.39603 3.70374 9.56655C3.70374 10.7193 4.04341 11.8196 4.67054 12.7561C4.89104 13.0854 4.80285 13.5311 4.47354 13.7516C4.14423 13.9722 3.69852 13.884 3.47801 13.5546C2.69389 12.3836 2.26855 11.0058 2.26855 9.56655C2.26855 5.6034 5.48133 2.39062 9.44448 2.39062ZM9.44448 10.4269L9.20879 11.188L9.04587 11.7413C8.83445 12.4807 8.72689 12.9596 8.72689 13.1545C8.72689 13.5508 9.04817 13.8721 9.44448 13.8721C9.8408 13.8721 10.1621 13.5508 10.1621 13.1545C10.1621 12.9161 10.0013 12.2533 9.6864 11.2087L9.44448 10.4269Z"
fill="#507BDC"
/>

View File

@ -0,0 +1,153 @@
export function StarsIcon() {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.39075 3.67726C9.58367 3.24444 9.68017 3.02804 9.8145 2.96139C9.93117 2.90349 10.0682 2.90349 10.1848 2.96139C10.3192 3.02804 10.4157 3.24444 10.6086 3.67726L12.1453 7.1247C12.2023 7.25265 12.2308 7.31663 12.275 7.36562C12.314 7.40897 12.3618 7.44364 12.415 7.46738C12.4753 7.49421 12.5449 7.50156 12.6843 7.51626L16.4378 7.91244C16.9091 7.96217 17.1447 7.98704 17.2496 8.09419C17.3407 8.18727 17.383 8.3176 17.364 8.44647C17.3422 8.5948 17.1662 8.75339 16.8142 9.07064L14.0103 11.5975C13.9063 11.6912 13.8542 11.7381 13.8213 11.7952C13.7921 11.8458 13.7738 11.9019 13.7678 11.9599C13.7608 12.0255 13.7753 12.094 13.8044 12.2311L14.5876 15.9233C14.6859 16.3869 14.7351 16.6186 14.6656 16.7515C14.6052 16.867 14.4943 16.9475 14.3659 16.9692C14.2181 16.9942 14.0128 16.8759 13.6023 16.6391L10.3328 14.7533C10.2114 14.6833 10.1508 14.6484 10.0863 14.6346C10.0292 14.6226 9.97017 14.6226 9.91309 14.6346C9.84859 14.6484 9.78792 14.6833 9.66659 14.7533L6.39702 16.6391C5.98654 16.8759 5.7813 16.9942 5.63345 16.9692C5.50503 16.9475 5.39416 16.867 5.3338 16.7515C5.2643 16.6186 5.31346 16.3869 5.41179 15.9233L6.19492 12.2311C6.22399 12.094 6.23852 12.0255 6.23162 11.9599C6.22551 11.9019 6.20729 11.8458 6.17812 11.7952C6.14516 11.7381 6.09313 11.6912 5.98907 11.5975L3.18522 9.07064C2.83321 8.75339 2.6572 8.5948 2.63532 8.44647C2.61632 8.3176 2.65866 8.18727 2.74978 8.09419C2.85468 7.98704 3.0903 7.96217 3.56155 7.91244L7.31513 7.51626C7.45445 7.50156 7.5241 7.49421 7.58433 7.46738C7.63762 7.44364 7.68534 7.40897 7.72439 7.36562C7.76851 7.31663 7.79703 7.25265 7.85407 7.1247L9.39075 3.67726Z"
stroke="#595965"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
export function DownloadIcon() {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2.5 11.875C2.84518 11.875 3.125 12.1548 3.125 12.5C3.125 13.6962 3.12633 14.5304 3.21096 15.1599C3.29317 15.7714 3.44354 16.0952 3.67418 16.3258C3.90481 16.5565 4.22863 16.7068 4.8401 16.7891C5.46956 16.8737 6.30383 16.875 7.5 16.875H12.5C13.6962 16.875 14.5304 16.8737 15.1599 16.7891C15.7714 16.7068 16.0952 16.5565 16.3258 16.3258C16.5565 16.0952 16.7068 15.7714 16.7891 15.1599C16.8737 14.5304 16.875 13.6962 16.875 12.5C16.875 12.1548 17.1548 11.875 17.5 11.875C17.8452 11.875 18.125 12.1548 18.125 12.5V12.5458C18.125 13.6854 18.125 14.604 18.0279 15.3265C17.9271 16.0766 17.7113 16.7081 17.2097 17.2097C16.7081 17.7113 16.0766 17.9271 15.3265 18.0279C14.604 18.125 13.6854 18.125 12.5458 18.125H7.45428C6.31462 18.125 5.39602 18.125 4.67354 18.0279C3.92345 17.9271 3.29189 17.7113 2.79029 17.2097C2.28869 16.7081 2.07295 16.0766 1.9721 15.3265C1.87497 14.604 1.87498 13.6854 1.875 12.5458C1.875 12.5305 1.875 12.5152 1.875 12.5C1.875 12.1548 2.15483 11.875 2.5 11.875Z"
fill="#FCFDFD"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10.0003 13.9583C10.1758 13.9583 10.3432 13.8846 10.4616 13.7551L13.7949 10.1093C14.0278 9.8545 14.0102 9.45917 13.7554 9.22625C13.5007 8.99333 13.1053 9.011 12.8724 9.26575L10.6253 11.7235V2.5C10.6253 2.15483 10.3455 1.875 10.0003 1.875C9.65516 1.875 9.37533 2.15483 9.37533 2.5V11.7235L7.12827 9.26575C6.89535 9.011 6.50002 8.99333 6.24527 9.22625C5.99052 9.45917 5.97281 9.8545 6.20573 10.1093L9.53908 13.7551C9.65749 13.8846 9.82483 13.9583 10.0003 13.9583Z"
fill="#FCFDFD"
/>
</svg>
);
}
export function EyeIconBig() {
return (
<svg
width="22"
height="22"
viewBox="0 0 22 22"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2.75 11.918C6.05 4.58464 15.95 4.58464 19.25 11.918"
stroke="#2B3344"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M11 15.5859C10.6389 15.5859 10.2813 15.5148 9.94762 15.3766C9.61398 15.2384 9.31082 15.0358 9.05546 14.7805C8.80009 14.5251 8.59753 14.222 8.45933 13.8883C8.32113 13.5547 8.25 13.1971 8.25 12.8359C8.25 12.4748 8.32113 12.1172 8.45933 11.7836C8.59753 11.4499 8.80009 11.1468 9.05546 10.8914C9.31082 10.636 9.61398 10.4335 9.94762 10.2953C10.2813 10.1571 10.6389 10.0859 11 10.0859C11.7293 10.0859 12.4288 10.3757 12.9445 10.8914C13.4603 11.4071 13.75 12.1066 13.75 12.8359C13.75 13.5653 13.4603 14.2648 12.9445 14.7805C12.4288 15.2962 11.7293 15.5859 11 15.5859Z"
stroke="#2B3344"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
export function CommentsIcon() {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_2926_17620)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8 13C7.416 13 6.852 12.932 6.31 12.8165L3.956 14.2315L3.9875 11.912C2.183 10.827 1 9.033 1 7C1 3.6865 4.134 1 8 1C11.866 1 15 3.6865 15 7C15 10.314 11.866 13 8 13ZM8 0C3.582 0 0 3.1345 0 7C0 9.2095 1.1725 11.177 3 12.4595V16L6.5045 13.8735C6.9895 13.9535 7.4885 14 8 14C12.418 14 16 10.866 16 7C16 3.1345 12.418 0 8 0ZM11.5 5.5H4.5C4.224 5.5 4 5.724 4 6C4 6.2765 4.224 6.5 4.5 6.5H11.5C11.776 6.5 12 6.2765 12 6C12 5.724 11.776 5.5 11.5 5.5ZM10.5 8.5H5.5C5.224 8.5 5 8.7235 5 9C5 9.2765 5.224 9.5 5.5 9.5H10.5C10.776 9.5 11 9.2765 11 9C11 8.7235 10.776 8.5 10.5 8.5Z"
fill="#2B3344"
/>
</g>
<defs>
<clipPath id="clip0_2926_17620">
<rect width="16" height="16" fill="white" />
</clipPath>
</defs>
</svg>
);
}
export function VerifiedIcon() {
return (
<svg
width="12"
height="13"
viewBox="0 0 12 13"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.7962 2.10014C4.67444 2.2039 4.61356 2.25579 4.54853 2.29937C4.39948 2.39927 4.23209 2.46861 4.05605 2.50336C3.97926 2.51853 3.89952 2.52489 3.74004 2.53761C3.33935 2.56959 3.139 2.58558 2.97186 2.64462C2.58526 2.78117 2.28117 3.08526 2.14462 3.47186C2.08558 3.639 2.06959 3.83935 2.03761 4.24004C2.02489 4.39952 2.01853 4.47926 2.00336 4.55605C1.96861 4.73209 1.89927 4.89948 1.79937 5.04853C1.75579 5.11356 1.70391 5.17444 1.60014 5.2962C1.33942 5.60215 1.20905 5.7551 1.13261 5.91505C0.955796 6.285 0.955796 6.715 1.13261 7.08495C1.20906 7.2449 1.33942 7.39785 1.60014 7.7038C1.70389 7.82555 1.75579 7.88645 1.79937 7.95145C1.89927 8.1005 1.96861 8.2679 2.00336 8.44395C2.01853 8.52075 2.02489 8.6005 2.03761 8.75995C2.06959 9.16065 2.08558 9.361 2.14462 9.52815C2.28117 9.91475 2.58526 10.2189 2.97186 10.3554C3.139 10.4144 3.33935 10.4304 3.74004 10.4624C3.89952 10.4751 3.97926 10.4815 4.05605 10.4966C4.23209 10.5314 4.39948 10.6007 4.54853 10.7007C4.61356 10.7442 4.67444 10.7961 4.7962 10.8998C5.10215 11.1606 5.2551 11.2909 5.41505 11.3674C5.785 11.5442 6.215 11.5442 6.58495 11.3674C6.7449 11.2909 6.89785 11.1606 7.2038 10.8998C7.32555 10.7961 7.38645 10.7442 7.45145 10.7007C7.6005 10.6007 7.7679 10.5314 7.94395 10.4966C8.02075 10.4815 8.1005 10.4751 8.25995 10.4624C8.66065 10.4304 8.861 10.4144 9.02815 10.3554C9.41475 10.2189 9.71885 9.91475 9.8554 9.52815C9.9144 9.361 9.9304 9.16065 9.9624 8.75995C9.9751 8.6005 9.9815 8.52075 9.99665 8.44395C10.0314 8.2679 10.1007 8.1005 10.2007 7.95145C10.2442 7.88645 10.2961 7.82555 10.3998 7.7038C10.6606 7.39785 10.7909 7.2449 10.8674 7.08495C11.0442 6.715 11.0442 6.285 10.8674 5.91505C10.7909 5.7551 10.6606 5.60215 10.3998 5.2962C10.2961 5.17444 10.2442 5.11356 10.2007 5.04853C10.1007 4.89948 10.0314 4.73209 9.99665 4.55605C9.9815 4.47926 9.9751 4.39952 9.9624 4.24004C9.9304 3.83935 9.9144 3.639 9.8554 3.47186C9.71885 3.08526 9.41475 2.78117 9.02815 2.64462C8.861 2.58558 8.66065 2.56959 8.25995 2.53761C8.1005 2.52489 8.02075 2.51853 7.94395 2.50336C7.7679 2.46861 7.6005 2.39927 7.45145 2.29937C7.38645 2.25579 7.32555 2.20391 7.2038 2.10014C6.89785 1.83942 6.7449 1.70906 6.58495 1.63261C6.215 1.4558 5.785 1.4558 5.41505 1.63261C5.2551 1.70905 5.10215 1.83942 4.7962 2.10014ZM8.18675 5.43157C8.34565 5.27265 8.34565 5.015 8.18675 4.85608C8.02785 4.69717 7.77015 4.69717 7.61125 4.85608L5.18615 7.2812L4.38873 6.4838C4.22982 6.3249 3.97216 6.3249 3.81325 6.4838C3.65433 6.6427 3.65433 6.90035 3.81325 7.0593L4.89839 8.14445C5.0573 8.30335 5.31495 8.30335 5.4739 8.14445L8.18675 5.43157Z"
fill="#6F42C1"
/>
</svg>
);
}
export function StarsIconSmall() {
return (
<svg
width="13"
height="13"
viewBox="0 0 13 13"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.43387 2.70558C6.54962 2.44589 6.60752 2.31604 6.68812 2.27606C6.75812 2.24131 6.84032 2.24131 6.91032 2.27606C6.99092 2.31604 7.04882 2.44589 7.16457 2.70558L8.08657 4.77404C8.12082 4.85081 8.13792 4.8892 8.16442 4.91859C8.18782 4.9446 8.21647 4.96541 8.24842 4.97965C8.28457 4.99575 8.32637 5.00016 8.40997 5.00898L10.6621 5.24668C10.9449 5.27652 11.0862 5.29144 11.1492 5.35574C11.2038 5.41158 11.2292 5.48978 11.2178 5.5671C11.2047 5.6561 11.0991 5.75125 10.8879 5.9416L9.20557 7.4577C9.14317 7.51395 9.11192 7.5421 9.09217 7.57635C9.07467 7.6067 9.06372 7.64035 9.06007 7.67515C9.05592 7.7145 9.06462 7.7556 9.08207 7.83785L9.55197 10.0532C9.61097 10.3314 9.64047 10.4704 9.59877 10.5501C9.56252 10.6194 9.49602 10.6677 9.41897 10.6808C9.33027 10.6958 9.20712 10.6248 8.96082 10.4827L6.99907 9.3512C6.92627 9.3092 6.88987 9.28825 6.85117 9.28C6.81692 9.27275 6.78152 9.27275 6.74727 9.28C6.70857 9.28825 6.67217 9.3092 6.59937 9.3512L4.63763 10.4827C4.39134 10.6248 4.26819 10.6958 4.17949 10.6808C4.10243 10.6677 4.03591 10.6194 3.99969 10.5501C3.958 10.4704 3.98749 10.3314 4.04649 10.0532L4.51637 7.83785C4.53381 7.7556 4.54253 7.7145 4.53839 7.67515C4.53472 7.64035 4.52379 7.6067 4.50629 7.57635C4.48651 7.5421 4.45529 7.51395 4.39286 7.4577L2.71055 5.9416C2.49934 5.75125 2.39374 5.6561 2.38061 5.5671C2.36921 5.48978 2.39461 5.41158 2.44928 5.35574C2.51222 5.29144 2.6536 5.27652 2.93635 5.24668L5.18849 5.00898C5.27208 5.00016 5.31387 4.99575 5.35001 4.97965C5.38199 4.96541 5.41062 4.9446 5.43405 4.91859C5.46052 4.8892 5.47763 4.85081 5.51186 4.77404L6.43387 2.70558Z"
stroke="#595965"
strokeWidth="0.6"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
export function FiileedStarsIconSmall() {
return (
<svg
width="11"
height="12"
viewBox="0 0 11 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5.07372 1.61354C5.20877 1.31056 5.27632 1.15908 5.37035 1.11243C5.45202 1.0719 5.54791 1.0719 5.62958 1.11243C5.72362 1.15908 5.79117 1.31056 5.92621 1.61354L7.00187 4.02675C7.04183 4.11631 7.06178 4.16109 7.0927 4.19539C7.12 4.22573 7.15342 4.25 7.1907 4.26662C7.23287 4.2854 7.28164 4.29055 7.37917 4.30084L10.0067 4.57816C10.3366 4.61297 10.5015 4.63038 10.5749 4.70539C10.6387 4.77054 10.6683 4.86177 10.655 4.95198C10.6397 5.05581 10.5165 5.16682 10.2701 5.3889L8.30737 7.15768C8.23457 7.22331 8.19811 7.25615 8.17507 7.29611C8.15466 7.33152 8.14188 7.37077 8.13762 7.41137C8.13278 7.45728 8.14293 7.50523 8.16329 7.60119L8.71151 10.1858C8.78034 10.5103 8.81476 10.6725 8.76611 10.7655C8.72381 10.8463 8.64623 10.9027 8.55634 10.9179C8.45286 10.9354 8.30918 10.8526 8.02183 10.6868L5.73312 9.36677C5.64819 9.31777 5.60572 9.29332 5.56057 9.2837C5.52062 9.27524 5.47931 9.27524 5.43936 9.2837C5.39421 9.29332 5.35174 9.31777 5.26681 9.36677L2.97811 10.6868C2.69077 10.8526 2.5471 10.9354 2.44361 10.9179C2.35372 10.9027 2.27611 10.8463 2.23385 10.7655C2.18521 10.6725 2.21962 10.5103 2.28845 10.1858L2.83664 7.60119C2.85699 7.50523 2.86716 7.45728 2.86233 7.41137C2.85805 7.37077 2.8453 7.33152 2.82488 7.29611C2.80181 7.25615 2.76539 7.22331 2.69254 7.15768L0.72985 5.3889C0.483444 5.16682 0.360238 5.05581 0.34492 4.95198C0.33162 4.86177 0.361259 4.77054 0.425041 4.70539C0.498471 4.63038 0.663408 4.61297 0.993283 4.57816L3.62079 4.30084C3.71831 4.29055 3.76706 4.2854 3.80923 4.26662C3.84653 4.25 3.87993 4.22573 3.90727 4.19539C3.93815 4.16109 3.95812 4.11631 3.99804 4.02675L5.07372 1.61354Z"
fill="#F3A50C"
stroke="#F3A50C"
strokeWidth="0.7"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}

View File

@ -30,6 +30,7 @@ const Outline: React.FC = () => {
defaultOpen={true}
showKebabMenu={false}
showFocusIcon={true}
remove
/>
<DropDownList
value="Scene"

View File

@ -5,7 +5,7 @@ import Widgets3D from "./Widgets3D";
import WidgetsFloating from "./WidgetsFloating";
const Widgets = () => {
const [activeOption, setActiveOption] = useState("Floating");
const [activeOption, setActiveOption] = useState("2D");
const handleToggleClick = (option: string) => {
setActiveOption(option);

View File

@ -9,7 +9,6 @@ const chartTypes: ChartType[] = [
"line",
"pie",
"doughnut",
"radar",
"polarArea",
];

View File

@ -12,20 +12,19 @@ import {
import useToggleStore from "../../../store/useUIToggleStore";
import MachineMechanics from "./mechanics/MachineMechanics";
import Visualization from "./visualization/Visualization";
import GlobalProperties from "./properties/GlobalProperties";
import AsstePropertiies from "./properties/AssetProperties";
import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations";
import { useSelectedActionSphere } from "../../../store/store";
import GlobalProperties from "./properties/GlobalProperties";
import AsstePropertiies from "./properties/AssetProperties";
import ZoneProperties from "./properties/ZoneProperties";
const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore();
const { toggleUI } = useToggleStore();
const { selectedActionSphere } = useSelectedActionSphere();
const { subModule, setSubModule } = useSubModuleStore();
const { toggleUI } = useToggleStore();
// Reset subModule whenever activeModule changes
// Reset activeList whenever activeModule changes
useEffect(() => {
if (activeModule !== "simulation") setSubModule("properties");
if (activeModule === "simulation") setSubModule("mechanics");
@ -84,7 +83,17 @@ const SideBarRight: React.FC = () => {
</div>
</div>
)}
{toggleUI &&
subModule === "zoneProperties" &&
activeModule === "builder" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
{/* <GlobalProperties /> */}
<ZoneProperties />
{/* <AsstePropertiies /> */}
</div>
</div>
)}
{/* simulation */}
{toggleUI && activeModule === "simulation" && (

View File

@ -1,62 +1,57 @@
import React from "react";
import { EyeDroperIcon } from "../../../icons/ExportCommonIcons";
// import { useThree } from "@react-three/fiber";
interface PositionInputProps {
onChange: (value: string) => void; // Callback for value change
onChange: (value: [number, number, number]) => void; // Callback for value change
header: string;
placeholder?: string; // Optional placeholder
type?: string; // Input type (e.g., text, number, email)
value: [number, number, number] | null;
disabled?: boolean; // To enable/disable editing
}
const Vector3Input: React.FC<PositionInputProps> = ({
onChange,
header,
placeholder = "Enter value", // Default placeholder
type = "number", // Default type
type = "string", // Default type
value,
disabled = false, // Default to disabled
}) => {
const handleChange = (index: number, newValue: string) => {
if (!value) return;
const updatedValue = [...value] as [number, number, number];
updatedValue[index] = parseFloat(newValue) || 0;
console.log('updatedValue: ', updatedValue);
onChange(updatedValue);
};
return (
<div className="custom-input-container">
<div className="header">
{header}
{/* <div className="eyedrop-button">
<EyeDroperIcon isActive={false} />
</div> */}
</div>
<div className="inputs-container">
<div className="input-container">
<div className="custom-input-label">X : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
disabled
/>
</div>
<div className="input-container">
<div className="custom-input-label">Y : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
disabled
min={0}
/>
</div>
<div className="input-container">
<div className="custom-input-label">Z : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
disabled
/>
</div>
{["X", "Y", "Z"].map((axis, i) => (
<div className="input-container" key={axis}>
<div className="custom-input-label">{axis}:</div>
<input
className="custom-input-field"
type={type}
value={value?.[i] !== undefined ? value[i].toFixed(2) : ""}
// onChange={(e) => handleChange(i, e.target.value)}
placeholder={placeholder}
disabled={disabled}
/>
</div>
))}
</div>
</div>
);
};
export default Vector3Input;
export default Vector3Input;

View File

@ -1,32 +1,65 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import RenameInput from "../../../ui/inputs/RenameInput";
import Vector3Input from "../customInput/Vector3Input";
import { useSelectedZoneStore } from "../../../../store/useZoneStore";
import { useEditPosition, usezonePosition, usezoneTarget } from "../../../../store/store";
const ZoneProperties: React.FC = () => {
const [Edit, setEdit] = useState(false);
const { Edit, setEdit } = useEditPosition();
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const { zonePosition, setZonePosition } = usezonePosition();
const { zoneTarget, setZoneTarget } = usezoneTarget();
useEffect(() => {
setZonePosition(selectedZone.zoneViewPortPosition)
setZoneTarget(selectedZone.zoneViewPortTarget)
}, [selectedZone?.zoneViewPortPosition, selectedZone?.zoneViewPortTarget])
function handleSetView() {
console.log("setApi");
console.log('zoneTarget: ', zoneTarget);
console.log('zonePosition: ', zonePosition);
setEdit(false);
}
function handleEditView() {
if (Edit) {
setEdit(false);
} else {
setEdit(true);
}
setEdit(!Edit); // This will toggle the `Edit` state correctly
}
function handleZoneNameChange(newName: string) {
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
}
function handleVectorChange(key: "zoneViewPortTarget" | "zoneViewPortPosition", newValue: [number, number, number]) {
setSelectedZone((prev) => ({ ...prev, [key]: newValue }));
}
useEffect(() => {
console.log("Updated selectedZone: ", selectedZone);
}, [selectedZone]);
return (
<div className="zone-properties-container">
<div className="header">
<RenameInput value="Selected Zone Name" />
<RenameInput value={selectedZone.zoneName} onRename={handleZoneNameChange} />
<div className="button" onClick={handleEditView}>
{Edit ? "Cancel" : "Edit"}
</div>
</div>
<Vector3Input onChange={() => {}} header="Viewport Target" />
<Vector3Input onChange={() => {}} header="Viewport Position" />
<Vector3Input
onChange={(value) => handleVectorChange("zoneViewPortTarget", value)}
header="Viewport Target"
value={zoneTarget as [number, number, number]}
disabled={!Edit}
/>
<Vector3Input
onChange={(value) => handleVectorChange("zoneViewPortPosition", value)}
header="Viewport Position"
value={zonePosition as [number, number, number]}
disabled={!Edit}
/>
{Edit && (
<div className="button-save" onClick={handleSetView}>
Set View
@ -37,3 +70,4 @@ const ZoneProperties: React.FC = () => {
};
export default ZoneProperties;

View File

@ -0,0 +1,115 @@
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 axios from 'axios'
type Props = {}
const LineGrapInput = (props: Props) => {
const [dropDowndata, setDropDownData] = useState({})
const [selections, setSelections] = useState<Record<string, { name: string, fields: string }>>({})
const [selectedOption, setSelectedOption] = useState('1h')
const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
const handleSelectDuration = (option: string) => {
updateDuration(option); // Normalize for key matching
};
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get('http://192.168.0.192:5010/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(() => {
console.log(selections);
}, [selections])
const handleSelect = (inputKey: string, selectedData: { name: string, fields: string } | null) => {
setSelections(prev => {
if (selectedData === null) {
const newSelections = { ...prev };
delete newSelections[inputKey];
return newSelections;
} else {
return {
...prev,
[inputKey]: selectedData
};
}
});
};
interface Measurement {
name: string;
fields: string;
}
interface InputData {
[key: string]: Measurement;
}
const extractMeasurements = (input: InputData): Measurement[] => {
return Object.values(input);
};
useEffect(() => {
const measurementsData = extractMeasurements(selections);
setMeasurements(measurementsData);
}, [selections]);
return (
<>
<div className="inputs-wrapper">
{[...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]}
/>
<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 LineGrapInput

View File

@ -0,0 +1,77 @@
import React, { useEffect, useState } from 'react'
import MultiLevelDropdown from '../../../../ui/inputs/MultiLevelDropDown'
import { AddIcon } from '../../../../icons/ExportCommonIcons'
import axios from 'axios'
type Props = {}
const PieChartInput = (props: Props) => {
const [dropDowndata, setDropDownData] = useState({})
const [selections, setSelections] = useState<Record<string, {name: string, fields: string}>>({})
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get('http://192.168.0.192:5010/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(() => {console.log(selections);
},[selections])
const handleSelect = (inputKey: string, selectedData: {name: string, fields: string} | null) => {
setSelections(prev => {
if (selectedData === null) {
const newSelections = {...prev};
delete newSelections[inputKey];
return newSelections;
} else {
return {
...prev,
[inputKey]: selectedData
};
}
});
};
return (
<>
<div className="inputs-wrapper">
{[...Array(3)].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]}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
<div>
</div>
</>
)
}
export default PieChartInput

View File

@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons";
import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown";
import LineGrapInput from "../IotInputCards/LineGrapInput";
// Define the data structure for demonstration purposes
const DATA_STRUCTURE = {
@ -123,41 +124,10 @@ const Data = () => {
<div className="sideBarHeader">{selectedChartId?.title}</div>
)}
{/* Render groups dynamically */}
{chartDataGroups[selectedChartId?.id]?.map((group) => (
<div key={group.id} className="inputs-wrapper">
{group.children.map((child, index) => (
<div key={child.id} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropDown data={DATA_STRUCTURE} />
{/* Add Icon */}
{group.children.length < 7 && (
<div
className="icon"
onClick={() => handleAddClick(group.id)} // Pass groupId to handleAddClick
>
<AddIcon />
</div>
)}
{/* Remove Icon */}
<span
className={`datas__separator ${
group.children.length > 1 ? "" : "disable"
}`}
onClick={(e) => {
e.stopPropagation(); // Prevent event bubbling
removeChild(group.id, child.id); // Pass groupId and childId to removeChild
}}
>
<RemoveIcon />
</span>
</div>
</div>
))}
</div>
))}
{
chartDataGroups[selectedChartId?.id] && <LineGrapInput />
}
{/* Info Box */}
<div className="infoBox">
<span className="infoIcon">i</span>
@ -173,3 +143,40 @@ const Data = () => {
};
export default Data;
// {chartDataGroups[selectedChartId?.id]?.map((group) => (
// <div key={group.id} className="inputs-wrapper">
// {group.children.map((child, index) => (
// <div key={child.id} className="datas">
// <div className="datas__label">Input {index + 1}</div>
// <div className="datas__class">
// <MultiLevelDropDown data={DATA_STRUCTURE} />
// {/* Add Icon */}
// {group.children.length < 7 && (
// <div
// className="icon"
// onClick={() => handleAddClick(group.id)} // Pass groupId to handleAddClick
// >
// <AddIcon />
// </div>
// )}
// {/* Remove Icon */}
// <span
// className={`datas__separator ${
// group.children.length > 1 ? "" : "disable"
// }`}
// onClick={(e) => {
// e.stopPropagation(); // Prevent event bubbling
// removeChild(group.id, child.id); // Pass groupId and childId to removeChild
// }}
// >
// <RemoveIcon />
// </span>
// </div>
// </div>
// ))}
// </div>
// ))}

View File

@ -17,7 +17,12 @@ import { handleSaveTemplate } from "../../modules/visualization/handleSaveTempla
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
import useTemplateStore from "../../store/useTemplateStore";
import { useSelectedZoneStore } from "../../store/useZoneStore";
import { useAddAction, useDeleteModels, useSelectedWallItem, useToggleView } from "../../store/store";
import {
useAddAction,
useDeleteModels,
useSelectedWallItem,
useToggleView,
} from "../../store/store";
const Tools: React.FC = () => {
const { templates } = useTemplateStore();
@ -39,7 +44,6 @@ const Tools: React.FC = () => {
const { setAddAction } = useAddAction();
const { setSelectedWallItem } = useSelectedWallItem();
// Reset activeTool whenever activeModule changes
useEffect(() => {
setActiveTool(activeSubTool);
@ -52,8 +56,7 @@ const Tools: React.FC = () => {
setDeleteModels(false);
setAddAction(null);
setToggleView(true);
}
else {
} else {
setToggleView(false);
}
setToggleThreeD(!toggleThreeD);
@ -68,196 +71,225 @@ const Tools: React.FC = () => {
setOpenDrop(false); // Close the dropdown
}
};
const handleEscKeyPress = (event: KeyboardEvent) => {
if (event.key === "Escape") {
setIsPlaying(false); // Set isPlaying to false when Escape key is pressed
}
};
document.addEventListener("mousedown", handleOutsideClick);
document.addEventListener("keydown", handleEscKeyPress); // Listen for ESC key
return () => {
document.removeEventListener("mousedown", handleOutsideClick);
document.removeEventListener("keydown", handleEscKeyPress); // Clean up the event listener
};
}, []);
return (
<div className="tools-container">
<div className="drop-down-icons">
<div className="activeDropicon">
{activeSubTool == "cursor" && (
<div
className={`tool-button ${activeTool === "cursor" ? "active" : ""
}`}
onClick={() => {
setActiveTool("cursor");
}}
>
<CursorIcon isActive={activeTool === "cursor"} />
</div>
)}
{activeSubTool == "free-hand" && (
<div
className={`tool-button ${activeTool === "free-hand" ? "active" : ""
}`}
onClick={() => {
setActiveTool("free-hand");
}}
>
<FreeMoveIcon isActive={activeTool === "free-hand"} />
</div>
)}
{activeModule !== "visualization" && (
<div
className="drop-down-option-button"
ref={dropdownRef}
onClick={() => {
setOpenDrop(!openDrop);
console.log(openDrop);
}}
>
<ArrowIcon />
{openDrop && (
<div className="drop-down-container">
<>
{!isPlaying ? (
<>
<div className="tools-container">
<div className="drop-down-icons">
<div className="activeDropicon">
{activeSubTool == "cursor" && (
<div
className="option-list"
className={`tool-button ${
activeTool === "cursor" ? "active" : ""
}`}
onClick={() => {
setOpenDrop(false);
setActiveTool("cursor");
setActiveSubTool("cursor");
}}
>
<div className="active-option">
{activeSubTool === "cursor" && <TickIcon />}
</div>
<CursorIcon isActive={false} />
<div className="option">Cursor</div>
<CursorIcon isActive={activeTool === "cursor"} />
</div>
)}
{activeSubTool == "free-hand" && (
<div
className={`tool-button ${
activeTool === "free-hand" ? "active" : ""
}`}
onClick={() => {
setActiveTool("free-hand");
}}
>
<FreeMoveIcon isActive={activeTool === "free-hand"} />
</div>
)}
{activeModule !== "visualization" && (
<div
className="drop-down-option-button"
ref={dropdownRef}
onClick={() => {
setOpenDrop(!openDrop);
console.log(openDrop);
}}
>
<ArrowIcon />
{openDrop && (
<div className="drop-down-container">
<div
className="option-list"
onClick={() => {
setOpenDrop(false);
setActiveTool("cursor");
setActiveSubTool("cursor");
}}
>
<div className="active-option">
{activeSubTool === "cursor" && <TickIcon />}
</div>
<CursorIcon isActive={false} />
<div className="option">Cursor</div>
</div>
<div
className="option-list"
onClick={() => {
setOpenDrop(false);
setActiveTool("free-hand");
setActiveSubTool("free-hand");
}}
>
<div className="active-option">
{activeSubTool === "free-hand" && <TickIcon />}
</div>
<FreeMoveIcon isActive={false} />
<div className="option">Free Hand</div>
</div>
</div>
)}
</div>
)}
</div>
</div>
{!toggleThreeD && activeModule === "builder" && (
<>
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${
activeTool === "draw-wall" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-wall");
}}
>
<WallIcon isActive={activeTool === "draw-wall"} />
</div>
<div
className="option-list"
className={`tool-button ${
activeTool === "draw-zone" ? "active" : ""
}`}
onClick={() => {
setOpenDrop(false);
setActiveTool("free-hand");
setActiveSubTool("free-hand");
setActiveTool("draw-zone");
}}
>
<div className="active-option">
{activeSubTool === "free-hand" && <TickIcon />}
</div>
<FreeMoveIcon isActive={false} />
<div className="option">Free Hand</div>
<ZoneIcon isActive={activeTool === "draw-zone"} />
</div>
<div
className={`tool-button ${
activeTool === "draw-aisle" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-aisle");
}}
>
<AsileIcon isActive={activeTool === "draw-aisle"} />
</div>
<div
className={`tool-button ${
activeTool === "draw-floor" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-floor");
}}
>
<FloorIcon isActive={activeTool === "draw-floor"} />
</div>
</div>
)}
</div>
)}
</div>
</div>
{!toggleThreeD && activeModule === "builder" && (
<>
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${activeTool === "draw-wall" ? "active" : ""
</>
)}
{activeModule === "simulation" && (
<>
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${
activeTool === "pen" ? "active" : ""
}`}
onClick={() => {
setActiveTool("pen");
}}
>
<PenIcon isActive={activeTool === "pen"} />
</div>
</div>
</>
)}
{activeModule === "visualization" && (
<>
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button`}
onClick={() =>
handleSaveTemplate({
addTemplate,
selectedZone,
templates,
})
}
>
<SaveTemplateIcon isActive={false} />
</div>
</div>
</>
)}
<div className="split"></div>
<div className="general-options">
<div
className={`tool-button ${
activeTool === "comment" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-wall");
}}
>
<WallIcon isActive={activeTool === "draw-wall"} />
</div>
<div
className={`tool-button ${activeTool === "draw-zone" ? "active" : ""
onClick={() => {
setActiveTool("comment");
}}
>
<CommentIcon isActive={activeTool === "comment"} />
</div>
<div
className={`tool-button ${
activeTool === "play" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-zone");
}}
>
<ZoneIcon isActive={activeTool === "draw-zone"} />
onClick={() => {
setIsPlaying(!isPlaying);
}}
>
<PlayIcon isActive={activeTool === "play"} />
</div>
</div>
<div className="split"></div>
<div
className={`tool-button ${activeTool === "draw-aisle" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-aisle");
}}
className={`toggle-threed-button${
toggleThreeD ? " toggled" : ""
}`}
onClick={toggleSwitch}
>
<AsileIcon isActive={activeTool === "draw-aisle"} />
</div>
<div
className={`tool-button ${activeTool === "draw-floor" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-floor");
}}
>
<FloorIcon isActive={activeTool === "draw-floor"} />
<div className={`toggle-option${!toggleThreeD ? " active" : ""}`}>
2d
</div>
<div className={`toggle-option${toggleThreeD ? " active" : ""}`}>
3d
</div>
</div>
</div>
</>
) : (
<div className="exitPlay" onClick={() => setIsPlaying(false)}>
X
</div>
)}
{activeModule === "simulation" && (
<>
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${activeTool === "pen" ? "active" : ""}`}
onClick={() => {
setActiveTool("pen");
}}
>
<PenIcon isActive={activeTool === "pen"} />
</div>
</div>
</>
)}
{activeModule === "visualization" && (
<>
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button`}
onClick={() =>
handleSaveTemplate({
addTemplate,
selectedZone,
templates,
})
}
>
<SaveTemplateIcon isActive={false} />
</div>
</div>
</>
)}
<div className="split"></div>
<div className="general-options">
<div
className={`tool-button ${activeTool === "comment" ? "active" : ""}`}
onClick={() => {
setActiveTool("comment");
}}
>
<CommentIcon isActive={activeTool === "comment"} />
</div>
<div
className={`tool-button ${activeTool === "play" ? "active" : ""}`}
onClick={() => {
setActiveTool("play");
setIsPlaying(!isPlaying);
}}
>
<PlayIcon isActive={activeTool === "play"} />
</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>
</div>
</>
);
};

View File

@ -4,6 +4,7 @@ import {
EyeIcon,
LockIcon,
} from "../../icons/RealTimeVisulationIcons";
import { panelData } from "../../../services/realTimeVisulization/zoneData/panel";
// Define the type for `Side`
type Side = "top" | "bottom" | "left" | "right";
@ -15,6 +16,9 @@ interface ButtonsProps {
activeSides: Side[];
panelOrder: Side[];
lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[]
widgets: {
id: string;
type: string;
@ -29,6 +33,9 @@ interface ButtonsProps {
activeSides: Side[];
panelOrder: Side[];
lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[]
widgets: {
id: string;
type: string;
@ -108,7 +115,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
panelOrder: newActiveSides,
};
// Update the selectedZone state
// Delete the selectedZone state
console.log('updatedZone: ', updatedZone);
setSelectedZone(updatedZone);
} else {
// If the panel is not active, activate it
@ -119,73 +127,84 @@ const AddButtons: React.FC<ButtonsProps> = ({
activeSides: newActiveSides,
panelOrder: newActiveSides,
};
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
// let response = panelData(organization, selectedZone.zoneId, newActiveSides)
// console.log('response: ', response);
// Update the selectedZone state
console.log("updatedZone: ", updatedZone);
setSelectedZone(updatedZone);
}
};
return (
<div>
{(["top", "right", "bottom", "left"] as Side[]).map((side) => (
<div key={side} className={`side-button-container ${side}`}>
{/* "+" Button */}
<button
className={`side-button ${side}`}
onClick={() => handlePlusButtonClick(side)}
title={
selectedZone.activeSides.includes(side)
? `Remove all items and close ${side} panel`
: `Activate ${side} panel`
}
>
+
</button>
<>
<div>
{(["top", "right", "bottom", "left"] as Side[]).map((side) => (
<div key={side} className={`side-button-container ${side}`}>
{/* "+" Button */}
<button
className={`side-button ${side}`}
onClick={() => handlePlusButtonClick(side)}
title={
selectedZone.activeSides.includes(side)
? `Remove all items and close ${side} panel`
: `Activate ${side} panel`
}
>
+
</button>
{/* Extra Buttons */}
{selectedZone.activeSides.includes(side) && (
<div className="extra-Bs">
{/* Hide Panel */}
<div
className={`icon ${
hiddenPanels.includes(side) ? "active" : ""
}`}
title={
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
}
onClick={() => toggleVisibility(side)}
>
<EyeIcon />
</div>
{/* Extra Buttons */}
{selectedZone.activeSides.includes(side) && (
<div className="extra-Bs">
{/* Hide Panel */}
<div
className={`icon ${hiddenPanels.includes(side) ? "active" : ""
}`}
title={
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
}
onClick={() => toggleVisibility(side)}
>
<EyeIcon
fill={
hiddenPanels.includes(side)
? "white"
: "#1D1E21"
}
/>
</div>
{/* Clean Panel */}
<div
className="icon"
title="Clean Panel"
onClick={() => cleanPanel(side)}
>
<CleanPannel />
</div>
{/* Clean Panel */}
<div
className="icon"
title="Clean Panel"
onClick={() => cleanPanel(side)}
>
<CleanPannel />
</div>
{/* Lock/Unlock Panel */}
<div
className={`icon ${
selectedZone.lockedPanels.includes(side) ? "active" : ""
}`}
title={
selectedZone.lockedPanels.includes(side)
? "Unlock Panel"
: "Lock Panel"
}
onClick={() => toggleLockPanel(side)}
>
<LockIcon />
{/* Lock/Unlock Panel */}
<div
className={`icon ${selectedZone.lockedPanels.includes(side) ? "active" : ""
}`}
title={
selectedZone.lockedPanels.includes(side)
? "Unlock Panel"
: "Lock Panel"
}
onClick={() => toggleLockPanel(side)}
>
<LockIcon fill={selectedZone.lockedPanels.includes(side) ? "#ffffff" : "#1D1E21"} />
</div>
</div>
</div>
)}
</div>
))}
</div>
)}
</div>
))}
</div>
</>
);
};

View File

@ -11,6 +11,9 @@ interface DisplayZoneProps {
panelOrder: Side[];
lockedPanels: Side[];
widgets: Widget[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[];
};
};
selectedZone: {
@ -18,6 +21,9 @@ interface DisplayZoneProps {
activeSides: Side[];
panelOrder: Side[];
lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[];
widgets: {
id: string;
type: string;
@ -32,6 +38,9 @@ interface DisplayZoneProps {
activeSides: Side[];
panelOrder: Side[];
lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[];
widgets: {
id: string;
type: string;
@ -152,21 +161,32 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
return (
<div
ref={containerRef}
className={`zoon-wrapper ${
selectedZone.activeSides.includes("bottom") && "bottom"
}`}
className={`zoon-wrapper ${selectedZone?.activeSides?.includes("bottom") && "bottom"
}`}
>
{Object.keys(zonesData).map((zoneName, index) => (
<div
key={index}
className={`zone ${
selectedZone.zoneName === zoneName ? "active" : ""
}`}
className={`zone ${selectedZone.zoneName === zoneName ? "active" : ""
}`}
onClick={() => {
setSelectedZone({
zoneName,
...zonesData[zoneName],
activeSides: zonesData[zoneName].activeSides || [],
panelOrder: zonesData[zoneName].panelOrder || [],
lockedPanels: zonesData[zoneName].lockedPanels || [],
widgets: zonesData[zoneName].widgets || [],
zoneId: zonesData[zoneName]?.zoneId || "",
zoneViewPortTarget: zonesData[zoneName].zoneViewPortTarget || [],
zoneViewPortPosition:
zonesData[zoneName].zoneViewPortPosition || [],
});
// setSelectedZone({
// zoneName,
// ...zonesData[zoneName],
// });
}}
>
{zoneName}
@ -176,4 +196,4 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
);
};
export default DisplayZone;
export default DisplayZone;

View File

@ -1,9 +1,21 @@
import { useWidgetStore } from "../../../store/useWidgetStore";
import PieGraphComponent from "../charts/PieGraphComponent";
import BarGraphComponent from "../charts/BarGraphComponent";
import LineGraphComponent from "../charts/LineGraphComponent";
import ProgressCard from "../realTimeVis/charts/ProgressCard";
import PieGraphComponent from "../realTimeVis/charts/PieGraphComponent";
import BarGraphComponent from "../realTimeVis/charts/BarGraphComponent";
import LineGraphComponent from "../realTimeVis/charts/LineGraphComponent";
import RadarGraphComponent from "../realTimeVis/charts/RadarGraphComponent";
import DoughnutGraphComponent from "../realTimeVis/charts/DoughnutGraphComponent";
import PolarAreaGraphComponent from "../realTimeVis/charts/PolarAreaGraphComponent";
export const DraggableWidget = ({ widget }: { widget: any }) => {
export const DraggableWidget = ({
widget,
hiddenPanels, // Add this prop to track hidden panels
index, onReorder
}: {
widget: any;
hiddenPanels: string[]; // Array of hidden panel names
index: number; onReorder: (fromIndex: number, toIndex: number) => void
}) => {
const { selectedChartId, setSelectedChartId } = useWidgetStore();
const handlePointerDown = () => {
@ -12,69 +24,139 @@ export const DraggableWidget = ({ widget }: { widget: any }) => {
}
};
// Determine if the widget's panel is hidden
const isPanelHidden = hiddenPanels.includes(widget.panel);
const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
event.dataTransfer.setData('text/plain', index.toString()); // Store the index of the dragged widget
};
const handleDragEnter = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault(); // Allow drop
};
const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault(); // Allow drop
};
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
const fromIndex = parseInt(event.dataTransfer.getData('text/plain'), 10); // Get the dragged widget's index
const toIndex = index; // The index of the widget where the drop occurred
if (fromIndex !== toIndex) {
onReorder(fromIndex, toIndex); // Call the reorder function passed as a prop
}
};
return (
<>
<div
draggable
key={widget.id}
className={`chart-container ${
selectedChartId?.id === widget.id && "activeChart"
}`}
className={`chart-container ${selectedChartId?.id === widget.id && "activeChart"
}`}
onPointerDown={handlePointerDown}
onDragStart={handleDragStart}
onDragEnter={handleDragEnter}
onDragOver={handleDragOver}
onDrop={handleDrop}
style={{
opacity: isPanelHidden ? 0 : 1, // Set opacity to 0 if the panel is hidden
pointerEvents: isPanelHidden ? "none" : "auto", // Disable interaction when hidden
}}
>
{widget.type === "progress" ? (
// <ProgressCard title={widget.title} data={widget.data} />
<></>
) : (
<>
{widget.type === "line" && (
<LineGraphComponent
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 === "bar" && (
<BarGraphComponent
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 === "pie" && (
<PieGraphComponent
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",
}}
/>
)}
</>
{/* Render charts based on widget type */}
{widget.type === "progress" && (
<ProgressCard title={widget.title} data={widget.data} />
)}
{widget.type === "line" && (
<LineGraphComponent
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 === "bar" && (
<BarGraphComponent
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 === "radar" && (
<RadarGraphComponent
type={widget.type}
title={widget.title}
fontSize={widget.fontSize}
fontWeight={widget.fontWeight}
data={widget.data.measurements.map((item: any) => item.fields)}
/>
)} */}
{widget.type === "pie" && (
<PieGraphComponent
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 === "doughnut" && (
<DoughnutGraphComponent
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
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

@ -0,0 +1,89 @@
// import { useState } from "react";
// import { useThree } from "@react-three/fiber";
// import * as THREE from "three";
// const DroppedObjects = () => {
// const { camera } = useThree(); // Now inside Canvas ✅
// const [objects, setObjects] = useState<{ id: number; position: [number, number, number] }[]>([]);
// // Function to convert drop event into 3D position
// const handleDrop = (event: DragEvent) => {
// event.preventDefault();
// const data = event.dataTransfer?.getData("text/plain");
// if (!data) return;
// try {
// const cardData = JSON.parse(data);
// if (!cardData.className.includes("floating total-card")) {
// console.log("Drop rejected: Incorrect element.");
// return;
// }
// // Convert 2D drop position to 3D world coordinates
// const x = (event.clientX / window.innerWidth) * 2 - 1;
// const y = -(event.clientY / window.innerHeight) * 2 + 1;
// // Raycasting to determine the drop position in 3D
// const raycaster = new THREE.Raycaster();
// const mouseVector = new THREE.Vector2(x, y);
// raycaster.setFromCamera(mouseVector, camera);
// // Intersect with a ground plane (assume y = 0)
// const groundPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
// const intersection = new THREE.Vector3();
// raycaster.ray.intersectPlane(groundPlane, intersection);
// console.log("Spawn Object at:", intersection);
// // Add the dropped object to the scene state
// setObjects((prev) => [...prev, { id: Date.now(), position: [intersection.x, intersection.y, intersection.z] }]);
// } catch (error) {
// console.error("Invalid data:", error);
// }
// };
// return (
// <group>
// {/* Render dropped objects as green boxes */}
// {objects.map((obj) => (
// <mesh key={obj.id} position={obj.position}>
// <boxGeometry args={[1, 1, 1]} />
// <meshStandardMaterial color="green" />
// </mesh>
// ))}
// </group>
// );
// };
import { Html } from "@react-three/drei";
import { useDroppedObjectsStore } from "../../../store/store";
const DroppedObjects: React.FC = () => {
const objects = useDroppedObjectsStore((state) => state.objects); // Get objects from Zustand store
console.log('objects: ', objects);
return (
<>
{objects.map((obj, index) => (
<group key={index} position={[Math.random() * 5, Math.random() * 5, 0]}>
<Html wrapperClass={obj.className}>
<div style={{ padding: "10px", background: "#fff", borderRadius: "6px" }}>
<div className="header">{obj.header}</div>
<div className="data-values">
<div className="value">{obj.value}</div>
<div className="per">{obj.per}</div>
</div>
</div>
</Html>
</group>
))}
</>
);
};
export default DroppedObjects;

View File

@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useRef, useState } from "react";
import { useWidgetStore } from "../../../store/useWidgetStore";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
import { DraggableWidget } from "./DraggableWidget";
import { arrayMove } from "@dnd-kit/sortable";
type Side = "top" | "bottom" | "left" | "right";
@ -19,6 +20,9 @@ interface PanelProps {
activeSides: Side[];
panelOrder: Side[];
lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[]
widgets: Widget[];
};
setSelectedZone: React.Dispatch<
@ -27,20 +31,30 @@ interface PanelProps {
activeSides: Side[];
panelOrder: Side[];
lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[]
widgets: Widget[];
}>
>;
hiddenPanels: string[];
}
const generateUniqueId = () =>
`${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const Panel: React.FC<PanelProps> = ({ selectedZone, setSelectedZone }) => {
const Panel: React.FC<PanelProps> = ({
selectedZone,
setSelectedZone,
hiddenPanels,
}) => {
const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({});
const [panelDimensions, setPanelDimensions] = useState<{
[side in Side]?: { width: number; height: number };
}>({});
const { isPlaying } = usePlayButtonStore();
const getPanelStyle = useMemo(
() => (side: Side) => {
const currentIndex = selectedZone.panelOrder.indexOf(side);
@ -49,87 +63,86 @@ const Panel: React.FC<PanelProps> = ({ selectedZone, setSelectedZone }) => {
const rightActive = previousPanels.includes("right");
const topActive = previousPanels.includes("top");
const bottomActive = previousPanels.includes("bottom");
const panelSize = isPlaying ? 300 : 210;
switch (side) {
case "top":
case "bottom":
return {
width: `calc(100% - ${
(leftActive ? 204 : 0) + (rightActive ? 204 : 0)
}px)`,
left: leftActive ? "204px" : "0",
right: rightActive ? "204px" : "0",
width: `calc(100% - ${(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0)
}px)`,
height: `${panelSize - 2}px`,
left: leftActive ? `${panelSize}px` : "0",
right: rightActive ? `${panelSize}px` : "0",
[side]: "0",
height: "200px",
};
case "left":
case "right":
return {
height: `calc(100% - ${
(topActive ? 204 : 0) + (bottomActive ? 204 : 0)
}px)`,
top: topActive ? "204px" : "0",
bottom: bottomActive ? "204px" : "0",
width: `${panelSize - 2}px`,
height: `calc(100% - ${(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0)
}px)`,
top: topActive ? `${panelSize}px` : "0",
bottom: bottomActive ? `${panelSize}px` : "0",
[side]: "0",
width: "200px",
};
default:
return {};
}
},
[selectedZone.panelOrder]
[selectedZone.panelOrder, isPlaying]
);
const handleDrop = (e: React.DragEvent, panel: Side) => {
e.preventDefault();
const { draggedAsset } = useWidgetStore.getState();
if (!draggedAsset) return;
if (isPanelLocked(panel)) return;
const currentWidgetsCount = getCurrentWidgetCount(panel);
const maxCapacity = calculatePanelCapacity(panel);
if (currentWidgetsCount >= maxCapacity) return;
console.log('draggedAsset: ', draggedAsset);
console.log('panel: ', panel);
addWidgetToPanel(draggedAsset, panel);
};
// Helper functions
const isPanelLocked = (panel: Side) =>
const isPanelLocked = (panel: Side) =>
selectedZone.lockedPanels.includes(panel);
const getCurrentWidgetCount = (panel: Side) =>
selectedZone.widgets.filter(w => w.panel === panel).length;
const getCurrentWidgetCount = (panel: Side) =>
selectedZone.widgets.filter((w) => w.panel === panel).length;
const calculatePanelCapacity = (panel: Side) => {
const CHART_WIDTH = 200;
const CHART_HEIGHT = 200;
const CHART_WIDTH = 150;
const CHART_HEIGHT = 150;
const FALLBACK_HORIZONTAL_CAPACITY = 5;
const FALLBACK_VERTICAL_CAPACITY = 3;
const dimensions = panelDimensions[panel];
if (!dimensions) {
return panel === "top" || panel === "bottom"
return panel === "top" || panel === "bottom"
? FALLBACK_HORIZONTAL_CAPACITY
: FALLBACK_VERTICAL_CAPACITY;
}
return panel === "top" || panel === "bottom"
? Math.floor(dimensions.width / CHART_WIDTH)
: Math.floor(dimensions.height / CHART_HEIGHT);
};
const addWidgetToPanel = (asset: any, panel: Side) => {
const newWidget = {
...asset,
id: generateUniqueId(),
panel,
};
setSelectedZone(prev => ({
setSelectedZone((prev) => ({
...prev,
widgets: [...prev.widgets, newWidget]
widgets: [...prev.widgets, newWidget],
}));
};
@ -159,8 +172,34 @@ const Panel: React.FC<PanelProps> = ({ selectedZone, setSelectedZone }) => {
};
}, [selectedZone.activeSides]);
const { isPlaying } = usePlayButtonStore();
const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => {
if (!selectedZone) return; // Ensure selectedZone is not null
console.log('selectedZone: ', selectedZone);
setSelectedZone((prev) => {
if (!prev) return prev; // Ensure prev is not null
// Filter widgets for the specified panel
const widgetsInPanel = prev.widgets.filter((w) => w.panel === panel);
// Reorder widgets within the same panel
const reorderedWidgets = arrayMove(widgetsInPanel, fromIndex, toIndex);
// Merge the reordered widgets back into the full list while preserving the order
const updatedWidgets = prev.widgets
.filter((widget) => widget.panel !== panel) // Keep widgets from other panels
.concat(reorderedWidgets); // Add the reordered widgets for the specified panel
return {
...prev,
widgets: updatedWidgets,
};
});
};
return (
<>
{selectedZone.activeSides.map((side) => (
@ -187,11 +226,18 @@ const Panel: React.FC<PanelProps> = ({ selectedZone, setSelectedZone }) => {
opacity: selectedZone.lockedPanels.includes(side) ? "0.8" : "1",
}}
>
<>{}</>
{selectedZone.widgets
.filter((w) => w.panel === side)
.map((widget) => (
<DraggableWidget widget={widget} key={widget.id} />
.map((widget, index) => (
<DraggableWidget
hiddenPanels={hiddenPanels}
widget={widget}
key={widget.id}
index={index}
onReorder={(fromIndex, toIndex) =>
handleReorder(fromIndex, toIndex, side)
}
/>
))}
</div>
</div>
@ -201,3 +247,5 @@ const Panel: React.FC<PanelProps> = ({ selectedZone, setSelectedZone }) => {
};
export default Panel;

View File

@ -6,76 +6,117 @@ import { useSelectedZoneStore } from "../../../store/useZoneStore";
import DisplayZone from "./DisplayZone";
import Scene from "../../../modules/scene/scene";
import useModuleStore from "../../../store/useModuleStore";
import { useDroppedObjectsStore, useZones } from "../../../store/store";
import DroppedObjects from "./DroppedFloatingWidgets";
type Side = "top" | "bottom" | "left" | "right";
interface Widget {
type FormattedZoneData = Record<
string,
{
activeSides: Side[];
panelOrder: Side[];
lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[]
widgets: Widget[];
}
>;
type Widget = {
id: string;
type: string;
title: string;
panel: Side;
data: any;
}
};
const RealTimeVisulization: React.FC = () => {
const [hiddenPanels, setHiddenPanels] = React.useState<Side[]>([]);
const containerRef = useRef<HTMLDivElement>(null);
const [zonesData, setZonesData] = useState<{
[key: string]: {
activeSides: Side[];
panelOrder: Side[];
lockedPanels: Side[];
widgets: Widget[];
};
}>({
"Manufacturing unit": {
activeSides: [],
panelOrder: [],
lockedPanels: [],
widgets: [],
},
"Assembly unit": {
activeSides: [],
panelOrder: [],
lockedPanels: [],
widgets: [],
},
"Packing unit": {
activeSides: [],
panelOrder: [],
lockedPanels: [],
widgets: [],
},
Warehouse: {
activeSides: [],
panelOrder: [],
lockedPanels: [],
widgets: [],
},
Inventory: {
activeSides: [],
panelOrder: [],
lockedPanels: [],
widgets: [],
},
});
const { isPlaying } = usePlayButtonStore();
const { activeModule } = useModuleStore();
const [droppedObjects, setDroppedObjects] = useState<any[]>([]);
const [zonesData, setZonesData] = useState<FormattedZoneData>({});
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const { zones } = useZones()
useEffect(() => {
setZonesData((prev) => ({
...prev,
[selectedZone.zoneName]: selectedZone,
}));
const data = Array.isArray(zones) ? zones : [];
const formattedData = data.reduce<FormattedZoneData>((acc, zone) => {
acc[zone.zoneName] = {
activeSides: [],
panelOrder: [],
lockedPanels: [],
zoneId: zone.zoneId,
zoneViewPortTarget: zone.viewPortCenter,
zoneViewPortPosition: zone.viewPortposition,
widgets: [],
};
return acc;
}, {});
setZonesData(formattedData);
}, [zones]);
useEffect(() => {
setZonesData((prev) => {
if (!selectedZone) return prev;
return {
...prev,
[selectedZone.zoneName]: {
...prev[selectedZone.zoneName], // Keep existing properties
activeSides: selectedZone.activeSides || [],
panelOrder: selectedZone.panelOrder || [],
lockedPanels: selectedZone.lockedPanels || [],
zoneId: selectedZone.zoneId || "",
zoneViewPortTarget: selectedZone.zoneViewPortTarget || [],
zoneViewPortPosition: selectedZone.zoneViewPortPosition || [],
widgets: selectedZone.widgets || [],
},
};
});
}, [selectedZone]);
// const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
// console.log("Drop event fired! ✅");
// event.preventDefault();
// const data = event.dataTransfer.getData("text/plain");
// if (!data) {
// console.log("❌ No data received on drop!");
// return;
// }
// try {
// const droppedData = JSON.parse(data);
// console.log("✅ Dropped Data:", droppedData);
// console.log('droppedData: ', droppedData);
// setDroppedObjects((prev) => [...prev, droppedData]); // ✅ Add to state
// console.log(droppedObjects);
// } catch (error) {
// console.error("❌ Error parsing dropped data:", error);
// }
// };
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
const data = event.dataTransfer.getData("text/plain"); // Use "text/plain" to match the drag event
if (data) {
const droppedData = JSON.parse(data);
useDroppedObjectsStore.getState().addObject(droppedData); // Add to Zustand store
}
};
return (
<div
ref={containerRef}
id="real-time-vis-canvas"
className="realTime-viz canvas"
className={`realTime-viz canvas ${isPlaying ? "playingFlase" : ""}`}
style={{
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
@ -89,7 +130,10 @@ const RealTimeVisulization: React.FC = () => {
width: "100%",
borderRadius: isPlaying || activeModule !== "visualization" ? "" : "6px",
}}
onDrop={(event) => handleDrop(event)}
onDragOver={(event) => event.preventDefault()}
>
<Scene />
</div>
{activeModule === "visualization" && (
@ -100,7 +144,7 @@ const RealTimeVisulization: React.FC = () => {
setSelectedZone={setSelectedZone}
/>
{!isPlaying && (
{!isPlaying && selectedZone?.zoneName !== "" && (
<AddButtons
hiddenPanels={hiddenPanels}
setHiddenPanels={setHiddenPanels}
@ -110,8 +154,10 @@ const RealTimeVisulization: React.FC = () => {
)}
<Panel
hiddenPanels={hiddenPanels}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
</>
)}

View File

@ -0,0 +1,107 @@
import { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import * as THREE from "three";
import { useSelectedZoneStore } from "../../../store/useZoneStore";
import { useEditPosition, usezonePosition, usezoneTarget } from "../../../store/store";
export default function ZoneCentreTarget() {
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const [previousZoneCentre, setPreviousZoneCentre] = useState<number[] | null>(null);
const sphereRef = useRef<THREE.Mesh>(null);
const { camera, controls }: any = useThree();
const { zonePosition, setZonePosition } = usezonePosition();
const { zoneTarget, setZoneTarget } = usezoneTarget();
const { Edit, setEdit } = useEditPosition();
useEffect(() => {
if (
selectedZone.zoneViewPortTarget &&
JSON.stringify(previousZoneCentre) !== JSON.stringify(selectedZone.zoneViewPortTarget)
) {
setPreviousZoneCentre(selectedZone.zoneViewPortTarget);
}
}, [selectedZone.zoneViewPortTarget, previousZoneCentre]);
const centrePoint = useMemo(() => {
if (!previousZoneCentre || !selectedZone.zoneViewPortTarget) return null;
return previousZoneCentre.map((value, index) =>
(value + selectedZone.zoneViewPortTarget[index]) / 2
);
}, [previousZoneCentre, selectedZone.zoneViewPortTarget]);
useEffect(() => {
if (selectedZone.zoneName !== "") {
if (sphereRef.current) {
sphereRef.current.position.set(selectedZone.zoneViewPortTarget[0], selectedZone.zoneViewPortTarget[1], selectedZone.zoneViewPortTarget[2]);
}
if (centrePoint) {
if (centrePoint.length > 0) {
let camPosition = new THREE.Vector3(...selectedZone.zoneViewPortPosition);
let CamTarget = new THREE.Vector3(...selectedZone.zoneViewPortTarget);
const direction = new THREE.Vector3().subVectors(CamTarget, camPosition).normalize();
const worldUp = new THREE.Vector3(0, 0, 1);
const right = new THREE.Vector3().crossVectors(worldUp, direction).normalize();
const up = new THREE.Vector3().crossVectors(direction, right).normalize();
const offsetPosition = up.clone().multiplyScalar(20);
camPosition.add(offsetPosition);
const setCam = async () => {
controls.setLookAt(centrePoint[0], 100, centrePoint[2], ...centrePoint, true);
setTimeout(() => {
controls?.setLookAt(
...camPosition.toArray(),
selectedZone.zoneViewPortTarget[0],
selectedZone.zoneViewPortTarget[1],
selectedZone.zoneViewPortTarget[2],
true
);
}, 400)
};
setCam();
} else {
let camPosition = new THREE.Vector3(...selectedZone.zoneViewPortPosition);
let CamTarget = new THREE.Vector3(...selectedZone.zoneViewPortTarget);
const direction = new THREE.Vector3().subVectors(CamTarget, camPosition).normalize();
const worldUp = new THREE.Vector3(0, 0, 1);
const right = new THREE.Vector3().crossVectors(worldUp, direction).normalize();
const up = new THREE.Vector3().crossVectors(direction, right).normalize();
const offsetPosition = up.clone().multiplyScalar(20);
camPosition.add(offsetPosition);
const setCam = async () => {
controls?.setLookAt(
...camPosition.toArray(),
selectedZone.zoneViewPortTarget[0],
selectedZone.zoneViewPortTarget[1],
selectedZone.zoneViewPortTarget[2],
true
);
};
setCam();
}
}
}
}, [selectedZone.zoneViewPortTarget]);
useFrame(() => {
if (Edit) {
setZonePosition([controls.getPosition().x, controls.getPosition().y, controls.getPosition().z])
setZoneTarget([controls.getTarget().x, controls.getTarget().y, controls.getTarget().z])
}
})
return (
<> </>
);
}

View File

@ -1,99 +1,213 @@
// import React, { useState, useRef, useEffect } from "react";
// // Dropdown Item Component
// const DropdownItem = ({
// label,
// href,
// onClick,
// }: {
// label: string;
// href?: string;
// onClick?: () => void;
// }) => (
// <a
// href={href || "#"}
// className="dropdown-item"
// onClick={(e) => {
// e.preventDefault();
// onClick?.();
// }}
// >
// {label}
// </a>
// );
// // Nested Dropdown Component
// const NestedDropdown = ({
// label,
// children,
// onSelect,
// }: {
// label: string;
// children: React.ReactNode;
// onSelect: (selectedLabel: string) => void;
// }) => {
// const [open, setOpen] = useState(false);
// return (
// <div className="nested-dropdown">
// {/* Dropdown Trigger */}
// <div
// className={`dropdown-trigger ${open ? "open" : ""}`}
// onClick={() => setOpen(!open)} // Toggle submenu on click
// >
// {label} <span className="icon">{open ? "▼" : "▶"}</span>
// </div>
// {/* Submenu */}
// {open && (
// <div className="submenu">
// {React.Children.map(children, (child) => {
// if (React.isValidElement(child)) {
// // Clone the element and pass the `onSelect` prop only if it's expected
// return React.cloneElement(child as React.ReactElement<any>, { onSelect });
// }
// return child; // Return non-element children as-is
// })}
// </div>
// )}
// </div>
// );
// };
// // Recursive Function to Render Nested Data
// const renderNestedData = (
// data: Record<string, any>,
// onSelect: (selectedLabel: string) => void
// ) => {
// return Object.entries(data).map(([key, value]) => {
// if (typeof value === "object" && !Array.isArray(value)) {
// // If the value is an object, render it as a nested dropdown
// return (
// <NestedDropdown key={key} label={key} onSelect={onSelect}>
// {renderNestedData(value, onSelect)}
// </NestedDropdown>
// );
// } else if (Array.isArray(value)) {
// // If the value is an array, render each item as a dropdown item
// return value.map((item, index) => (
// <DropdownItem key={index} label={item} onClick={() => onSelect(item)} />
// ));
// } else {
// // If the value is a simple string, render it as a dropdown item
// return (
// <DropdownItem key={key} label={value} onClick={() => onSelect(value)} />
// );
// }
// });
// };
// // Main Multi-Level Dropdown Component
// const MultiLevelDropdown = ({ data }: { data: Record<string, any> }) => {
// const [open, setOpen] = useState(false);
// const [selectedLabel, setSelectedLabel] = useState("Dropdown trigger");
// const dropdownRef = useRef<HTMLDivElement>(null);
// // Handle outer click to close the dropdown
// useEffect(() => {
// const handleClickOutside = (event: MouseEvent) => {
// if (
// dropdownRef.current &&
// !dropdownRef.current.contains(event.target as Node)
// ) {
// setOpen(false);
// }
// };
// document.addEventListener("mousedown", handleClickOutside);
// return () => {
// document.removeEventListener("mousedown", handleClickOutside);
// };
// }, []);
// // Handle selection of an item
// const handleSelect = (selectedLabel: string) => {
// setSelectedLabel(selectedLabel); // Update the dropdown trigger text
// setOpen(false); // Close the dropdown
// };
// return (
// <div className="multi-level-dropdown" ref={dropdownRef}>
// {/* Dropdown Trigger Button */}
// <button
// className={`dropdown-button ${open ? "open" : ""}`}
// onClick={() => setOpen(!open)} // Toggle main menu on click
// >
// {selectedLabel} <span className="icon">▾</span>
// </button>
// {/* Dropdown Menu */}
// {open && (
// <div className="dropdown-menu">
// <div className="dropdown-content">
// {renderNestedData(data, handleSelect)}
// </div>
// </div>
// )}
// </div>
// );
// };
// export default MultiLevelDropdown;
import React, { useState, useRef, useEffect } from "react";
// Dropdown Item Component
const DropdownItem = ({
label,
href,
onClick,
}: {
label: string;
href?: string;
onClick?: () => void;
onClick: () => void;
}) => (
<a
href={href || "#"}
className="dropdown-item"
onClick={(e) => {
e.preventDefault();
onClick?.();
}}
>
<div className="dropdown-item" onClick={onClick}>
{label}
</a>
</div>
);
// Nested Dropdown Component
const NestedDropdown = ({
label,
children,
fields,
onSelect,
}: {
label: string;
children: React.ReactNode;
onSelect: (selectedLabel: string) => void;
fields: string[];
onSelect: (selectedData: { name: string; fields: string }) => void;
}) => {
const [open, setOpen] = useState(false);
return (
<div className="nested-dropdown">
{/* Dropdown Trigger */}
<div
className={`dropdown-trigger ${open ? "open" : ""}`}
onClick={() => setOpen(!open)} // Toggle submenu on click
onClick={() => setOpen(!open)}
>
{label} <span className="icon">{open ? "▼" : "▶"}</span>
</div>
{/* Submenu */}
{open && (
<div className="submenu">
{React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
// Clone the element and pass the `onSelect` prop only if it's expected
return React.cloneElement(child as React.ReactElement<any>, { onSelect });
}
return child; // Return non-element children as-is
})}
{fields.map((field) => (
<DropdownItem
key={field}
label={field}
onClick={() => onSelect({ name: label, fields: field })}
/>
))}
</div>
)}
</div>
);
};
// Recursive Function to Render Nested Data
const renderNestedData = (
data: Record<string, any>,
onSelect: (selectedLabel: string) => void
) => {
return Object.entries(data).map(([key, value]) => {
if (typeof value === "object" && !Array.isArray(value)) {
// If the value is an object, render it as a nested dropdown
return (
<NestedDropdown key={key} label={key} onSelect={onSelect}>
{renderNestedData(value, onSelect)}
</NestedDropdown>
);
} else if (Array.isArray(value)) {
// If the value is an array, render each item as a dropdown item
return value.map((item, index) => (
<DropdownItem key={index} label={item} onClick={() => onSelect(item)} />
));
} else {
// If the value is a simple string, render it as a dropdown item
return (
<DropdownItem key={key} label={value} onClick={() => onSelect(value)} />
);
}
});
};
// Props type for MultiLevelDropdown
interface MultiLevelDropdownProps {
data: Record<string, any>;
onSelect: (selectedData: { name: string; fields: string }) => void;
onUnselect: () => void;
selectedValue?: { name: string; fields: string };
}
// Main Multi-Level Dropdown Component
const MultiLevelDropdown = ({ data }: { data: Record<string, any> }) => {
const MultiLevelDropdown = ({
data,
onSelect,
onUnselect,
selectedValue
}: MultiLevelDropdownProps) => {
const [open, setOpen] = useState(false);
const [selectedLabel, setSelectedLabel] = useState("Dropdown trigger");
const dropdownRef = useRef<HTMLDivElement>(null);
// Handle outer click to close the dropdown
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
@ -103,34 +217,51 @@ const MultiLevelDropdown = ({ data }: { data: Record<string, any> }) => {
setOpen(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);
// Handle selection of an item
const handleSelect = (selectedLabel: string) => {
setSelectedLabel(selectedLabel); // Update the dropdown trigger text
setOpen(false); // Close the dropdown
// Handle item selection
const handleItemSelect = (selectedData: { name: string; fields: string }) => {
onSelect(selectedData);
setOpen(false);
};
// Handle unselect
const handleItemUnselect = () => {
onUnselect();
setOpen(false);
};
// Determine the display label
const displayLabel = selectedValue
? `${selectedValue.name} - ${selectedValue.fields}`
: "Dropdown trigger";
return (
<div className="multi-level-dropdown" ref={dropdownRef}>
{/* Dropdown Trigger Button */}
<button
className={`dropdown-button ${open ? "open" : ""}`}
onClick={() => setOpen(!open)} // Toggle main menu on click
onClick={() => setOpen(!open)}
>
{selectedLabel} <span className="icon"></span>
{displayLabel} <span className="icon"></span>
</button>
{/* Dropdown Menu */}
{open && (
<div className="dropdown-menu">
<div className="dropdown-content">
{renderNestedData(data, handleSelect)}
{/* Unselect Option */}
<DropdownItem label="Unselect" onClick={handleItemUnselect} />
{/* Nested Dropdown Items */}
{Object.entries(data).map(([key, value]) => (
<NestedDropdown
key={key}
label={key}
fields={Object.keys(value)}
onSelect={handleItemSelect}
/>
))}
</div>
</div>
)}
@ -138,4 +269,5 @@ const MultiLevelDropdown = ({ data }: { data: Record<string, any> }) => {
);
};
export default MultiLevelDropdown;
export default MultiLevelDropdown;

View File

@ -1,4 +1,4 @@
import React, { useState, useRef } from "react";
import React, { useState, useRef, useEffect } from "react";
interface RenameInputProps {
value: string;
@ -9,6 +9,9 @@ const RenameInput: React.FC<RenameInputProps> = ({ value, onRename }) => {
const [isEditing, setIsEditing] = useState(false);
const [text, setText] = useState(value);
const inputRef = useRef<HTMLInputElement | null>(null);
useEffect(() => {
setText(value); // Ensure state updates when parent value changes
}, [value]);
const handleDoubleClick = () => {
setIsEditing(true);

View File

@ -1,7 +1,9 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import List from "./List";
import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons";
import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect";
import { useZones } from "../../../store/store";
import { useSelectedZoneStore } from "../../../store/useZoneStore";
interface DropDownListProps {
value?: string; // Value to display in the DropDownList
@ -12,6 +14,7 @@ interface DropDownListProps {
kebabMenuItems?: { id: string; name: string }[]; // Items for the KebabMenuList
defaultOpen?: boolean; // Determines if the dropdown list should be open by default
listType?: string; // Type of list to display
remove?: boolean;
}
const DropDownList: React.FC<DropDownListProps> = ({
@ -27,12 +30,25 @@ const DropDownList: React.FC<DropDownListProps> = ({
],
defaultOpen = false,
listType = "default",
remove,
}) => {
const [isOpen, setIsOpen] = useState<boolean>(defaultOpen);
const { zones, setZones } = useZones()
const handleToggle = () => {
setIsOpen((prev) => !prev); // Toggle the state
};
const [zoneDataList, setZoneDataList] = useState<{ id: string; name: string }[]>([]);
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
useEffect(() => {
const value = (zones || []).map((val: { zoneId: string; zoneName: string }) => ({
id: val.zoneId,
name: val.zoneName
}));
setZoneDataList(prev => (JSON.stringify(prev) !== JSON.stringify(value) ? value : prev));
}, [zones]);
return (
<div className="dropdown-list-container">
@ -67,7 +83,7 @@ const DropDownList: React.FC<DropDownListProps> = ({
</div>
{isOpen && (
<div className="lists-container">
{listType === "default" && <List items={items} />}
{listType === "default" && <List items={items} remove={remove} />}
{listType === "outline" && (
<>
<DropDownList
@ -79,7 +95,7 @@ const DropDownList: React.FC<DropDownListProps> = ({
value="Zones"
showKebabMenu={false}
showAddIcon={false}
items={[]}
items={zoneDataList}
/>
</>
)}

View File

@ -1,13 +1,38 @@
import React from "react";
import RenameInput from "../inputs/RenameInput";
import { EyeIcon, LockIcon, RmoveIcon } from "../../icons/ExportCommonIcons";
import { useSelectedZoneStore } from "../../../store/useZoneStore";
import { getZoneData } from "../../../services/realTimeVisulization/zoneData/getZones";
import { useSubModuleStore } from "../../../store/useModuleStore";
interface ListProps {
items?: { id: string; name: string }[]; // Optional array of items to render
placeholder?: string; // Optional placeholder text
remove?: boolean;
}
const List: React.FC<ListProps> = ({ items = [] }) => {
const List: React.FC<ListProps> = ({ items = [], remove }) => {
const { setSelectedZone } = useSelectedZoneStore();
const { setSubModule } = useSubModuleStore();
async function handleSelectZone(id: string) {
setSubModule("zoneProperties")
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
let response = await getZoneData(id, organization)
setSelectedZone({
zoneName: response?.zoneName,
activeSides: response?.activeSides || [],
panelOrder: response?.panelOrder || [],
lockedPanels: response?.lockedPanels || [],
widgets: response?.widgets || [],
zoneId: response?.zoneId,
zoneViewPortTarget: response?.viewPortCenter || [],
zoneViewPortPosition:
response?.viewPortposition || [],
});
}
return (
<>
{items.length > 0 ? (
@ -15,7 +40,7 @@ const List: React.FC<ListProps> = ({ items = [] }) => {
{items.map((item, index) => (
<li key={index} className="list-container">
<div className="list-item">
<div className="value">
<div className="value" onClick={() => handleSelectZone(item.id)}>
<RenameInput value={item.name} />
</div>
<div className="options-container">
@ -25,9 +50,11 @@ const List: React.FC<ListProps> = ({ items = [] }) => {
<div className="visibe option">
<EyeIcon isClosed />
</div>
<div className="remove option">
<RmoveIcon />
</div>
{remove && (
<div className="remove option">
<RmoveIcon />
</div>
)}
</div>
</div>
</li>

View File

@ -1,5 +1,107 @@
import { useMemo } from "react";
import { Line } from "react-chartjs-2";
// import { useMemo } from "react";
// import { Line } from "react-chartjs-2";
// interface ChartComponentProps {
// type: any;
// title: string;
// fontFamily?: string;
// fontSize?: string;
// fontWeight?: "Light" | "Regular" | "Bold";
// data: any;
// }
// const LineGraphComponent = ({
// title,
// fontFamily,
// fontSize,
// fontWeight = "Regular",
// }: ChartComponentProps) => {
// // Memoize Font Weight Mapping
// const chartFontWeightMap = useMemo(
// () => ({
// Light: "lighter" as const,
// Regular: "normal" as const,
// Bold: "bold" as const,
// }),
// []
// );
// // Parse and Memoize Font Size
// const fontSizeValue = useMemo(
// () => (fontSize ? parseInt(fontSize) : 12),
// [fontSize]
// );
// // Determine and Memoize Font Weight
// const fontWeightValue = useMemo(
// () => chartFontWeightMap[fontWeight],
// [fontWeight, chartFontWeightMap]
// );
// // Memoize Chart Font Style
// const chartFontStyle = useMemo(
// () => ({
// family: fontFamily || "Arial",
// size: fontSizeValue,
// weight: fontWeightValue,
// }),
// [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: true, // This hides the x-axis labels
// },
// },
// },
// }),
// [title, chartFontStyle]
// );
// 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,
// },
// ],
// };
// return <Line data={chartData} options={options} />;
// };
// export default LineGraphComponent;
import React, { useEffect, useRef, useMemo, useState } from "react";
import { Chart } from "chart.js/auto";
import { useThemeStore } from "../../../../store/useThemeStore";
import io from "socket.io-client";
import { Line } from 'react-chartjs-2';
import useChartStore from "../../../../store/useChartStore";
// WebSocket Connection
// const socket = io("http://localhost:5000"); // Adjust to your backend URL
interface ChartComponentProps {
type: any;
@ -11,86 +113,153 @@ interface ChartComponentProps {
}
const LineGraphComponent = ({
type,
title,
fontFamily,
fontSize,
fontWeight = "Regular",
data,
}: ChartComponentProps) => {
// Memoize Font Weight Mapping
const chartFontWeightMap = useMemo(
() => ({
Light: "lighter" as const,
Regular: "normal" as const,
Bold: "bold" as const,
}),
[]
);
const canvasRef = useRef<HTMLCanvasElement>(null);
const { themeColor } = useThemeStore();
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
labels: [],
datasets: [],
});
// Parse and Memoize Font Size
const fontSizeValue = useMemo(
() => (fontSize ? parseInt(fontSize) : 12),
[fontSize]
);
// Determine and Memoize Font Weight
const fontWeightValue = useMemo(
() => chartFontWeightMap[fontWeight],
[fontWeight, chartFontWeightMap]
);
// Memoize Chart Font Style
const chartFontStyle = useMemo(
() => ({
family: fontFamily || "Arial",
size: fontSizeValue,
weight: fontWeightValue,
}),
[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: true, // This hides the x-axis labels
// Memoize Theme Colors to Prevent Unnecessary Recalculations
const buttonActionColor = useMemo(
() => themeColor[0] || "#5c87df",
[themeColor]
);
const buttonAbortColor = useMemo(
() => themeColor[1] || "#ffffff",
[themeColor]
);
// Memoize Font Weight Mapping
const chartFontWeightMap = useMemo(
() => ({
Light: "lighter" as const,
Regular: "normal" as const,
Bold: "bold" as const,
}),
[]
);
// Parse and Memoize Font Size
const fontSizeValue = useMemo(
() => (fontSize ? parseInt(fontSize) : 12),
[fontSize]
);
// Determine and Memoize Font Weight
const fontWeightValue = useMemo(
() => chartFontWeightMap[fontWeight],
[fontWeight, chartFontWeightMap]
);
// Memoize Chart Font Style
const chartFontStyle = useMemo(
() => ({
family: fontFamily || "Arial",
size: fontSizeValue,
weight: fontWeightValue,
}),
[fontFamily, fontSizeValue, fontWeightValue]
);
// Memoize Chart Data
// const data = useMemo(() => propsData, [propsData]);
// Memoize Chart Options
const options = useMemo(
() => ({
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: title,
font: chartFontStyle,
},
legend: {
display: false,
},
},
},
}),
[title, chartFontStyle]
);
scales: {
x: {
ticks: {
display: true, // This hides the x-axis labels
},
},
},
}),
[title, chartFontStyle]
);
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
const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
useEffect(() => {
if ( measurements.length > 0 ) {
const socket = io("http://192.168.0.192:5010");
var inputes = {
measurements: measurements,
duration: duration,
interval: 1000,
}
console.log('graphHHHHHHHHHHHHHHHHHHHHHHHHHHHHH',inputes);
// Start stream
const startStream = () => {
socket.emit("lineInput", inputes);
}
socket.on('connect', startStream);
socket.on("lineOutput", (response) => {
const responceData = response.data;
console.log("Received data:", responceData);
// Extract timestamps and values
const labels = responceData.time;
const datasets = data.measurements.map((measurement: any) => ({
label: `${measurement.name}.${measurement.fields}`,
data: responceData[`${measurement.name}.${measurement.fields}`]?.values || [],
backgroundColor: themeColor[0] || "#5c87df",
borderColor: themeColor[1] || "#ffffff",
borderWidth: 2,
fill: false,
},
],
};
// fill: false,
}));
setChartData({ labels, datasets });
});
return () => {
socket.off("lineOutput");
socket.emit("stop_stream"); // Stop streaming when component unmounts
};
}
}, [measurements, duration]);
// useEffect(() => {
// if (!canvasRef.current) return;
// const ctx = canvasRef.current.getContext("2d");
// if (!ctx) return;
// const chart = new Chart(ctx, {
// type,
// data: chartData,
// options: options,
// });
// return () => chart.destroy();
// }, [chartData, type, title]);
return <Line data={chartData} options={options} />;
};
export default LineGraphComponent;
// like this
export default LineGraphComponent;

View File

@ -1,3 +1,5 @@
import { StockIncreseIcon } from "../../../icons/RealTimeVisulationIcons";
const ProgressCard = ({
title,
data,
@ -16,7 +18,9 @@ const ProgressCard = ({
</span>
<div className="stock-description">{stock.description}</div>
</span>
<div className="icon">Icon</div>
<div className="icon">
<StockIncreseIcon />
</div>
</div>
))}
</div>

View File

@ -1,12 +1,9 @@
import React, { useMemo } from "react";
import { Radar } from "react-chartjs-2";
import {
ChartOptions,
ChartData,
RadialLinearScaleOptions,
} from "chart.js";
import { ChartOptions, ChartData, RadialLinearScaleOptions } from "chart.js";
interface ChartComponentProps {
type: string;
title: string;
fontFamily?: string;
fontSize?: string;
@ -19,7 +16,7 @@ const RadarGraphComponent = ({
fontFamily,
fontSize,
fontWeight = "Regular",
data,
data, // Now guaranteed to be number[]
}: ChartComponentProps) => {
// Memoize Font Weight Mapping
const chartFontWeightMap = useMemo(
@ -31,14 +28,15 @@ const RadarGraphComponent = ({
[]
);
const fontSizeValue = useMemo(() => (fontSize ? parseInt(fontSize) : 12), [
fontSize,
]);
const fontSizeValue = useMemo(
() => (fontSize ? parseInt(fontSize) : 12),
[fontSize]
);
const fontWeightValue = useMemo(() => chartFontWeightMap[fontWeight], [
fontWeight,
chartFontWeightMap,
]);
const fontWeightValue = useMemo(
() => chartFontWeightMap[fontWeight],
[fontWeight, chartFontWeightMap]
);
const chartFontStyle = useMemo(
() => ({

View File

@ -13,8 +13,22 @@ const SimpleCard: React.FC<SimpleCardProps> = ({
value,
per,
}) => {
const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
const cardData = JSON.stringify({
header,
value,
per,
className: event.currentTarget.className,
});
console.log("Dragging Data:", cardData); // ✅ Debugging log
event.dataTransfer.setData("text/plain", cardData);
};
return (
<div className="floating total-card" draggable>
<div className="floating total-card" draggable onDragStart={handleDragStart}>
<div className="header-wrapper">
<div className="header">{header}</div>
<div className="data-values">

View File

@ -112,7 +112,7 @@ export default async function assetManager(
) {
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
const existingModel = itemsGroup.current.getObjectByProperty("uuid", item.modeluuid);
const existingModel = itemsGroup?.current?.getObjectByProperty("uuid", item.modeluuid);
if (existingModel) {
// console.log(`Model ${item.modelname} already exists in the scene.`);
resolve();

View File

@ -65,6 +65,8 @@ const ZoneGroup: React.FC = () => {
zoneId: zone.zoneId,
zoneName: zone.zoneName,
points: zone.points,
viewPortCenter: zone.viewPortCenter,
viewPortposition: zone.viewPortposition,
layer: zone.layer
}));
@ -145,7 +147,7 @@ const ZoneGroup: React.FC = () => {
const target: [number, number, number] | null = calculateCenter(zone.points);
if (!target) return;
const position = [target[0], 50, target[2]];
const position = [target[0], 10, target[2]];
const input = {
userId: userId,
@ -186,7 +188,7 @@ const ZoneGroup: React.FC = () => {
const target: [number, number, number] | null = calculateCenter(zone.points);
if (!target) return;
const position = [target[0], 75, target[2]];
const position = [target[0], 10, target[2]];
const input = {
userId: userId,

View File

@ -745,6 +745,7 @@ export default function SocketResponses({
return
}
if (data.message === "zone deleted") {
console.log('data: ', data);
const updatedZones = zones.filter((zone: any) => zone.zoneId !== data.data.zoneId);
setZones(updatedZones);

View File

@ -0,0 +1,95 @@
import React from "react";
import assetImage from "../../assets/image/image.png";
import { FiileedStarsIconSmall } from "../../components/icons/marketPlaceIcons";
// Define the shape of the selected card
interface SelectedCard {
assetName: string;
uploadedOn: string;
price: number;
rating: number;
views: number;
}
// Define the props type for AssetPreview
interface AssetPreviewProps {
selectedCard: SelectedCard;
setSelectedCard: React.Dispatch<React.SetStateAction<SelectedCard | null>>; // Type for setter function
}
const AssetPreview: React.FC<AssetPreviewProps> = ({
selectedCard,
setSelectedCard,
}) => {
// Ensure rating is a valid number between 0 and 5
const rating = Math.max(
0,
Math.min(5, isNaN(selectedCard.rating) ? 0 : selectedCard.rating)
);
console.log("selectedCard: ", selectedCard);
// Ensure that the rating is a valid positive integer for array length
const starsArray = Array.from({ length: rating }, (_, index) => index);
return (
<div className="assetPreview-wrapper">
<div className="assetPreview">
<div className="image-preview">
<img src={assetImage} alt="" />
</div>
<div className="asset-details-preview">
<div className="organization">
<div className="image">H</div>
<div className="organization-details">
<div className="organization-name">HERX FACTORY</div>
<div className="follow">Follow +</div>
</div>
</div>
{/* asset details */}
<div className="asset-details">
<div className="asset-name">{selectedCard.assetName}</div>
<div className="asset-description">
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Doloremque nisi beatae facilis architecto quaerat delectus velit
aliquid assumenda cumque vitae! Tempore quibusdam ab natus in
minima voluptates, aliquid corrupti excepturi consectetur
distinctio sequi beatae odit autem? Distinctio ab, voluptatem
omnis quibusdam, incidunt eum ipsa aliquid enim eaque eveniet nisi
autem, accusantium vel! Laborum in iste voluptates ad! Harum eum
amet pariatur fugit laudantium dolorem maxime voluptates atque
molestiae modi inventore quidem maiores dolore numquam, natus
quisquam optio distinctio eveniet aliquam, aut eligendi laboriosam
eaque! Porro cumque cum distinctio ullam debitis, dolorum
similique! Harum cupiditate perferendis voluptatum molestiae,
fugiat quisquam assumenda!
</div>
<div className="asset-review">
<div className="asset-rating">
<FiileedStarsIconSmall />
{selectedCard.rating}
</div>
<div className="asset-view">{selectedCard.views} views</div>
</div>
<div className="asset-price"> {selectedCard.price}</div>
</div>
{/* buttons */}
<div className="button-container">
<div className="button">Add to cart</div>
<div className="button">Buy now</div>
</div>
{/* close button */}
<div className="closeButton" onClick={() => setSelectedCard(null)}>
{`<-back`}
</div>
</div>
</div>
</div>
);
};
export default AssetPreview;

View File

@ -0,0 +1,57 @@
import React from "react";
import {
CommentsIcon,
DownloadIcon,
EyeIconBig,
StarsIconSmall,
VerifiedIcon,
} from "../../components/icons/marketPlaceIcons";
import assetImage from "../../assets/image/image.png";
const Card: React.FC = () => {
return (
<div className="card-container">
<div className="icon">
<DownloadIcon />
</div>
<div className="image-container">
<img src={assetImage} alt="" />
</div>
<div className="assets-container">
<div className="name-container">
<div className="asstes-container">Asset name</div>
<div className="assets-date">Uploaded on-12 Jan 23</div>
</div>
<div className="details">
<div className="content">
<EyeIconBig />
1.5k
</div>
<div className="content">
<CommentsIcon />
32
</div>
</div>
</div>
<div className="vendor-icon">
HEXR FACTORY <VerifiedIcon />
</div>
<div className="stars-container">
<div className="stars-wrapper">
<StarsIconSmall />
<StarsIconSmall />
<StarsIconSmall />
<StarsIconSmall />
<StarsIconSmall />
</div>
<div className="units">
36,500/<span>unit</span>
</div>
</div>
<div className="buy-now-button">Buy now</div>
</div>
);
};
export default Card;

View File

@ -0,0 +1,18 @@
import React from "react";
import Card from "./Card";
const CardsContainer: React.FC = () => {
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
return (
<div className="cards-container-container">
<div className="header">Products You May Like</div>
<div className="cards-wrapper-container">
{array.map((index) => (
<Card key={index} />
))}
</div>
</div>
);
};
export default CardsContainer;

View File

@ -0,0 +1,39 @@
import React, { useState } from "react";
// import RegularDropDown from "./ui/inputs/RegularDropDown";
import Search from "../../components/ui/inputs/Search";
import { StarsIcon } from "../../components/icons/marketPlaceIcons";
import RegularDropDown from "../../components/ui/inputs/RegularDropDown";
const FilterSearch: React.FC = () => {
const [activeOption, setActiveOption] = useState("Sort by"); // State for active option
const handleSelect = (option: string) => {
setActiveOption(option);
};
return (
<div className="filter-search-container">
<Search onChange={() => {}} />
<RegularDropDown
header={activeOption}
options={["Alphabet ascending", "Alphabet descending", ""]}
onSelect={handleSelect}
search={false}
/>
<div className="button">Free</div>
<div className="button">Animated</div>
<div className="rating-container">
<div className="label">Rating</div>
<div className="stars">
<StarsIcon />
<StarsIcon />
<StarsIcon />
<StarsIcon />
<StarsIcon />
</div>
</div>
</div>
);
};
export default FilterSearch;

View File

@ -0,0 +1,18 @@
import React from "react";
import FilterSearch from "./FilterSearch";
import CardsContainer from "./CardsContainer";
const MarketPlace = () => {
return (
<div className="marketplace-wrapper">
<div className="marketplace-container">
<div className="marketPlace">
<FilterSearch />
<CardsContainer />
</div>
</div>
</div>
);
};
export default MarketPlace;

View File

@ -15,7 +15,8 @@ import background from "../../assets/textures/hdr/mudroadpuresky2k.hdr";
import SelectionControls from "./controls/selection/selectionControls";
import MeasurementTool from "./tools/measurementTool";
import Simulation from "../simulation/simulation";
// import Simulation from "../simulation/simulationtemp/simulation";
// import Simulation from "./simulationtemp/simulation";
import ZoneCentreTarget from "../../components/ui/componets/zoneCameraTarget";
export default function Scene() {
@ -41,6 +42,7 @@ export default function Scene() {
<SelectionControls />
<MeasurementTool />
<World />
<ZoneCentreTarget />
<Simulation />
<PostProcessing />
<Sun />

View File

@ -16,7 +16,9 @@ import {
useLoadingProgress,
} from "../store/store";
import { useNavigate } from "react-router-dom";
import { usePlayButtonStore } from "../store/usePlayButtonStore";
import SimulationUI from "../modules/simulation/simulationUI";
import MarketPlace from "../modules/market/MarketPlace";
import LoadingPage from "../components/templates/LoadingPage";
const Project: React.FC = () => {
@ -46,13 +48,20 @@ const Project: React.FC = () => {
navigate("/");
}
}, []);
const { isPlaying } = usePlayButtonStore();
return (
<div className="project-main">
{loadingProgress && <LoadingPage progress={loadingProgress} />}
<ModuleToggle />
<SideBarLeft />
<SideBarRight />
{!isPlaying && (
<>
<ModuleToggle />
<ModuleToggle />
<SideBarLeft />
<SideBarRight />
</>
)}
{activeModule === "market" && <MarketPlace />}
<RealTimeVisulization />
{activeModule !== "market" && <Tools />}
{/* <SimulationUI /> */}

View File

@ -0,0 +1,23 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const getZoneData = async (zoneId: string, organization: string) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v2/A_zone/${zoneId}/${organization}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
throw new Error("Failed to fetch zoneData");
}
return await response.json();
} catch (error: any) {
throw new Error(error.message);
}
};

View File

@ -0,0 +1,31 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_BACKEND_URL}`;
type Side = "top" | "bottom" | "left" | "right";
export const panelData = async (organization: string, zoneID: string, panelOrder: Side[]) => {
console.log('panelOrder: ', panelOrder);
console.log('zoneID: ', zoneID);
console.log('organization: ', organization);
try {
const response = await fetch(`${url_Backend_dwinzo}/api/v1/panel/save`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ organization, zoneID, panelOrder }),
});
if (!response.ok) {
throw new Error("Failed to add panelOrder for Zone");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -1,29 +1,32 @@
import * as THREE from "three";
import * as Types from '../types/world/worldTypes';
import * as Types from "../types/world/worldTypes";
import { create } from "zustand";
import { io } from "socket.io-client";
export const useSocketStore = create<any>((set: any, get: any) => ({
socket: null,
initializeSocket: (email: any) => {
const existingSocket = get().socket;
if (existingSocket) {
return;
}
const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/`, {
reconnection: false,
auth: { email }
});
set({ socket });
},
disconnectSocket: () => {
set((state: any) => {
state.socket?.disconnect();
return { socket: null };
});
socket: null,
initializeSocket: (email: any) => {
const existingSocket = get().socket;
if (existingSocket) {
return;
}
const socket = io(
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/`,
{
reconnection: false,
auth: { email },
}
);
set({ socket });
},
disconnectSocket: () => {
set((state: any) => {
state.socket?.disconnect();
return { socket: null };
});
},
}));
export const useLoadingProgress = create<{ loadingProgress: number; setLoadingProgress: (x: number) => void }>((set) => ({
@ -32,270 +35,279 @@ export const useLoadingProgress = create<{ loadingProgress: number; setLoadingPr
}));
export const useOrganization = create<any>((set: any) => ({
organization: "",
setOrganization: (x: any) => set(() => ({ organization: x })),
organization: "",
setOrganization: (x: any) => set(() => ({ organization: x })),
}));
export const useToggleView = create<any>((set: any) => ({
toggleView: false,
setToggleView: (x: any) => set(() => ({ toggleView: x })),
toggleView: false,
setToggleView: (x: any) => set(() => ({ toggleView: x })),
}));
export const useUpdateScene = create<any>((set: any) => ({
updateScene: false,
setUpdateScene: (x: any) => set(() => ({ updateScene: x })),
updateScene: false,
setUpdateScene: (x: any) => set(() => ({ updateScene: x })),
}));
export const useWalls = create<any>((set: any) => ({
walls: [],
setWalls: (x: any) => set(() => ({ walls: x })),
walls: [],
setWalls: (x: any) => set(() => ({ walls: x })),
}));
export const useZones = create<any>((set: any) => ({
zones: [],
setZones: (x: any) => set(() => ({ zones: x })),
zones: [],
setZones: (x: any) => set(() => ({ zones: x })),
}));
interface ZonePointsState {
zonePoints: THREE.Vector3[];
setZonePoints: (points: THREE.Vector3[]) => void;
zonePoints: THREE.Vector3[];
setZonePoints: (points: THREE.Vector3[]) => void;
}
export const useZonePoints = create<ZonePointsState>((set) => ({
zonePoints: [],
setZonePoints: (points) => set({ zonePoints: points }),
zonePoints: [],
setZonePoints: (points) => set({ zonePoints: points }),
}));
export const useSelectedItem = create<any>((set: any) => ({
selectedItem: { name: "", id: "" },
setSelectedItem: (x: any) => set(() => ({ selectedItem: x })),
selectedItem: { name: "", id: "" },
setSelectedItem: (x: any) => set(() => ({ selectedItem: x })),
}));
export const useSelectedAssets = create<any>((set: any) => ({
selectedAssets: [],
setSelectedAssets: (x: any) => set(() => ({ selectedAssets: x })),
selectedAssets: [],
setSelectedAssets: (x: any) => set(() => ({ selectedAssets: x })),
}));
export const useLayers = create<any>((set: any) => ({
Layers: 1,
setLayers: (x: any) => set(() => ({ Layers: x })),
Layers: 1,
setLayers: (x: any) => set(() => ({ Layers: x })),
}));
export const useCamPosition = create<any>((set: any) => ({
camPosition: { x: undefined, y: undefined, z: undefined },
setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }),
camPosition: { x: undefined, y: undefined, z: undefined },
setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }),
}));
export const useMenuVisible = create<any>((set: any) => ({
menuVisible: false,
setMenuVisible: (x: any) => set(() => ({ menuVisible: x })),
menuVisible: false,
setMenuVisible: (x: any) => set(() => ({ menuVisible: x })),
}));
export const useDeleteModels = create<any>((set: any) => ({
deleteModels: false,
setDeleteModels: (x: any) => set(() => ({ deleteModels: x })),
deleteModels: false,
setDeleteModels: (x: any) => set(() => ({ deleteModels: x })),
}));
export const useToolMode = create<any>((set: any) => ({
toolMode: null,
setToolMode: (x: any) => set(() => ({ toolMode: x })),
toolMode: null,
setToolMode: (x: any) => set(() => ({ toolMode: x })),
}));
export const useNewLines = create<any>((set: any) => ({
newLines: [],
setNewLines: (x: any) => set(() => ({ newLines: x })),
newLines: [],
setNewLines: (x: any) => set(() => ({ newLines: x })),
}));
export const useDeletedLines = create<any>((set: any) => ({
deletedLines: [],
setDeletedLines: (x: any) => set(() => ({ deletedLines: x })),
deletedLines: [],
setDeletedLines: (x: any) => set(() => ({ deletedLines: x })),
}));
export const useMovePoint = create<any>((set: any) => ({
movePoint: false,
setMovePoint: (x: any) => set(() => ({ movePoint: x })),
movePoint: false,
setMovePoint: (x: any) => set(() => ({ movePoint: x })),
}));
export const useTransformMode = create<any>((set: any) => ({
transformMode: null,
setTransformMode: (x: any) => set(() => ({ transformMode: x })),
transformMode: null,
setTransformMode: (x: any) => set(() => ({ transformMode: x })),
}));
export const useDeletePointOrLine = create<any>((set: any) => ({
deletePointOrLine: false,
setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })),
deletePointOrLine: false,
setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })),
}));
export const useFloorItems = create<any>((set: any) => ({
floorItems: null,
setFloorItems: (callback: any) =>
set((state: any) => ({
floorItems:
typeof callback === "function"
? callback(state.floorItems)
: callback,
})),
floorItems: null,
setFloorItems: (callback: any) =>
set((state: any) => ({
floorItems:
typeof callback === "function" ? callback(state.floorItems) : callback,
})),
}));
export const useWallItems = create<any>((set: any) => ({
wallItems: [],
setWallItems: (callback: any) =>
set((state: any) => ({
wallItems:
typeof callback === "function"
? callback(state.wallItems)
: callback,
})),
wallItems: [],
setWallItems: (callback: any) =>
set((state: any) => ({
wallItems:
typeof callback === "function" ? callback(state.wallItems) : callback,
})),
}));
export const useSelectedWallItem = create<any>((set: any) => ({
selectedWallItem: null,
setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })),
selectedWallItem: null,
setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })),
}));
export const useselectedFloorItem = create<any>((set: any) => ({
selectedFloorItem: null,
setselectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })),
selectedFloorItem: null,
setselectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })),
}));
export const useDeletableFloorItem = create<any>((set: any) => ({
deletableFloorItem: null,
setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })),
deletableFloorItem: null,
setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })),
}));
export const useSetScale = create<any>((set: any) => ({
scale: null,
setScale: (x: any) => set(() => ({ scale: x })),
scale: null,
setScale: (x: any) => set(() => ({ scale: x })),
}));
export const useRoofVisibility = create<any>((set: any) => ({
roofVisibility: false,
setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })),
roofVisibility: false,
setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })),
}));
export const useWallVisibility = create<any>((set: any) => ({
wallVisibility: false,
setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })),
wallVisibility: false,
setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })),
}));
export const useShadows = create<any>((set: any) => ({
shadows: false,
setShadows: (x: any) => set(() => ({ shadows: x })),
shadows: false,
setShadows: (x: any) => set(() => ({ shadows: x })),
}));
export const useSunPosition = create<any>((set: any) => ({
sunPosition: { x: undefined, y: undefined, z: undefined },
setSunPosition: (newSuntPosition: any) => set({ sunPosition: newSuntPosition }),
sunPosition: { x: undefined, y: undefined, z: undefined },
setSunPosition: (newSuntPosition: any) =>
set({ sunPosition: newSuntPosition }),
}));
export const useRemoveLayer = create<any>((set: any) => ({
removeLayer: false,
setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })),
removeLayer: false,
setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })),
}));
export const useRemovedLayer = create<any>((set: any) => ({
removedLayer: null,
setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })),
removedLayer: null,
setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })),
}));
export const useActiveLayer = create<any>((set: any) => ({
activeLayer: 1,
setActiveLayer: (x: any) => set({ activeLayer: x }),
activeLayer: 1,
setActiveLayer: (x: any) => set({ activeLayer: x }),
}));
export const useResetCamera = create<any>((set: any) => ({
resetCamera: false,
setResetCamera: (x: any) => set({ resetCamera: x }),
resetCamera: false,
setResetCamera: (x: any) => set({ resetCamera: x }),
}));
export const useAddAction = create<any>((set: any) => ({
addAction: null,
setAddAction: (x: any) => set({ addAction: x }),
addAction: null,
setAddAction: (x: any) => set({ addAction: x }),
}));
export const useActiveTool = create<any>((set: any) => ({
activeTool: "Cursor",
setActiveTool: (x: any) => set({ activeTool: x }),
activeTool: "Cursor",
setActiveTool: (x: any) => set({ activeTool: x }),
}));
export const use2DUndoRedo = create<any>((set: any) => ({
is2DUndoRedo: null,
set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }),
}))
is2DUndoRedo: null,
set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }),
}));
export const useElevation = create<any>((set: any) => ({
elevation: 45,
setElevation: (x: any) => set({ elevation: x }),
elevation: 45,
setElevation: (x: any) => set({ elevation: x }),
}));
export const useAzimuth = create<any>((set: any) => ({
azimuth: -160,
setAzimuth: (x: any) => set({ azimuth: x }),
azimuth: -160,
setAzimuth: (x: any) => set({ azimuth: x }),
}));
export const useRenderDistance = create<any>((set: any) => ({
renderDistance: 50,
setRenderDistance: (x: any) => set({ renderDistance: x }),
renderDistance: 50,
setRenderDistance: (x: any) => set({ renderDistance: x }),
}));
export const useCamMode = create<any>((set: any) => ({
camMode: "ThirdPerson",
setCamMode: (x: any) => set({ camMode: x }),
camMode: "ThirdPerson",
setCamMode: (x: any) => set({ camMode: x }),
}));
export const useUserName = create<any>((set: any) => ({
userName: "",
setUserName: (x: any) => set({ userName: x }),
userName: "",
setUserName: (x: any) => set({ userName: x }),
}));
export const useObjectPosition = create<any>((set: any) => ({
objectPosition: { x: undefined, y: undefined, z: undefined },
setObjectPosition: (newObjectPosition: any) => set({ objectPosition: newObjectPosition }),
objectPosition: { x: undefined, y: undefined, z: undefined },
setObjectPosition: (newObjectPosition: any) =>
set({ objectPosition: newObjectPosition }),
}));
export const useObjectScale = create<any>((set: any) => ({
objectScale: { x: undefined, y: undefined, z: undefined },
setObjectScale: (newObjectScale: any) => set({ objectScale: newObjectScale }),
objectScale: { x: undefined, y: undefined, z: undefined },
setObjectScale: (newObjectScale: any) => set({ objectScale: newObjectScale }),
}));
export const useObjectRotation = create<any>((set: any) => ({
objectRotation: { x: undefined, y: undefined, z: undefined },
setObjectRotation: (newObjectRotation: any) => set({ objectRotation: newObjectRotation }),
objectRotation: { x: undefined, y: undefined, z: undefined },
setObjectRotation: (newObjectRotation: any) =>
set({ objectRotation: newObjectRotation }),
}));
export const useDrieTemp = create<any>((set: any) => ({
drieTemp: undefined,
setDrieTemp: (x: any) => set({ drieTemp: x }),
drieTemp: undefined,
setDrieTemp: (x: any) => set({ drieTemp: x }),
}));
export const useActiveUsers = create<any>((set: any) => ({
activeUsers: [],
setActiveUsers: (x: any) => set({ activeUsers: x }),
activeUsers: [],
setActiveUsers: (x: any) => set({ activeUsers: x }),
}));
export const useDrieUIValue = create<any>((set: any) => ({
drieUIValue: { touch: null, temperature: null, humidity: null },
drieUIValue: { touch: null, temperature: null, humidity: null },
setDrieUIValue: (x: any) => set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })),
setDrieUIValue: (x: any) =>
set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })),
setTouch: (value: any) => set((state: any) => ({ drieUIValue: { ...state.drieUIValue, touch: value } })),
setTemperature: (value: any) => set((state: any) => ({ drieUIValue: { ...state.drieUIValue, temperature: value } })),
setHumidity: (value: any) => set((state: any) => ({ drieUIValue: { ...state.drieUIValue, humidity: value } })),
setTouch: (value: any) =>
set((state: any) => ({
drieUIValue: { ...state.drieUIValue, touch: value },
})),
setTemperature: (value: any) =>
set((state: any) => ({
drieUIValue: { ...state.drieUIValue, temperature: value },
})),
setHumidity: (value: any) =>
set((state: any) => ({
drieUIValue: { ...state.drieUIValue, humidity: value },
})),
}));
export const useDrawMaterialPath = create<any>((set: any) => ({
drawMaterialPath: false,
setDrawMaterialPath: (x: any) => set({ drawMaterialPath: x }),
drawMaterialPath: false,
setDrawMaterialPath: (x: any) => set({ drawMaterialPath: x }),
}));
export const useSelectedActionSphere = create<any>((set: any) => ({
selectedActionSphere: undefined,
setSelectedActionSphere: (x: any) => set({ selectedActionSphere: x }),
selectedActionSphere: undefined,
setSelectedActionSphere: (x: any) => set({ selectedActionSphere: x }),
}));
export const useSelectedPath = create<any>((set: any) => ({
selectedPath: undefined,
setSelectedPath: (x: any) => set({ selectedPath: x }),
selectedPath: undefined,
setSelectedPath: (x: any) => set({ selectedPath: x }),
}));
interface Path {
@ -315,8 +327,8 @@ interface Path {
}
interface SimulationPathsStore {
simulationPaths: Path[];
setSimulationPaths: (paths: Path[]) => void;
simulationPaths: Path[];
setSimulationPaths: (paths: Path[]) => void;
}
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
@ -325,11 +337,47 @@ export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
}));
export const useIsConnecting = create<any>((set: any) => ({
isConnecting: false,
setIsConnecting: (x: any) => set({ isConnecting: x }),
isConnecting: false,
setIsConnecting: (x: any) => set({ isConnecting: x }),
}));
export const useStartSimulation = create<any>((set: any) => ({
startSimulation: false,
setStartSimulation: (x: any) => set({ startSimulation: x }),
}));
startSimulation: false,
setStartSimulation: (x: any) => set({ startSimulation: x }),
}));
export const usezoneTarget = create<any>((set: any) => ({
zoneTarget: [],
setZoneTarget: (x: any) => set({ zoneTarget: x }),
}));
export const usezonePosition = create<any>((set: any) => ({
zonePosition: [],
setZonePosition: (x: any) => set({ zonePosition: x }),
}));
interface EditPositionState {
Edit: boolean;
setEdit: (value: boolean) => void;
}
export const useEditPosition = create<EditPositionState>((set) => ({
Edit: false,
setEdit: (value) => set({ Edit: value }), // Properly updating the state
}));
interface DroppedObject {
header: string;
value: string;
per: string;
className: string;
}
interface DroppedObjectsState {
objects: DroppedObject[];
addObject: (obj: DroppedObject) => void;
}
export const useDroppedObjectsStore = create<DroppedObjectsState>((set) => ({
objects: [],
addObject: (obj) => set((state) => ({ objects: [...state.objects, obj] })),
}));

View File

@ -0,0 +1,28 @@
import { create } from "zustand";
interface Measurement {
name: string;
fields: string;
}
interface MeasurementStore {
measurements: Measurement[];
interval: number;
duration: string;
setMeasurements: (newMeasurements: Measurement[]) => void;
updateDuration: (newDuration: string) => void;
}
const useChartStore = create<MeasurementStore>((set) => ({
measurements: [],
interval: 1000,
duration: "1h",
setMeasurements: (newMeasurements) =>
set(() => ({ measurements: newMeasurements })),
updateDuration: (newDuration) =>
set(() => ({ duration: newDuration })),
}));
export default useChartStore;

View File

@ -15,21 +15,31 @@ interface SelectedZoneState {
activeSides: Side[];
panelOrder: Side[];
lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[];
widgets: Widget[];
}
interface SelectedZoneStore {
selectedZone: SelectedZoneState;
setSelectedZone: (zone: Partial<SelectedZoneState> | ((prev: SelectedZoneState) => SelectedZoneState)) => void;
setSelectedZone: (
zone:
| Partial<SelectedZoneState>
| ((prev: SelectedZoneState) => SelectedZoneState)
) => void;
}
export const useSelectedZoneStore = create<SelectedZoneStore>((set) => ({
selectedZone: {
zoneName: "Manufacturing unit",
activeSides: [],
panelOrder: [],
lockedPanels: [],
widgets: [],
zoneName: "", // Empty string initially
activeSides: [], // Empty array
panelOrder: [], // Empty array
lockedPanels: [], // Empty array
zoneId: "",
zoneViewPortTarget: [],
zoneViewPortPosition: [],
widgets: [], // Empty array
},
setSelectedZone: (zone) =>
set((state) => ({
@ -38,4 +48,4 @@ export const useSelectedZoneStore = create<SelectedZoneStore>((set) => ({
? zone(state.selectedZone) // Handle functional updates
: { ...state.selectedZone, ...zone }, // Handle partial updates
})),
}));
}));

View File

@ -0,0 +1,187 @@
@use "../../abstracts/variables" as *;
@use "../../abstracts/mixins.scss" as *;
.marketplace-wrapper {
height: 100vh;
width: 100vw;
z-index: #{$z-index-marketplace};
background-color: var(--background-color-secondary);
position: absolute;
left: 0;
padding: 100px 50px;
.marketplace-container {
padding: 20px 2px;
height: calc(100vh - 120px);
background-color: var(--background-color);
box-shadow: #{$box-shadow-medium};
border-radius: #{$border-radius-extra-large};
}
.marketPlace {
width: 100%;
height: 100%;
overflow: auto;
left: calc(120px / 2);
top: 100px;
padding: 14px;
padding-bottom: 60px;
display: flex;
flex-direction: column;
gap: 24px;
.filter-search-container {
width: 100%;
display: flex;
align-items: center;
gap: 12px;
.search-wrapper {
min-width: 60%;
max-width: 684px;
padding: 0;
border-radius: $border-radius-large ;
.search-container {
border: none !important;
box-shadow: $box-shadow-medium;
border-radius: $border-radius-large ;
input {
border: none !important;
outline: none;
}
}
}
.regularDropdown-container {
max-width: 159px;
}
.button {
padding: 5px 20px;
border: 1px solid var(--accent-color);
border-radius: 14px;
}
.rating-container {
display: flex;
align-items: center;
gap: 6px;
.stars {
display: flex;
align-items: center;
}
}
}
.cards-container-container {
padding: 0px 20px;
display: flex;
flex-direction: column;
gap: 6px;
.header {
color: var(--text-color);
font-weight: $medium-weight;
font-size: $xlarge;
}
.cards-wrapper-container {
display: flex;
flex-wrap: wrap;
gap: 28px;
.card-container {
width: calc(25% - 23px);
border-radius: 18px;
padding: 12px;
box-shadow: 0px 2px 10.5px 0px #0000000D;
border: 1px solid var(--background-accent-transparent, #E0DFFF80);
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
gap: 6px;
.icon {
position: absolute;
top: 12px;
left: 12px;
width: 30px;
height: 30px;
border-radius: 10px;
padding: 5px;
background-color: var(--accent-color);
}
.image-container {
width: 100%;
display: flex;
justify-content: center;
}
.assets-container {
display: flex;
justify-content: space-between;
.name-container {
display: flex;
flex-direction: column;
gap: 3px;
.asstes-container {
font-weight: #{$bold-weight};
font-size: $regular ;
}
.assets-date {
color: var(--accent-color);
font-size: $small;
}
}
.details {
display: flex;
align-items: center;
gap: 10px;
.content {
display: flex;
align-items: center;
gap: 6px;
}
}
}
.vendor-icon {
font-weight: #{$bold-weight};
font-size: $regular ;
}
.stars-container {
display: flex;
justify-content: space-between;
}
.buy-now-button {
width: 100%;
background-color: var(--background-color-secondary);
border-radius: $border-radius-extra-large ;
padding: 8px 0;
@include flex-center;
color: var(--accent-color);
&:hover {
cursor: pointer;
}
}
}
}
}
}
}

View File

@ -4,7 +4,7 @@
.tools-container {
@include flex-center;
position: fixed;
bottom: 32px;
bottom: 50px;
left: 50%;
transform: translate(-50%, 0);
padding: 8px;
@ -15,12 +15,14 @@
transition: width 0.2s;
background-color: var(--background-color);
z-index: #{$z-index-default};
.split {
height: 20px;
width: 2px;
border-radius: 2px;
background: var(--highlight-accent-color);
}
.draw-tools,
.general-options,
.activeDropicon {
@ -30,42 +32,46 @@
width: 0;
opacity: 0;
animation: expandWidth 0.2s ease-in-out forwards;
.tool-button {
@include flex-center;
height: 28px;
width: 28px;
cursor: pointer;
border-radius: #{$border-radius-small};
&:hover {
background: color-mix(
in srgb,
var(--highlight-accent-color) 60%,
transparent
);
background: color-mix(in srgb,
var(--highlight-accent-color) 60%,
transparent);
}
}
.active {
background-color: var(--accent-color);
&:hover {
background-color: var(--accent-color);
}
}
}
.activeDropicon {
gap: 2px;
.drop-down-option-button {
@include flex-center;
height: 28px;
cursor: pointer;
border-radius: #{$border-radius-small};
position: relative;
&:hover {
background: color-mix(
in srgb,
var(--highlight-accent-color) 60%,
transparent
);
background: color-mix(in srgb,
var(--highlight-accent-color) 60%,
transparent);
}
.drop-down-container {
position: absolute;
bottom: 40px;
@ -74,6 +80,7 @@
padding: 8px;
border-radius: #{$border-radius-large};
background: var(--background-color);
.option-list {
margin: 4px 0;
display: flex;
@ -82,18 +89,22 @@
border-radius: #{$border-radius-medium};
gap: 6px;
padding: 4px;
&:hover {
background-color: var(--highlight-accent-color);
color: var(--accent-color);
path {
stroke: var(--accent-color);
}
}
.active-option {
height: 12px;
width: 12px;
@include flex-center;
}
.option {
color: inherit;
}
@ -101,6 +112,7 @@
}
}
}
.toggle-threed-button {
@include flex-center;
padding: 3px;
@ -108,12 +120,14 @@
background-color: var(--highlight-accent-color);
gap: 2px;
position: relative;
.toggle-option {
font-size: var(--font-size-small);
padding: 2px;
z-index: 1;
transition: all 0.2s;
}
&::after {
content: "";
position: absolute;
@ -125,15 +139,70 @@
border-radius: #{$border-radius-small};
transition: all 0.2s;
}
.active {
color: var(--highlight-accent-color);
}
}
.toggled {
&::after {
left: 24px;
}
}
}
.exitPlay {
width: 30px;
height: 30px;
border-radius: 50%;
background-color: var(--highlight-accent-color);
cursor: pointer;
@include flex-center;
position: fixed;
bottom: 60px;
left: 50%;
transform: translate(-50%, 0);
color: var(--accent-color);
z-index: 100;
isolation: isolate;
font-weight: 700;
&:hover {
font-weight: 500;
background-color: var(--accent-color);
color: var(--highlight-accent-color);
&::after{
animation: pulse 1s ease-out infinite;
}
}
&::after{
content: "";
position: absolute;
height: 100%;
width: 100%;
background: var(--background-color-secondary);
border-radius: #{$border-radius-circle};
z-index: -1;
}
}
@keyframes pulse {
0%{
opacity: 0;
scale: .5;
}
50%{
opacity: 1;
}
100%{
opacity: 0;
scale: 2;
}
}
@keyframes expandWidth {
@ -141,8 +210,9 @@
width: 0;
opacity: 0;
}
to {
width: fit-content;
opacity: 1;
}
}
}

View File

@ -530,7 +530,7 @@
border-radius: #{$border-radius-medium};
path {
stroke: var(--accent-color);
stroke-width: 1.5px;
strokeWidth: 1.5px;
}
&:hover {
background: var(--accent-color);

View File

@ -21,6 +21,7 @@
@use 'components/visualization/floating/energyConsumed';
@use 'components/visualization/ui/styledWidgets';
@use './components/visualization/floating/common';
@use './components/marketPlace/marketPlace.scss';
// layout
@use 'layout/loading';

View File

@ -167,7 +167,9 @@
.chart-container {
width: 100%;
height: 200px;
height: 24% !important;
min-height: 150px;
max-height: 100%;
border: 1px dotted #a9a9a9;
border-radius: 8px;
@ -192,17 +194,17 @@
left: 0;
right: 0;
.fullScreen {
background-color: red;
}
.panel-content {
display: flex;
flex-direction: row;
height: 100%;
.chart-container {
height: 100%;
width: 200px;
height: 100% !important;
width: 20%;
min-width: 150px;
}
}
}
@ -234,6 +236,11 @@
}
}
.playingFlase{
.zoon-wrapper{
bottom: 300px !important;
}
}
// Side Buttons
.side-button-container {
position: absolute;