updated simulation player
This commit is contained in:
@@ -42,44 +42,46 @@ export function FlipXAxisIcon() {
|
||||
}
|
||||
|
||||
export function FlipYAxisIcon() {
|
||||
<svg
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.0568 11H2.94321C2.09213 11 1.6666 11 1.52703 10.7288C1.38746 10.4576 1.6348 10.1113 2.12947 9.41877L2.6942 8.62814C2.91415 8.32021 3.02413 8.16625 3.18565 8.08313C3.34718 8 3.53639 8 3.9148 8H8.08525C8.46365 8 8.65285 8 8.8144 8.08313C8.9759 8.16625 9.0859 8.32021 9.30585 8.62814L9.87055 9.41876C10.3653 10.1113 10.6126 10.4576 10.473 10.7288C10.3335 11 9.9079 11 9.0568 11Z"
|
||||
fill="var(--text-color)"
|
||||
/>
|
||||
<path
|
||||
d="M2.99935 3.15388L2.99936 3.1539C3.11318 3.31326 3.18452 3.41252 3.2461 3.48409C3.30271 3.54989 3.33407 3.57152 3.3572 3.58344L2.99935 3.15388ZM2.99935 3.15388L2.43462 2.36329C2.43462 2.36329 2.43462 2.36328 2.43462 2.36328C2.17987 2.00663 2.01464 1.7736 1.92406 1.59704C1.88093 1.51299 1.86801 1.46687 1.86465 1.44495C1.88444 1.43495 1.92948 1.41866 2.02293 1.4049C2.21925 1.37599 2.50491 1.375 2.94321 1.375L9.0568 1.375C9.49511 1.375 9.78078 1.37599 9.9771 1.4049C10.0705 1.41866 10.1156 1.43494 10.1354 1.44495C10.132 1.46687 10.1191 1.51299 10.076 1.59705C9.98539 1.7736 9.82016 2.00663 9.5654 2.36328L9.5654 2.36329L9.0007 3.15389L9.00069 3.15389M2.99935 3.15388L9.00069 3.15389M9.00069 3.15389C8.88688 3.31325 8.81553 3.41252 8.75395 3.48409C8.69737 3.54985 8.666 3.5715 8.64287 3.58343C8.61972 3.59534 8.5839 3.60831 8.49735 3.61614C8.40331 3.62465 8.28108 3.625 8.08525 3.625L3.9148 3.625C3.71896 3.625 3.59672 3.62465 3.50269 3.61614M9.00069 3.15389L3.50269 3.61614M3.50269 3.61614C3.41623 3.60832 3.38041 3.59537 3.35729 3.58348L3.50269 3.61614ZM1.86435 1.42845C1.86468 1.42867 1.86476 1.43108 1.86363 1.43501C1.86345 1.4302 1.86402 1.42823 1.86435 1.42845ZM1.85597 1.4499C1.85343 1.45311 1.85142 1.45444 1.85105 1.4543C1.85068 1.45416 1.85195 1.45255 1.85597 1.4499ZM10.149 1.45429C10.1486 1.45443 10.1466 1.4531 10.1441 1.44989C10.1481 1.45254 10.1493 1.45415 10.149 1.45429ZM10.1364 1.435C10.1353 1.43107 10.1353 1.42867 10.1357 1.42845C10.136 1.42823 10.1366 1.4302 10.1364 1.435Z"
|
||||
stroke="var(--text-color)"
|
||||
strokeWidth="0.75"
|
||||
/>
|
||||
<path
|
||||
opacity="0.5"
|
||||
d="M7 6H5"
|
||||
stroke="var(--text-color)"
|
||||
strokeWidth="0.75"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
opacity="0.5"
|
||||
d="M3 6H1"
|
||||
stroke="var(--text-color)"
|
||||
strokeWidth="0.75"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
opacity="0.5"
|
||||
d="M11 6H9"
|
||||
stroke="var(--text-color)"
|
||||
strokeWidth="0.75"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>;
|
||||
return (
|
||||
<svg
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.0568 11H2.94321C2.09213 11 1.6666 11 1.52703 10.7288C1.38746 10.4576 1.6348 10.1113 2.12947 9.41877L2.6942 8.62814C2.91415 8.32021 3.02413 8.16625 3.18565 8.08313C3.34718 8 3.53639 8 3.9148 8H8.08525C8.46365 8 8.65285 8 8.8144 8.08313C8.9759 8.16625 9.0859 8.32021 9.30585 8.62814L9.87055 9.41876C10.3653 10.1113 10.6126 10.4576 10.473 10.7288C10.3335 11 9.9079 11 9.0568 11Z"
|
||||
fill="var(--text-color)"
|
||||
/>
|
||||
<path
|
||||
d="M2.99935 3.15388L2.99936 3.1539C3.11318 3.31326 3.18452 3.41252 3.2461 3.48409C3.30271 3.54989 3.33407 3.57152 3.3572 3.58344L2.99935 3.15388ZM2.99935 3.15388L2.43462 2.36329C2.43462 2.36329 2.43462 2.36328 2.43462 2.36328C2.17987 2.00663 2.01464 1.7736 1.92406 1.59704C1.88093 1.51299 1.86801 1.46687 1.86465 1.44495C1.88444 1.43495 1.92948 1.41866 2.02293 1.4049C2.21925 1.37599 2.50491 1.375 2.94321 1.375L9.0568 1.375C9.49511 1.375 9.78078 1.37599 9.9771 1.4049C10.0705 1.41866 10.1156 1.43494 10.1354 1.44495C10.132 1.46687 10.1191 1.51299 10.076 1.59705C9.98539 1.7736 9.82016 2.00663 9.5654 2.36328L9.5654 2.36329L9.0007 3.15389L9.00069 3.15389M2.99935 3.15388L9.00069 3.15389M9.00069 3.15389C8.88688 3.31325 8.81553 3.41252 8.75395 3.48409C8.69737 3.54985 8.666 3.5715 8.64287 3.58343C8.61972 3.59534 8.5839 3.60831 8.49735 3.61614C8.40331 3.62465 8.28108 3.625 8.08525 3.625L3.9148 3.625C3.71896 3.625 3.59672 3.62465 3.50269 3.61614M9.00069 3.15389L3.50269 3.61614M3.50269 3.61614C3.41623 3.60832 3.38041 3.59537 3.35729 3.58348L3.50269 3.61614ZM1.86435 1.42845C1.86468 1.42867 1.86476 1.43108 1.86363 1.43501C1.86345 1.4302 1.86402 1.42823 1.86435 1.42845ZM1.85597 1.4499C1.85343 1.45311 1.85142 1.45444 1.85105 1.4543C1.85068 1.45416 1.85195 1.45255 1.85597 1.4499ZM10.149 1.45429C10.1486 1.45443 10.1466 1.4531 10.1441 1.44989C10.1481 1.45254 10.1493 1.45415 10.149 1.45429ZM10.1364 1.435C10.1353 1.43107 10.1353 1.42867 10.1357 1.42845C10.136 1.42823 10.1366 1.4302 10.1364 1.435Z"
|
||||
stroke="var(--text-color)"
|
||||
strokeWidth="0.75"
|
||||
/>
|
||||
<path
|
||||
opacity="0.5"
|
||||
d="M7 6H5"
|
||||
stroke="var(--text-color)"
|
||||
strokeWidth="0.75"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
opacity="0.5"
|
||||
d="M3 6H1"
|
||||
stroke="var(--text-color)"
|
||||
strokeWidth="0.75"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
opacity="0.5"
|
||||
d="M11 6H9"
|
||||
stroke="var(--text-color)"
|
||||
strokeWidth="0.75"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
export function FlipZAxisIcon() {
|
||||
return (
|
||||
|
||||
@@ -168,20 +168,6 @@ export function AddIcon() {
|
||||
);
|
||||
}
|
||||
|
||||
export function RmoveIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M3 6.5H9" stroke="var(--text-color)" strokeLinecap="round" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function CloseIcon() {
|
||||
return (
|
||||
<svg
|
||||
@@ -607,3 +593,212 @@ export const DeleteIcon = () => {
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const HourlySimulationIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="17"
|
||||
height="16"
|
||||
viewBox="0 0 17 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M9.22794 8.29297C9.22794 9.1131 9.69975 9.49575 10.1561 9.86512C10.7275 10.3286 11.371 10.8503 11.4375 12.4462H5.91087C5.97732 10.8503 6.62079 10.3286 7.19228 9.86512C7.64859 9.49575 8.1204 9.1131 8.1204 8.29297C8.1204 7.47284 7.64859 7.09018 7.19228 6.72082C6.62079 6.25732 5.97732 5.73567 5.91087 4.13971H11.4375C11.371 5.73567 10.7275 6.25732 10.1561 6.72082C9.69975 7.09018 9.22794 7.47284 9.22794 8.29297ZM10.5049 7.15054C11.1694 6.61173 11.9968 5.94112 11.9968 3.86282V3.58594H5.35156V3.86282C5.35156 5.94112 6.17889 6.61173 6.84342 7.15054C7.27867 7.50385 7.56663 7.73699 7.56663 8.29297C7.56663 8.84895 7.27867 9.08209 6.84342 9.4354C6.17889 9.97421 5.35156 10.6448 5.35156 12.7231V13H11.9968V12.7231C11.9968 10.6448 11.1695 9.97421 10.5049 9.4354C10.0697 9.08209 9.78171 8.84895 9.78171 8.29297C9.78171 7.73699 10.0697 7.50385 10.5049 7.15054ZM8.54764 9.83582L7.71588 10.5109C7.3515 10.806 7.03751 11.0602 6.86916 11.6156H10.4792C10.3108 11.0602 9.99685 10.806 9.63247 10.5109L8.80071 9.83582C8.72706 9.77602 8.62129 9.77602 8.54764 9.83582Z"
|
||||
fill="#2B3344"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const DailyProductionIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="17"
|
||||
height="16"
|
||||
viewBox="0 0 17 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M13.4564 6.96778C13.3816 6.81906 13.2232 6.72864 13.0596 6.74287L12.5621 6.77922C12.0226 4.82899 10.2365 3.39063 8.11668 3.39063C5.57103 3.39059 3.5 5.46179 3.5 8.00724C3.5 10.5529 5.57103 12.6239 8.11664 12.6239C9.59017 12.6239 10.9876 11.911 11.8549 10.7172C11.988 10.5335 11.947 10.2772 11.7637 10.1437C11.5801 10.0105 11.3235 10.0519 11.1904 10.2347C10.477 11.2167 9.328 11.8032 8.11645 11.8032C6.02331 11.8032 4.32065 10.1003 4.32065 8.00737C4.32065 5.91438 6.02334 4.21163 8.11648 4.21163C9.80226 4.21163 11.2333 5.3171 11.7269 6.84049L11.4679 6.85944C11.3024 6.87139 11.1604 6.98234 11.1083 7.13969C11.0559 7.29735 11.104 7.47084 11.2294 7.57934L11.9746 8.22285C12.0471 8.33961 12.1753 8.41774 12.3224 8.41774C12.3301 8.41774 12.3373 8.41599 12.3449 8.41564C12.3474 8.41564 12.3493 8.4167 12.3516 8.4167C12.3614 8.4167 12.3714 8.41654 12.3816 8.41564C12.4901 8.40757 12.5909 8.35682 12.6622 8.27447L13.3998 7.42041C13.5087 7.2949 13.5308 7.11596 13.4564 6.96778Z"
|
||||
fill="#2B3344"
|
||||
/>
|
||||
<path
|
||||
d="M5.94531 9.43859V9.04L6.30878 8.71149C6.92314 8.16192 7.22165 7.84585 7.23024 7.51715C7.23024 7.28766 7.09188 7.1061 6.76706 7.1061C6.52494 7.1061 6.31281 7.2269 6.16567 7.33979L5.97956 6.86783C6.19166 6.70822 6.52036 6.57812 6.90122 6.57812C7.53737 6.57812 7.88783 6.95018 7.88783 7.46078C7.88783 7.9324 7.54615 8.30903 7.1393 8.67234L6.87962 8.88866V8.89708H7.9398V9.43823H5.94531V9.43859Z"
|
||||
fill="#2B3344"
|
||||
/>
|
||||
<path
|
||||
d="M9.51199 9.43788V8.76696H8.26587V8.33889L9.33028 6.625H10.1352V8.27375H10.4726V8.76696H10.1352V9.43788H9.51199ZM9.51199 8.27375V7.65077C9.51199 7.48187 9.52061 7.30909 9.53359 7.12718H9.51638C9.42525 7.30909 9.35168 7.47344 9.25671 7.65077L8.88026 8.26513V8.27375H9.51199Z"
|
||||
fill="#2B3344"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const MonthlyROI = () => {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M3.78955 11.9997V4.84175H4.84219V4.21016C4.84221 3.97761 5.03071 3.7891 5.26325 3.7891H6.10535C6.33789 3.7891 6.52639 3.97761 6.52641 4.21012V4.84175H9.47381L9.47379 4.21012C9.47379 3.97756 9.66231 3.78906 9.89485 3.78906H10.737C10.9695 3.78906 11.158 3.97756 11.158 4.21012V4.84175H12.2107V11.9997H3.78955ZM4.42113 11.3681H11.5791V6.52599H4.42113V11.3681ZM4.84219 9.89443H6.10535V10.9471H4.84219V9.89443ZM6.52641 9.89443H7.78957V10.9471H6.52641V9.89443ZM8.21063 9.89443H9.47379V10.9471H8.21063V9.89443ZM9.89485 9.89443H11.158V10.9471H9.89485V9.89443ZM4.84219 8.42073H6.10535V9.47337H4.84219V8.42073ZM6.52641 8.42073H7.78957V9.47337H6.52641V8.42073ZM8.21063 8.42073H9.47379V9.47337H8.21063V8.42073ZM9.89485 8.42073H11.158V9.47337H9.89485V8.42073ZM6.52641 6.94707H7.78957V7.99971H6.52641V6.94707ZM8.21063 6.94707H9.47379V7.99971H8.21063V6.94707ZM9.89485 6.94707H11.158V7.99971H9.89485V6.94707ZM10.2106 4.21019C10.0362 4.21019 9.89485 4.35156 9.89485 4.52598V5.15756C9.89485 5.33198 10.0362 5.47335 10.2106 5.47335H10.4212C10.5956 5.47335 10.737 5.33198 10.737 5.15756V4.52598C10.737 4.35156 10.5956 4.21019 10.4212 4.21019H10.2106ZM5.57904 4.21016C5.40462 4.21016 5.26325 4.35156 5.26325 4.52598V5.15756C5.26325 5.33195 5.40462 5.47335 5.57904 5.47335H5.78956C5.96398 5.47335 6.10535 5.33195 6.10535 5.15756V4.52598C6.10535 4.35156 5.96398 4.21016 5.78956 4.21016H5.57904ZM6.73695 8.63125V9.26285H7.57905V8.63125H6.73695ZM5.05271 8.63125V9.26285H5.89483V8.63125H5.05271ZM8.42117 8.63125V9.26285H9.26327V8.63125H8.42117ZM10.1054 8.63125V9.26283H10.9475V8.63125H10.1054Z"
|
||||
fill="#2B3344"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ExpandIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16 5.32324C16 5.09668 15.8018 4.89844 15.5752 4.89844H3.96387C3.7373 4.89844 3.53906 5.09668 3.53906 5.32324V6.17285C3.53906 6.39941 3.7373 6.59766 3.96387 6.59766H15.5752C15.8018 6.59766 16 6.39941 16 6.17285V5.32324Z"
|
||||
fill="#2B3344"
|
||||
/>
|
||||
<path
|
||||
d="M16 13.8232C16 13.5967 15.8018 13.3984 15.5752 13.3984H3.96387C3.7373 13.3984 3.53906 13.5967 3.53906 13.8232V14.6729C3.53906 14.8994 3.7373 15.0977 3.96387 15.0977H15.5752C15.8018 15.0977 16 14.8994 16 14.6729V13.8232Z"
|
||||
fill="#2B3344"
|
||||
/>
|
||||
<path
|
||||
d="M12.1768 10.8477C12.4033 10.8477 12.6016 10.6494 12.6016 10.4229V9.57324C12.6016 9.34668 12.4033 9.14844 12.1768 9.14844H7.3623C7.13574 9.14844 6.9375 9.34668 6.9375 9.57324V10.4229C6.9375 10.6494 7.13574 10.8477 7.3623 10.8477H12.1768Z"
|
||||
fill="#2B3344"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const StartIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="21"
|
||||
height="20"
|
||||
viewBox="0 0 21 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M10.8542 7.58594V10.5918"
|
||||
stroke="#6F42C1"
|
||||
strokeWidth="0.901765"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M10.854 15.9971C7.95036 15.9971 5.59375 13.6405 5.59375 10.7369C5.59375 7.83317 7.95036 5.47656 10.854 5.47656C13.7577 5.47656 16.1143 7.83317 16.1143 10.7369"
|
||||
stroke="#6F42C1"
|
||||
strokeWidth="0.901765"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M9.05078 3.97656H12.6578"
|
||||
stroke="#6F42C1"
|
||||
strokeWidth="0.901765"
|
||||
strokeMiterlimit="10"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M12.5977 13.898V13.2007C12.5977 12.341 13.2109 11.9863 13.9563 12.4191L14.5575 12.7678L15.1587 13.1165C15.9041 13.5494 15.9041 14.2527 15.1587 14.6856L14.5575 15.0343L13.9563 15.3829C13.2109 15.8158 12.5977 15.4611 12.5977 14.6014V13.898Z"
|
||||
stroke="#6F42C1"
|
||||
strokeWidth="0.901765"
|
||||
strokeMiterlimit="10"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const EndIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="21"
|
||||
height="20"
|
||||
viewBox="0 0 21 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M10.8542 7.58594V10.5918"
|
||||
stroke="#6F42C1"
|
||||
strokeWidth="0.901765"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M10.854 15.9971C7.95036 15.9971 5.59375 13.6405 5.59375 10.7369C5.59375 7.83317 7.95036 5.47656 10.854 5.47656C13.7577 5.47656 16.1143 7.83317 16.1143 10.7369"
|
||||
stroke="#6F42C1"
|
||||
strokeWidth="0.901765"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M9.05078 3.97656H12.6578"
|
||||
stroke="#6F42C1"
|
||||
strokeWidth="0.901765"
|
||||
strokeMiterlimit="10"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M12.5977 13.898V13.2007C12.5977 12.341 13.2109 11.9863 13.9563 12.4191L14.5575 12.7678L15.1587 13.1165C15.9041 13.5494 15.9041 14.2527 15.1587 14.6856L14.5575 15.0343L13.9563 15.3829C13.2109 15.8158 12.5977 15.4611 12.5977 14.6014V13.898Z"
|
||||
stroke="#6F42C1"
|
||||
strokeWidth="0.901765"
|
||||
strokeMiterlimit="10"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const SpeedIcon = () => {
|
||||
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="M9.55992 9.81727L4.10352 6.17969V14.7664L9.55992 11.1288V14.7664L16 10.4731L9.55992 6.17969V9.81727ZM5.1948 12.7273V8.21877L8.57624 10.4731L5.1948 12.7273ZM10.6512 12.7273V8.21877L14.0326 10.4731L10.6512 12.7273Z"
|
||||
fill="#2B3344"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
// export const DublicateIcon = () => {
|
||||
// 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="M14.3125 11.375C14.3125 11.7545 14.0045 12.0625 13.625 12.0625H8.125C7.7455 12.0625 7.4375 11.7545 7.4375 11.375V5.875C7.4375 5.4955 7.7455 5.1875 8.125 5.1875H13.625C14.0045 5.1875 14.3125 5.4955 14.3125 5.875V11.375ZM13.625 4.5H8.125C7.36566 4.5 6.75 5.11566 6.75 5.875V11.375C6.75 12.1343 7.36566 12.75 8.125 12.75H13.625C14.3843 12.75 15 12.1343 15 11.375V5.875C15 5.11566 14.3843 4.5 13.625 4.5ZM11.5625 14.125C11.5625 14.5045 11.2545 14.8125 10.875 14.8125H5.375C4.9955 14.8125 4.6875 14.5045 4.6875 14.125V8.625C4.6875 8.2455 4.9955 7.9375 5.375 7.9375H6.0625V7.25H5.375C4.61566 7.25 4 7.86566 4 8.625V14.125C4 14.8843 4.61566 15.5 5.375 15.5H10.875C11.6343 15.5 12.25 14.8843 12.25 14.125V13.4375H11.5625V14.125Z"
|
||||
// fill="var(--text-color)"
|
||||
// />
|
||||
// </svg>
|
||||
// );
|
||||
// };
|
||||
|
||||
@@ -124,7 +124,6 @@ export function LogoIconLarge() {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle cx="45" cy="45" r="45" fill="#FCFDFD" />
|
||||
<circle
|
||||
cx="45.1957"
|
||||
cy="45.1957"
|
||||
|
||||
@@ -9,8 +9,8 @@ export function ThroughputSummaryIcon() {
|
||||
>
|
||||
<circle cx="13.3457" cy="13.498" r="12.6543" fill="#FC9D2F" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M13.9063 12.9046L14.2265 13.86L14.4378 14.5073C14.9906 16.2239 15.2594 17.2662 15.2594 17.7299C15.2594 18.8219 14.3742 19.7072 13.2822 19.7072C12.1902 19.7072 11.305 18.8219 11.305 17.7299C11.305 17.2106 11.6422 15.9654 12.3379 13.86L12.658 12.9046C12.8604 12.3082 13.704 12.3082 13.9063 12.9046ZM13.2822 7.84375C16.9222 7.84375 19.873 10.7945 19.873 14.4345C19.873 15.7565 19.4823 17.0219 18.7621 18.0974C18.5596 18.3999 18.1502 18.4809 17.8478 18.2784C17.5453 18.0758 17.4643 17.6665 17.6668 17.364C18.2428 16.5038 18.5548 15.4933 18.5548 14.4345C18.5548 11.5225 16.1942 9.16191 13.2822 9.16191C10.3702 9.16191 8.00956 11.5225 8.00956 14.4345C8.00956 15.4933 8.32153 16.5038 8.89752 17.364C9.10005 17.6665 9.01904 18.0758 8.71659 18.2784C8.41414 18.4809 8.00477 18.3999 7.80224 18.0974C7.08206 17.0219 6.69141 15.7565 6.69141 14.4345C6.69141 10.7945 9.6422 7.84375 13.2822 7.84375ZM13.2822 15.2247L13.0657 15.9238L12.9161 16.4319C12.7219 17.111 12.6231 17.5509 12.6231 17.7299C12.6231 18.0939 12.9182 18.389 13.2822 18.389C13.6462 18.389 13.9413 18.0939 13.9413 17.7299C13.9413 17.511 13.7936 16.9022 13.5044 15.9428L13.2822 15.2247Z"
|
||||
fill="white"
|
||||
/>
|
||||
@@ -28,8 +28,8 @@ export function ProductionCapacityIcon() {
|
||||
>
|
||||
<circle cx="13.3457" cy="13.498" r="12.6543" fill="#FC9D2F" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M13.9063 12.9046L14.2265 13.86L14.4378 14.5073C14.9906 16.2239 15.2594 17.2662 15.2594 17.7299C15.2594 18.8219 14.3742 19.7072 13.2822 19.7072C12.1902 19.7072 11.305 18.8219 11.305 17.7299C11.305 17.2106 11.6422 15.9654 12.3379 13.86L12.658 12.9046C12.8604 12.3082 13.704 12.3082 13.9063 12.9046ZM13.2822 7.84375C16.9222 7.84375 19.873 10.7945 19.873 14.4345C19.873 15.7565 19.4823 17.0219 18.7621 18.0974C18.5596 18.3999 18.1502 18.4809 17.8478 18.2784C17.5453 18.0758 17.4643 17.6665 17.6668 17.364C18.2428 16.5038 18.5548 15.4933 18.5548 14.4345C18.5548 11.5225 16.1942 9.16191 13.2822 9.16191C10.3702 9.16191 8.00956 11.5225 8.00956 14.4345C8.00956 15.4933 8.32153 16.5038 8.89752 17.364C9.10005 17.6665 9.01904 18.0758 8.71659 18.2784C8.41414 18.4809 8.00477 18.3999 7.80224 18.0974C7.08206 17.0219 6.69141 15.7565 6.69141 14.4345C6.69141 10.7945 9.6422 7.84375 13.2822 7.84375ZM13.2822 15.2247L13.0657 15.9238L12.9161 16.4319C12.7219 17.111 12.6231 17.5509 12.6231 17.7299C12.6231 18.0939 12.9182 18.389 13.2822 18.389C13.6462 18.389 13.9413 18.0939 13.9413 17.7299C13.9413 17.511 13.7936 16.9022 13.5044 15.9428L13.2822 15.2247Z"
|
||||
fill="white"
|
||||
/>
|
||||
@@ -49,12 +49,12 @@ export function ROISummaryIcon() {
|
||||
<path
|
||||
d="M6.00015 7.51562V19.0974H19.0002"
|
||||
stroke="white"
|
||||
stroke-linecap="round"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M6.50037 15.0553L10.3102 11.847C10.6984 11.52 11.2701 11.5358 11.6397 11.8837L15.0095 15.0553L19.5004 11.2734"
|
||||
stroke="white"
|
||||
stroke-linecap="round"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -23,16 +23,16 @@ const MarketPlaceBanner = () => {
|
||||
<path
|
||||
d="M167.189 2C154.638 36.335 104.466 106.204 4.18872 111"
|
||||
stroke="white"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
strokeWidth="3"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M10.662 118.326L1.59439 111.524L9.47334 103.374"
|
||||
stroke="white"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
strokeWidth="3"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
import { SettingsIcon, TrashIcon } from "../../icons/ExportCommonIcons";
|
||||
|
||||
const SidePannel: React.FC = () => {
|
||||
const userName = localStorage.getItem("userName") || "Anonymous";
|
||||
const userName = localStorage.getItem("userName") ?? "Anonymous";
|
||||
return (
|
||||
<div className="side-pannel-container">
|
||||
<div className="side-pannel-header">
|
||||
|
||||
@@ -17,12 +17,12 @@ const ConfirmationPopup: React.FC<ConfirmationPopupProps> = ({
|
||||
<div className="confirmation-modal">
|
||||
<p className="message">{message}</p>
|
||||
<div className="buttton-wrapper">
|
||||
<div className="confirmation-button" onClick={onConfirm}>
|
||||
<button className="confirmation-button" onClick={onConfirm}>
|
||||
OK
|
||||
</div>
|
||||
<div className="confirmation-button" onClick={onCancel}>
|
||||
</button>
|
||||
<button className="confirmation-button" onClick={onCancel}>
|
||||
Cancel
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,8 +5,8 @@ import Header from "./Header";
|
||||
import useToggleStore from "../../../store/useUIToggleStore";
|
||||
import Assets from "./Assets";
|
||||
import useModuleStore from "../../../store/useModuleStore";
|
||||
import Widgets from ".//visualization/widgets/Widgets";
|
||||
import Templates from "../../../modules//visualization/template/Templates";
|
||||
import Widgets from "./visualization/widgets/Widgets";
|
||||
import Templates from "../../../modules/visualization/template/Templates";
|
||||
import Search from "../../ui/inputs/Search";
|
||||
|
||||
const SideBarLeft: React.FC = () => {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useEffect, useRef, useMemo } from "react";
|
||||
import { Chart } from "chart.js/auto";
|
||||
// import { useThemeStore } from "../../../../../store/useThemeStore";
|
||||
|
||||
// Define Props Interface
|
||||
interface ChartComponentProps {
|
||||
@@ -29,7 +28,6 @@ const ChartComponent = ({
|
||||
data: propsData,
|
||||
}: ChartComponentProps) => {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
// const { themeColor } = useThemeStore();
|
||||
|
||||
// Memoize Theme Colors to Prevent Unnecessary Recalculations
|
||||
// const buttonActionColor = useMemo(
|
||||
@@ -66,7 +64,7 @@ const ChartComponent = ({
|
||||
// Memoize Chart Font Style
|
||||
const chartFontStyle = useMemo(
|
||||
() => ({
|
||||
family: fontFamily || "Arial",
|
||||
family: fontFamily ?? "Arial",
|
||||
size: fontSizeValue,
|
||||
weight: fontWeightValue,
|
||||
color: "#2B3344",
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useState } from "react";
|
||||
import ToggleHeader from "../../../../ui/inputs/ToggleHeader";
|
||||
import Widgets2D from "./Widgets2D";
|
||||
import Widgets3D from "./Widgets3D";
|
||||
@@ -6,7 +5,6 @@ import WidgetsFloating from "./WidgetsFloating";
|
||||
import { useWidgetSubOption } from "../../../../../store/store";
|
||||
|
||||
const Widgets = () => {
|
||||
const [activeOption, setActiveOption] = useState("2D");
|
||||
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
||||
|
||||
const handleToggleClick = (option: string) => {
|
||||
|
||||
@@ -5,45 +5,14 @@ import {
|
||||
GlobeIcon,
|
||||
WalletIcon,
|
||||
} from "../../../../icons/3dChartIcons";
|
||||
import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard";
|
||||
import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard";
|
||||
|
||||
import WarehouseThroughput from "../../../../../modules//visualization/widgets/floating/cards/WarehouseThroughput";
|
||||
import ProductivityDashboard from "../../../../../modules//visualization/widgets/floating/cards/ProductivityDashboard";
|
||||
import FleetEfficiency from "../../../../../modules//visualization/widgets/floating/cards/FleetEfficiency";
|
||||
|
||||
interface Widget {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const WidgetsFloating = () => {
|
||||
// const [widgets, setWidgets] = useState<Widget[]>([
|
||||
// { id: "1", name: "Working State Widget" },
|
||||
// { id: "2", name: "Floating Widget 2" },
|
||||
// { id: "3", name: "Floating Widget 3" },
|
||||
// { id: "4", name: "Floating Widget 4" },
|
||||
// ]);
|
||||
|
||||
// Function to handle drag start
|
||||
const handleDragStart = (
|
||||
e: React.DragEvent<HTMLDivElement>,
|
||||
widget: Widget
|
||||
) => {
|
||||
e.dataTransfer.setData("application/json", JSON.stringify(widget));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="floatingWidgets-wrapper widgets-wrapper">
|
||||
{/* {widgets.map((widget) => (
|
||||
<div
|
||||
key={widget.id}
|
||||
className="floating"
|
||||
draggable
|
||||
onDragStart={(e) => handleDragStart(e, widget)}
|
||||
>
|
||||
{widget.name}
|
||||
</div>
|
||||
))} */}
|
||||
{/* Floating 1 */}
|
||||
<SimpleCard
|
||||
header={"Today’s Earnings"}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import Header from "./Header";
|
||||
import useModuleStore, {
|
||||
useSubModuleStore,
|
||||
@@ -14,6 +14,10 @@ import Visualization from "./visualization/Visualization";
|
||||
import Analysis from "./analysis/Analysis";
|
||||
import Simulations from "./simulation/Simulations";
|
||||
import { useSelectedFloorItem } from "../../../store/store";
|
||||
import {
|
||||
useSelectedEventData,
|
||||
useSelectedEventSphere,
|
||||
} from "../../../store/simulation/useSimulationStore";
|
||||
import GlobalProperties from "./properties/GlobalProperties";
|
||||
import AsstePropertiies from "./properties/AssetProperties";
|
||||
import ZoneProperties from "./properties/ZoneProperties";
|
||||
@@ -24,88 +28,70 @@ const SideBarRight: React.FC = () => {
|
||||
const { toggleUI } = useToggleStore();
|
||||
const { subModule, setSubModule } = useSubModuleStore();
|
||||
const { selectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
|
||||
// Reset activeList whenever activeModule changes
|
||||
useEffect(() => {
|
||||
if (activeModule !== "simulation") setSubModule("properties");
|
||||
if (activeModule === "simulation") setSubModule("mechanics");
|
||||
}, [activeModule]);
|
||||
if (activeModule === "simulation") setSubModule("simulations");
|
||||
}, [activeModule, setSubModule]);
|
||||
|
||||
// romove late
|
||||
const dummyData = {
|
||||
assetType: "store",
|
||||
selectedPoint: {
|
||||
name: "Point A",
|
||||
uuid: "123e4567-e89b-12d3-a456-426614174000",
|
||||
actions: [
|
||||
{
|
||||
uuid: "action-1",
|
||||
name: "Action One",
|
||||
},
|
||||
{
|
||||
uuid: "action-2",
|
||||
name: "Action Two",
|
||||
},
|
||||
{
|
||||
uuid: "action-3",
|
||||
name: "Action Three",
|
||||
},
|
||||
],
|
||||
},
|
||||
selectedItem: {
|
||||
item: {
|
||||
uuid: "item-1",
|
||||
name: "Item One",
|
||||
isUsed: false,
|
||||
},
|
||||
},
|
||||
setSelectedPoint: (value: string) => {
|
||||
console.log(`Selected point updated to: ${value}`);
|
||||
},
|
||||
selectedActionSphere: "Sphere A",
|
||||
};
|
||||
useEffect(() => {
|
||||
if (
|
||||
activeModule !== "mechanics" &&
|
||||
selectedEventData &&
|
||||
selectedEventSphere
|
||||
) {
|
||||
setSubModule("mechanics");
|
||||
} else if (!selectedEventData && !selectedEventSphere) {
|
||||
if (activeModule === "simulation") {
|
||||
setSubModule("simulations");
|
||||
}
|
||||
}
|
||||
}, [activeModule, selectedEventData, selectedEventSphere, setSubModule]);
|
||||
|
||||
return (
|
||||
<div className="sidebar-right-wrapper">
|
||||
<Header />
|
||||
{toggleUI && (
|
||||
<div className="sidebar-actions-container">
|
||||
{/* {activeModule === "builder" && ( */}
|
||||
<div
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "properties" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("properties")}
|
||||
>
|
||||
<PropertiesIcon isActive={subModule === "properties"} />
|
||||
</div>
|
||||
{/* )} */}
|
||||
{activeModule !== "simulation" && (
|
||||
<button
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "properties" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("properties")}
|
||||
>
|
||||
<PropertiesIcon isActive={subModule === "properties"} />
|
||||
</button>
|
||||
)}
|
||||
{activeModule === "simulation" && (
|
||||
<>
|
||||
<div
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "mechanics" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("mechanics")}
|
||||
>
|
||||
<MechanicsIcon isActive={subModule === "mechanics"} />
|
||||
</div>
|
||||
<div
|
||||
<button
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "simulations" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("simulations")}
|
||||
>
|
||||
<SimulationIcon isActive={subModule === "simulations"} />
|
||||
</div>
|
||||
<div
|
||||
</button>
|
||||
<button
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "mechanics" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("mechanics")}
|
||||
>
|
||||
<MechanicsIcon isActive={subModule === "mechanics"} />
|
||||
</button>
|
||||
<button
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "analysis" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("analysis")}
|
||||
>
|
||||
<AnalysisIcon isActive={subModule === "analysis"} />
|
||||
</div>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@@ -141,13 +127,19 @@ const SideBarRight: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
{/* simulation */}
|
||||
|
||||
{toggleUI && activeModule === "simulation" && (
|
||||
<>
|
||||
{subModule === "simulations" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<Simulations />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{subModule === "mechanics" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<EventProperties {...dummyData} />
|
||||
<EventProperties />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -158,16 +150,8 @@ const SideBarRight: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{subModule === "simulations" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<Simulations />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* realtime visualization */}
|
||||
{toggleUI && activeModule === "visualization" && <Visualization />}
|
||||
</div>
|
||||
|
||||
@@ -1,208 +1,130 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown";
|
||||
import LabledDropdown from "../../../../ui/inputs/LabledDropdown";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
AddIcon,
|
||||
RemoveIcon,
|
||||
ResizeHeightIcon,
|
||||
} from "../../../../icons/ExportCommonIcons";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { handleResize } from "../../../../../functions/handleResizePannel";
|
||||
import { handleActionToggle } from "./functions/handleActionToggle";
|
||||
import { handleDeleteAction } from "./functions/handleDeleteAction";
|
||||
import DefaultAction from "./actions/DefaultAction";
|
||||
import SpawnAction from "./actions/SpawnAction";
|
||||
import SwapAction from "./actions/SwapAction";
|
||||
import DespawnAction from "./actions/DespawnAction";
|
||||
import TravelAction from "./actions/TravelAction";
|
||||
import PickAndPlaceAction from "./actions/PickAndPlaceAction";
|
||||
import ProcessAction from "./actions/ProcessAction";
|
||||
import StorageAction from "./actions/StorageAction";
|
||||
import Trigger from "./trigger/Trigger";
|
||||
useSelectedAsset,
|
||||
useSelectedEventData,
|
||||
useSelectedEventSphere,
|
||||
useSelectedProduct,
|
||||
} from "../../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||
import ConveyorMechanics from "./mechanics/conveyorMechanics";
|
||||
import VehicleMechanics from "./mechanics/vehicleMechanics";
|
||||
import RoboticArmMechanics from "./mechanics/roboticArmMechanics";
|
||||
import MachineMechanics from "./mechanics/machineMechanics";
|
||||
import StorageMechanics from "./mechanics/storageMechanics";
|
||||
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||
import { handleAddEventToProduct } from "../../../../../modules/simulation/events/points/functions/handleAddEventToProduct";
|
||||
|
||||
interface EventPropertiesProps {
|
||||
assetType: string;
|
||||
selectedPoint: {
|
||||
name: string;
|
||||
uuid: string;
|
||||
actions: {
|
||||
uuid: string;
|
||||
name: string;
|
||||
}[];
|
||||
const EventProperties: React.FC = () => {
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getEventByModelUuid } = useProductStore();
|
||||
const { selectedProduct } = useSelectedProduct();
|
||||
const [currentEventData, setCurrentEventData] = useState<EventsSchema | null>(
|
||||
null
|
||||
);
|
||||
const [assetType, setAssetType] = useState<string | null>(null);
|
||||
const { products, addEvent } = useProductStore();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
|
||||
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||
useEffect(() => {
|
||||
const event = getCurrentEventData();
|
||||
setCurrentEventData(event);
|
||||
|
||||
const type = determineAssetType(event);
|
||||
setAssetType(type);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedEventData, selectedProduct]);
|
||||
|
||||
const getCurrentEventData = () => {
|
||||
if (!selectedEventData?.data || !selectedProduct) return null;
|
||||
return (
|
||||
getEventByModelUuid(
|
||||
selectedProduct.productId,
|
||||
selectedEventData.data.modelUuid
|
||||
) ?? null
|
||||
);
|
||||
};
|
||||
selectedItem: {
|
||||
item: {
|
||||
uuid: string;
|
||||
name: string;
|
||||
} | null;
|
||||
};
|
||||
setSelectedPoint: (value: string) => void;
|
||||
selectedActionSphere: string;
|
||||
}
|
||||
|
||||
const EventProperties: React.FC<EventPropertiesProps> = ({
|
||||
assetType,
|
||||
selectedPoint,
|
||||
selectedItem,
|
||||
setSelectedPoint,
|
||||
selectedActionSphere,
|
||||
}) => {
|
||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||
const determineAssetType = (event: EventsSchema | null) => {
|
||||
if (!event) return null;
|
||||
|
||||
const [activeOption, setActiveOption] = useState("default");
|
||||
const [dummyactiveOption, setTypeOption] = useState("default");
|
||||
|
||||
const getAvailableActions = () => {
|
||||
if (assetType === "conveyor") {
|
||||
return {
|
||||
defaultOption: "default",
|
||||
options: ["default", "spawn", "swap", "despawn"],
|
||||
};
|
||||
}
|
||||
if (assetType === "vehicle") {
|
||||
return {
|
||||
defaultOption: "travel",
|
||||
options: ["travel"],
|
||||
};
|
||||
}
|
||||
if (assetType === "roboticArm") {
|
||||
return {
|
||||
defaultOption: "pickAndPlace",
|
||||
options: ["pickAndPlace"],
|
||||
};
|
||||
}
|
||||
if (assetType === "machine") {
|
||||
return {
|
||||
defaultOption: "process",
|
||||
options: ["process"],
|
||||
};
|
||||
}
|
||||
if (assetType === "store") {
|
||||
return {
|
||||
defaultOption: "store",
|
||||
options: ["store", "spawn"],
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
defaultOption: "default",
|
||||
options: ["default"],
|
||||
};
|
||||
switch (event.type) {
|
||||
case "transfer":
|
||||
return "conveyor";
|
||||
case "vehicle":
|
||||
return "vehicle";
|
||||
case "roboticArm":
|
||||
return "roboticArm";
|
||||
case "machine":
|
||||
return "machine";
|
||||
case "storageUnit":
|
||||
return "storageUnit";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="event-proprties-wrapper">
|
||||
<div className="header">
|
||||
<div className="header-value">{selectedPoint.name}</div>
|
||||
</div>
|
||||
<div className="global-props">
|
||||
<div className="property-list-container">
|
||||
{/* <div className="property-item">
|
||||
<LabledDropdown
|
||||
defaultOption={assetType}
|
||||
options={[]}
|
||||
onSelect={(option) => setTypeOption(option)}
|
||||
/>
|
||||
</div> */}
|
||||
<div className="property-item">
|
||||
<InputWithDropDown
|
||||
label="Speed"
|
||||
value="0.5"
|
||||
min={0}
|
||||
step={0.1}
|
||||
defaultValue="0.5"
|
||||
max={10}
|
||||
activeOption="s"
|
||||
onClick={() => {}}
|
||||
onChange={(value) => console.log(value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="property-item">
|
||||
<InputWithDropDown
|
||||
label="Delay"
|
||||
value="0.5"
|
||||
min={0}
|
||||
step={0.1}
|
||||
defaultValue="0.5"
|
||||
max={10}
|
||||
activeOption="s"
|
||||
onClick={() => {}}
|
||||
onChange={(value) => console.log(value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="actions-list-container">
|
||||
<div className="actions">
|
||||
{currentEventData && (
|
||||
<>
|
||||
<div className="header">
|
||||
<div className="header-value">Actions</div>
|
||||
<div className="add-button" onClick={() => {}}>
|
||||
<AddIcon /> Add
|
||||
<div className="header-value">
|
||||
{selectedEventData?.data.modelName}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="lists-main-container"
|
||||
ref={actionsContainerRef}
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
{selectedPoint?.actions.map((action) => (
|
||||
<div
|
||||
key={action.uuid}
|
||||
className={`list-item ${
|
||||
selectedItem.item?.uuid === action.uuid ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className="value"
|
||||
onClick={() => handleActionToggle(action.uuid)}
|
||||
{assetType === "conveyor" && <ConveyorMechanics />}
|
||||
{assetType === "vehicle" && <VehicleMechanics />}
|
||||
{assetType === "roboticArm" && <RoboticArmMechanics />}
|
||||
{assetType === "machine" && <MachineMechanics />}
|
||||
{assetType === "storageUnit" && <StorageMechanics />}
|
||||
</>
|
||||
)}
|
||||
{!currentEventData && selectedEventSphere && (
|
||||
<div className="no-event-selected">
|
||||
<p>
|
||||
<strong>Oops!</strong> It looks like this object doesn't have an
|
||||
event assigned yet. To continue, please link it to one of the
|
||||
products below.
|
||||
</p>
|
||||
|
||||
<div className="products-list">
|
||||
<p>
|
||||
<strong>Here are some products you can add it to:</strong>
|
||||
</p>
|
||||
<ul>
|
||||
{products.map((product) => (
|
||||
<li key={product.productId}>
|
||||
<button
|
||||
onClick={() =>
|
||||
handleAddEventToProduct({
|
||||
selectedAsset,
|
||||
addEvent,
|
||||
selectedProduct: {
|
||||
productId: product.productId,
|
||||
productName: product.productName,
|
||||
},
|
||||
clearSelectedAsset,
|
||||
})
|
||||
}
|
||||
>
|
||||
<RenameInput value={action.name} />
|
||||
</div>
|
||||
{selectedPoint?.actions.length > 1 && (
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleDeleteAction(action.uuid)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<AddIcon />
|
||||
{product.productName}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className="resize-icon"
|
||||
id="action-resize"
|
||||
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
|
||||
>
|
||||
<ResizeHeightIcon />
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="selected-actions-details">
|
||||
<div className="selected-actions-header">
|
||||
<RenameInput value="Action Name" />
|
||||
)}
|
||||
{!selectedEventSphere && (
|
||||
<div className="no-event-selected">
|
||||
<p>
|
||||
<strong>Oops!</strong> It looks like you haven't selected an event
|
||||
point yet. Please select an event to view its properties.
|
||||
</p>
|
||||
</div>
|
||||
<div className="selected-actions-list">
|
||||
<LabledDropdown
|
||||
defaultOption={getAvailableActions().defaultOption}
|
||||
options={getAvailableActions().options}
|
||||
onSelect={(option) => setActiveOption(option)}
|
||||
/>
|
||||
{activeOption === "default" && <DefaultAction />} {/* done */}
|
||||
{activeOption === "spawn" && <SpawnAction />} {/* done */}
|
||||
{activeOption === "swap" && <SwapAction />} {/* done */}
|
||||
{activeOption === "despawn" && <DespawnAction />} {/* done */}
|
||||
{activeOption === "travel" && <TravelAction />} {/* done */}
|
||||
{activeOption === "pickAndPlace" && <PickAndPlaceAction />} {/* done */}
|
||||
{activeOption === "process" && <ProcessAction />} {/* done */}
|
||||
{activeOption === "store" && <StorageAction />} {/* done */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="tirgger">
|
||||
<Trigger />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import React from "react";
|
||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||
|
||||
interface DelayActionProps {
|
||||
value: string;
|
||||
defaultValue: string;
|
||||
min: number;
|
||||
max: number;
|
||||
onChange: (value: string) => void;
|
||||
}
|
||||
|
||||
const DelayAction: React.FC<DelayActionProps> = ({
|
||||
value,
|
||||
defaultValue,
|
||||
min,
|
||||
max,
|
||||
onChange,
|
||||
}) => {
|
||||
return (
|
||||
<InputWithDropDown
|
||||
label="Delay"
|
||||
value={value}
|
||||
min={min}
|
||||
step={0.1}
|
||||
defaultValue={defaultValue}
|
||||
max={max}
|
||||
activeOption="s"
|
||||
onClick={() => {}}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DelayAction;
|
||||
@@ -1,20 +1,8 @@
|
||||
import React from "react";
|
||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||
|
||||
const DespawnAction: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Delay"
|
||||
value=""
|
||||
min={0}
|
||||
step={0.1}
|
||||
max={10}
|
||||
defaultValue="0"
|
||||
activeOption="s"
|
||||
onClick={() => {}}
|
||||
onChange={(value) => console.log(value)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
import React from "react";
|
||||
import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
|
||||
|
||||
const PickAndPlaceAction: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<EyeDropInput label="Pick Point" value="na" onChange={() => {}} />
|
||||
<EyeDropInput label="Unload Point" value="na" onChange={() => {}} />
|
||||
</>
|
||||
);
|
||||
interface PickAndPlaceActionProps {
|
||||
pickPointValue: string;
|
||||
pickPointOnChange: (value: string) => void;
|
||||
placePointValue: string;
|
||||
placePointOnChange: (value: string) => void;
|
||||
}
|
||||
|
||||
const PickAndPlaceAction: React.FC<PickAndPlaceActionProps> = ({
|
||||
pickPointValue,
|
||||
pickPointOnChange,
|
||||
placePointValue,
|
||||
placePointOnChange,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<EyeDropInput label="Pick Point" value={pickPointValue} onChange={pickPointOnChange} />
|
||||
<EyeDropInput label="Unload Point" value={placePointValue} onChange={placePointOnChange} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PickAndPlaceAction;
|
||||
|
||||
@@ -2,23 +2,47 @@ import React from "react";
|
||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||
import SwapAction from "./SwapAction";
|
||||
|
||||
const ProcessAction: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Process Time"
|
||||
value="6"
|
||||
min={0}
|
||||
step={1}
|
||||
max={10}
|
||||
defaultValue="0"
|
||||
activeOption="s"
|
||||
onClick={() => {}}
|
||||
onChange={(value) => console.log(value)}
|
||||
/>
|
||||
<SwapAction />
|
||||
</>
|
||||
);
|
||||
interface ProcessActionProps {
|
||||
value: string;
|
||||
min: number;
|
||||
max: number;
|
||||
defaultValue: string;
|
||||
onChange: (value: string) => void;
|
||||
swapOptions: string[];
|
||||
swapDefaultOption: string;
|
||||
onSwapSelect: (value: string) => void;
|
||||
}
|
||||
|
||||
const ProcessAction: React.FC<ProcessActionProps> = ({
|
||||
value,
|
||||
min,
|
||||
max,
|
||||
defaultValue,
|
||||
onChange,
|
||||
swapOptions,
|
||||
swapDefaultOption,
|
||||
onSwapSelect,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Process Time"
|
||||
value={value}
|
||||
min={min}
|
||||
step={1}
|
||||
max={max}
|
||||
defaultValue={defaultValue}
|
||||
activeOption="s"
|
||||
onClick={() => { }}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<SwapAction
|
||||
options={swapOptions}
|
||||
defaultOption={swapDefaultOption}
|
||||
onSelect={onSwapSelect}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProcessAction;
|
||||
|
||||
@@ -1,35 +1,72 @@
|
||||
import React from "react";
|
||||
import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
|
||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||
|
||||
const SpawnAction: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Spawn interval"
|
||||
value="0"
|
||||
min={0}
|
||||
step={1}
|
||||
defaultValue="0"
|
||||
max={10}
|
||||
activeOption="s"
|
||||
onClick={() => {}}
|
||||
onChange={(value) => console.log(value)}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Spawn count"
|
||||
value="0"
|
||||
min={0}
|
||||
step={1}
|
||||
defaultValue="0"
|
||||
max={10}
|
||||
activeOption="s"
|
||||
onClick={() => {}}
|
||||
onChange={(value) => console.log(value)}
|
||||
/>
|
||||
<PreviewSelectionWithUpload />
|
||||
</>
|
||||
);
|
||||
interface SpawnActionProps {
|
||||
onChangeInterval: (value: string) => void;
|
||||
onChangeCount: (value: string) => void;
|
||||
defaultOption: string;
|
||||
options: string[];
|
||||
onSelect: (option: string) => void;
|
||||
intervalValue: string;
|
||||
countValue: string;
|
||||
intervalMin: number;
|
||||
intervalMax: number;
|
||||
intervalDefaultValue: string;
|
||||
countMin: number;
|
||||
countMax: number;
|
||||
countDefaultValue: string;
|
||||
}
|
||||
|
||||
const SpawnAction: React.FC<SpawnActionProps> = ({
|
||||
onChangeInterval,
|
||||
onChangeCount,
|
||||
defaultOption,
|
||||
options,
|
||||
onSelect,
|
||||
intervalValue,
|
||||
countValue,
|
||||
intervalMin,
|
||||
intervalMax,
|
||||
intervalDefaultValue,
|
||||
countMin,
|
||||
countMax,
|
||||
countDefaultValue,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Spawn interval"
|
||||
value={intervalValue}
|
||||
min={intervalMin}
|
||||
step={1}
|
||||
defaultValue={intervalDefaultValue}
|
||||
max={intervalMax}
|
||||
activeOption="s"
|
||||
onClick={() => { }}
|
||||
onChange={onChangeInterval}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Spawn count"
|
||||
value={countValue}
|
||||
min={countMin}
|
||||
step={1}
|
||||
defaultValue={countDefaultValue}
|
||||
max={countMax}
|
||||
activeOption="s"
|
||||
onClick={() => { }}
|
||||
onChange={onChangeCount}
|
||||
/>
|
||||
{/* <PreviewSelectionWithUpload /> */}
|
||||
<LabledDropdown
|
||||
label="Presets"
|
||||
defaultOption={defaultOption}
|
||||
options={options}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SpawnAction;
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
import React from "react";
|
||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||
|
||||
const StorageAction: React.FC = () => {
|
||||
return (
|
||||
<InputWithDropDown
|
||||
label="Storage Capacity"
|
||||
value=""
|
||||
min={0}
|
||||
step={0.1}
|
||||
max={10}
|
||||
defaultValue="0"
|
||||
activeOption="s"
|
||||
onClick={() => {}}
|
||||
onChange={(value) => console.log(value)}
|
||||
/>
|
||||
);
|
||||
interface StorageActionProps {
|
||||
value: string;
|
||||
min: number;
|
||||
max: number;
|
||||
defaultValue: string;
|
||||
onChange: (value: string) => void;
|
||||
}
|
||||
|
||||
const StorageAction: React.FC<StorageActionProps> = ({ value, min, max, defaultValue, onChange }) => {
|
||||
return (
|
||||
<InputWithDropDown
|
||||
label="Storage Capacity"
|
||||
value={value}
|
||||
min={min}
|
||||
step={1}
|
||||
max={max}
|
||||
defaultValue={defaultValue}
|
||||
activeOption="s"
|
||||
onClick={() => { }}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default StorageAction;
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
import React from "react";
|
||||
import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
|
||||
|
||||
const SwapAction: React.FC = () => {
|
||||
interface SwapActionProps {
|
||||
onSelect: (option: string) => void;
|
||||
defaultOption: string;
|
||||
options: string[];
|
||||
}
|
||||
|
||||
const SwapAction: React.FC<SwapActionProps> = ({
|
||||
onSelect,
|
||||
defaultOption,
|
||||
options,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<PreviewSelectionWithUpload />
|
||||
</>
|
||||
<PreviewSelectionWithUpload
|
||||
label="Presets"
|
||||
defaultOption={defaultOption}
|
||||
options={options}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,35 +2,77 @@ import React from "react";
|
||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||
import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
|
||||
|
||||
const TravelAction: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Load Capacity"
|
||||
value=""
|
||||
min={0}
|
||||
step={0.1}
|
||||
max={10}
|
||||
defaultValue="0"
|
||||
activeOption="s"
|
||||
onClick={() => {}}
|
||||
onChange={(value) => console.log(value)}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Unload Duration"
|
||||
value=""
|
||||
min={0}
|
||||
step={0.1}
|
||||
max={10}
|
||||
defaultValue="0"
|
||||
activeOption="s"
|
||||
onClick={() => {}}
|
||||
onChange={(value) => console.log(value)}
|
||||
/>
|
||||
<EyeDropInput label="Pick Point" value="na" onChange={() => {}} />
|
||||
<EyeDropInput label="Unload Point" value="na" onChange={() => {}} />
|
||||
</>
|
||||
);
|
||||
interface TravelActionProps {
|
||||
loadCapacity: {
|
||||
value: string;
|
||||
min: number;
|
||||
max: number;
|
||||
defaultValue: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
unloadDuration: {
|
||||
value: string;
|
||||
min: number;
|
||||
max: number;
|
||||
defaultValue: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
pickPoint?: {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
unloadPoint?: {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
}
|
||||
|
||||
const TravelAction: React.FC<TravelActionProps> = ({
|
||||
loadCapacity,
|
||||
unloadDuration,
|
||||
pickPoint,
|
||||
unloadPoint,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Load Capacity"
|
||||
value={loadCapacity.value}
|
||||
min={loadCapacity.min}
|
||||
max={loadCapacity.max}
|
||||
defaultValue={loadCapacity.defaultValue}
|
||||
step={0.1}
|
||||
activeOption="s"
|
||||
onClick={() => { }}
|
||||
onChange={loadCapacity.onChange}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Unload Duration"
|
||||
value={unloadDuration.value}
|
||||
min={unloadDuration.min}
|
||||
max={unloadDuration.max}
|
||||
defaultValue={unloadDuration.defaultValue}
|
||||
step={0.1}
|
||||
activeOption="s"
|
||||
onClick={() => { }}
|
||||
onChange={unloadDuration.onChange}
|
||||
/>
|
||||
{pickPoint && (
|
||||
<EyeDropInput
|
||||
label="Pick Point"
|
||||
value={pickPoint.value}
|
||||
onChange={pickPoint.onChange}
|
||||
/>
|
||||
)}
|
||||
{unloadPoint && (
|
||||
<EyeDropInput
|
||||
label="Unload Point"
|
||||
value={unloadPoint.value}
|
||||
onChange={unloadPoint.onChange}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default TravelAction;
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
import React, { useRef } from "react";
|
||||
import {
|
||||
AddIcon,
|
||||
RemoveIcon,
|
||||
ResizeHeightIcon,
|
||||
} from "../../../../../icons/ExportCommonIcons";
|
||||
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||
import { handleResize } from "../../../../../../functions/handleResizePannel";
|
||||
import {
|
||||
useSelectedAction,
|
||||
useSelectedEventData,
|
||||
useSelectedProduct,
|
||||
} from "../../../../../../store/simulation/useSimulationStore";
|
||||
import { MathUtils } from "three";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
|
||||
interface ActionsListProps {
|
||||
setSelectedPointData: (data: any) => void; // You can replace `any` with a more specific type if you have one
|
||||
selectedPointData: any; // You can replace `any` with a more specific type if you have one
|
||||
// ui control props
|
||||
multipleAction?: boolean;
|
||||
}
|
||||
|
||||
const ActionsList: React.FC<ActionsListProps> = ({
|
||||
setSelectedPointData,
|
||||
selectedPointData,
|
||||
multipleAction = false,
|
||||
}) => {
|
||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// store
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { updateAction, addAction, removeAction } = useProductStore();
|
||||
const { selectedProduct } = useSelectedProduct();
|
||||
const { selectedAction, setSelectedAction, clearSelectedAction } =
|
||||
useSelectedAction();
|
||||
|
||||
const handleAddAction = () => {
|
||||
if (!selectedEventData || !selectedPointData) return;
|
||||
|
||||
const newAction = {
|
||||
actionUuid: MathUtils.generateUUID(),
|
||||
actionName: `Action ${selectedPointData.actions.length + 1}`,
|
||||
actionType: "pickAndPlace" as const,
|
||||
process: {
|
||||
startPoint: null,
|
||||
endPoint: null,
|
||||
},
|
||||
triggers: [] as TriggerSchema[],
|
||||
};
|
||||
|
||||
addAction(
|
||||
selectedProduct.productId,
|
||||
selectedEventData.data.modelUuid,
|
||||
selectedEventData.selectedPoint,
|
||||
newAction
|
||||
);
|
||||
|
||||
const updatedPoint = {
|
||||
...selectedPointData,
|
||||
actions: [...selectedPointData.actions, newAction],
|
||||
};
|
||||
setSelectedPointData(updatedPoint);
|
||||
setSelectedAction(newAction.actionUuid, newAction.actionName);
|
||||
};
|
||||
|
||||
const handleDeleteAction = (actionUuid: string) => {
|
||||
if (!selectedPointData) return;
|
||||
|
||||
removeAction(actionUuid);
|
||||
const newActions = selectedPointData.actions.filter(
|
||||
(a: any) => a.actionUuid !== actionUuid
|
||||
);
|
||||
|
||||
const updatedPoint = {
|
||||
...selectedPointData,
|
||||
actions: newActions,
|
||||
};
|
||||
setSelectedPointData(updatedPoint);
|
||||
|
||||
if (selectedAction.actionId === actionUuid) {
|
||||
if (newActions.length > 0) {
|
||||
setSelectedAction(newActions[0].actionUuid, newActions[0].actionName);
|
||||
} else {
|
||||
clearSelectedAction();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleRenameAction = (newName: string) => {
|
||||
if (!selectedAction.actionId) return;
|
||||
updateAction(selectedAction.actionId, { actionName: newName });
|
||||
|
||||
if (selectedPointData?.actions) {
|
||||
const updatedActions = selectedPointData.actions.map((action: any) =>
|
||||
action.actionUuid === selectedAction.actionId
|
||||
? { ...action, actionName: newName }
|
||||
: action
|
||||
);
|
||||
setSelectedPointData({
|
||||
...selectedPointData,
|
||||
actions: updatedActions,
|
||||
});
|
||||
} else {
|
||||
// write logic for single action
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const handleActionSelect = (actionUuid: string, actionName: string) => {
|
||||
setSelectedAction(actionUuid, actionName);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="actions-list-container">
|
||||
<div className="actions">
|
||||
<div className="header">
|
||||
<div className="header-value">Actions</div>
|
||||
|
||||
<button
|
||||
className="add-button"
|
||||
onClick={() => handleAddAction()}
|
||||
disabled={!multipleAction}
|
||||
>
|
||||
<AddIcon /> Add
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="lists-main-container"
|
||||
ref={actionsContainerRef}
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
{multipleAction &&
|
||||
selectedPointData.actions.map((action: any) => (
|
||||
<div
|
||||
key={action.actionUuid}
|
||||
className={`list-item ${
|
||||
selectedAction.actionId === action.actionUuid
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
className="value"
|
||||
onClick={() =>
|
||||
handleActionSelect(action.actionUuid, action.actionName)
|
||||
}
|
||||
>
|
||||
<RenameInput
|
||||
value={action.actionName}
|
||||
onRename={handleRenameAction}
|
||||
/>
|
||||
</button>
|
||||
{selectedPointData.actions.length > 1 && (
|
||||
<button
|
||||
className="remove-button"
|
||||
onClick={() => handleDeleteAction(action.actionUuid)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{!multipleAction && selectedPointData && (
|
||||
<div
|
||||
key={selectedPointData.action.actionUuid}
|
||||
className={`list-item active`}
|
||||
>
|
||||
<button
|
||||
className="value"
|
||||
onClick={() =>
|
||||
handleActionSelect(
|
||||
selectedPointData.action.actionUuid,
|
||||
selectedPointData.action.actionName
|
||||
)
|
||||
}
|
||||
>
|
||||
<RenameInput
|
||||
value={selectedPointData.action.actionName}
|
||||
onRename={handleRenameAction}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{multipleAction && (
|
||||
<button
|
||||
className="resize-icon"
|
||||
id="action-resize"
|
||||
onMouseDown={(e: any) => handleResize(e, actionsContainerRef)}
|
||||
>
|
||||
<ResizeHeightIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ActionsList;
|
||||
@@ -0,0 +1,224 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||
import DelayAction from "../actions/DelayAction";
|
||||
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||
import DespawnAction from "../actions/DespawnAction";
|
||||
import SwapAction from "../actions/SwapAction";
|
||||
import SpawnAction from "../actions/SpawnAction";
|
||||
import DefaultAction from "../actions/DefaultAction";
|
||||
import Trigger from "../trigger/Trigger";
|
||||
import {
|
||||
useSelectedEventData,
|
||||
useSelectedProduct,
|
||||
} from "../../../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
import ActionsList from "../components/ActionsList";
|
||||
|
||||
function ConveyorMechanics() {
|
||||
const [activeOption, setActiveOption] = useState<
|
||||
"default" | "spawn" | "swap" | "delay" | "despawn"
|
||||
>("default");
|
||||
const [selectedPointData, setSelectedPointData] = useState<
|
||||
ConveyorPointSchema | undefined
|
||||
>();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
|
||||
const { selectedProduct } = useSelectedProduct();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEventData) {
|
||||
const point = getPointByUuid(
|
||||
selectedProduct.productId,
|
||||
selectedEventData?.data.modelUuid,
|
||||
selectedEventData?.selectedPoint
|
||||
) as ConveyorPointSchema | undefined;
|
||||
if (point && "action" in point) {
|
||||
setSelectedPointData(point);
|
||||
setActiveOption(
|
||||
point.action.actionType as
|
||||
| "default"
|
||||
| "spawn"
|
||||
| "swap"
|
||||
| "delay"
|
||||
| "despawn"
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [selectedProduct, selectedEventData, getPointByUuid]);
|
||||
|
||||
const handleSpeedChange = (value: string) => {
|
||||
if (!selectedEventData) return;
|
||||
updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
|
||||
speed: parseFloat(value),
|
||||
});
|
||||
};
|
||||
|
||||
const handleActionTypeChange = (option: string) => {
|
||||
if (!selectedEventData || !selectedPointData) return;
|
||||
const validOption = option as
|
||||
| "default"
|
||||
| "spawn"
|
||||
| "swap"
|
||||
| "delay"
|
||||
| "despawn";
|
||||
setActiveOption(validOption);
|
||||
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
actionType: validOption,
|
||||
});
|
||||
};
|
||||
|
||||
const handleRenameAction = (newName: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
|
||||
};
|
||||
|
||||
const handleSpawnCountChange = (value: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
spawnCount: value === "inherit" ? "inherit" : parseFloat(value),
|
||||
});
|
||||
};
|
||||
|
||||
const handleSpawnIntervalChange = (value: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
spawnInterval: value === "inherit" ? "inherit" : parseFloat(value),
|
||||
});
|
||||
};
|
||||
|
||||
const handleMaterialSelect = (material: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, { material });
|
||||
};
|
||||
|
||||
const handleDelayChange = (value: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
delay: value === "inherit" ? "inherit" : parseFloat(value),
|
||||
});
|
||||
};
|
||||
|
||||
const availableActions = {
|
||||
defaultOption: "default",
|
||||
options: ["default", "spawn", "swap", "delay", "despawn"],
|
||||
};
|
||||
|
||||
// Get current values from store
|
||||
const currentSpeed =
|
||||
selectedEventData?.data.type === "transfer"
|
||||
? selectedEventData.data.speed.toString()
|
||||
: "0.5";
|
||||
|
||||
const currentActionName = selectedPointData
|
||||
? selectedPointData.action.actionName
|
||||
: "Action Name";
|
||||
|
||||
const currentMaterial = selectedPointData
|
||||
? selectedPointData.action.material
|
||||
: "Default material";
|
||||
|
||||
const currentSpawnCount = selectedPointData
|
||||
? selectedPointData.action.spawnCount?.toString() || "1"
|
||||
: "1";
|
||||
|
||||
const currentSpawnInterval = selectedPointData
|
||||
? selectedPointData.action.spawnInterval?.toString() || "1"
|
||||
: "1";
|
||||
|
||||
const currentDelay = selectedPointData
|
||||
? selectedPointData.action.delay?.toString() || "0"
|
||||
: "0";
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedEventData && (
|
||||
<>
|
||||
<div key={selectedPointData?.uuid} className="global-props">
|
||||
<div className="property-list-container">
|
||||
<div className="property-item">
|
||||
<InputWithDropDown
|
||||
label="Speed"
|
||||
value={currentSpeed}
|
||||
min={0}
|
||||
step={0.1}
|
||||
defaultValue={"0.5"}
|
||||
max={10}
|
||||
activeOption="m/s"
|
||||
onClick={() => {}}
|
||||
onChange={handleSpeedChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ActionsList
|
||||
setSelectedPointData={setSelectedPointData}
|
||||
selectedPointData={selectedPointData}
|
||||
/>
|
||||
|
||||
<div className="selected-actions-details">
|
||||
<div className="selected-actions-header">
|
||||
<RenameInput
|
||||
value={currentActionName}
|
||||
onRename={handleRenameAction}
|
||||
/>
|
||||
</div>
|
||||
<div className="selected-actions-list">
|
||||
<LabledDropdown
|
||||
defaultOption={
|
||||
selectedPointData
|
||||
? selectedPointData.action.actionType
|
||||
: "default"
|
||||
}
|
||||
options={availableActions.options}
|
||||
onSelect={handleActionTypeChange}
|
||||
/>
|
||||
{activeOption === "default" && <DefaultAction />}
|
||||
{activeOption === "spawn" && (
|
||||
<SpawnAction
|
||||
onChangeCount={handleSpawnCountChange}
|
||||
options={["Default material", "Material 1", "Material 2"]}
|
||||
defaultOption={currentMaterial}
|
||||
onSelect={handleMaterialSelect}
|
||||
onChangeInterval={handleSpawnIntervalChange}
|
||||
intervalValue={currentSpawnInterval}
|
||||
countValue={currentSpawnCount}
|
||||
intervalMin={1}
|
||||
intervalMax={60}
|
||||
intervalDefaultValue="1"
|
||||
countMin={1}
|
||||
countMax={100}
|
||||
countDefaultValue="1"
|
||||
/>
|
||||
)}
|
||||
{activeOption === "swap" && (
|
||||
<SwapAction
|
||||
options={["Default material", "Material 1", "Material 2"]}
|
||||
defaultOption={currentMaterial}
|
||||
onSelect={handleMaterialSelect}
|
||||
/>
|
||||
)}
|
||||
{activeOption === "despawn" && <DespawnAction />}
|
||||
{activeOption === "delay" && (
|
||||
<DelayAction
|
||||
value={currentDelay}
|
||||
defaultValue="0"
|
||||
min={0}
|
||||
max={60}
|
||||
onChange={handleDelayChange}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="tirgger">
|
||||
<Trigger />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ConveyorMechanics;
|
||||
@@ -0,0 +1,129 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||
import Trigger from "../trigger/Trigger";
|
||||
import {
|
||||
useSelectedEventData,
|
||||
useSelectedProduct,
|
||||
} from "../../../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
import ProcessAction from "../actions/ProcessAction";
|
||||
import ActionsList from "../components/ActionsList";
|
||||
|
||||
function MachineMechanics() {
|
||||
const [activeOption, setActiveOption] = useState<"default" | "process">(
|
||||
"default"
|
||||
);
|
||||
const [selectedPointData, setSelectedPointData] = useState<
|
||||
MachinePointSchema | undefined
|
||||
>();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getPointByUuid, updateAction } = useProductStore();
|
||||
const { selectedProduct } = useSelectedProduct();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEventData) {
|
||||
const point = getPointByUuid(
|
||||
selectedProduct.productId,
|
||||
selectedEventData?.data.modelUuid,
|
||||
selectedEventData?.selectedPoint
|
||||
) as MachinePointSchema | undefined;
|
||||
if (point && "action" in point) {
|
||||
setSelectedPointData(point);
|
||||
setActiveOption(point.action.actionType as "process");
|
||||
}
|
||||
}
|
||||
}, [selectedProduct, selectedEventData, getPointByUuid]);
|
||||
|
||||
const handleActionTypeChange = (option: string) => {
|
||||
if (!selectedEventData || !selectedPointData) return;
|
||||
const validOption = option as "process";
|
||||
setActiveOption(validOption);
|
||||
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
actionType: validOption,
|
||||
});
|
||||
};
|
||||
|
||||
const handleRenameAction = (newName: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
|
||||
};
|
||||
|
||||
const handleProcessTimeChange = (value: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
processTime: parseFloat(value),
|
||||
});
|
||||
};
|
||||
|
||||
const handleMaterialSelect = (material: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
swapMaterial: material,
|
||||
});
|
||||
};
|
||||
|
||||
// Get current values from store
|
||||
const currentActionName = selectedPointData
|
||||
? selectedPointData.action.actionName
|
||||
: "Action Name";
|
||||
|
||||
const currentProcessTime = selectedPointData
|
||||
? selectedPointData.action.processTime.toString()
|
||||
: "1";
|
||||
|
||||
const currentMaterial = selectedPointData
|
||||
? selectedPointData.action.swapMaterial
|
||||
: "Default material";
|
||||
|
||||
const availableActions = {
|
||||
defaultOption: "process",
|
||||
options: ["process"],
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedEventData && (
|
||||
<>
|
||||
<div className="selected-actions-details">
|
||||
<div className="selected-actions-header">
|
||||
<RenameInput
|
||||
value={currentActionName}
|
||||
onRename={handleRenameAction}
|
||||
/>
|
||||
</div>
|
||||
<ActionsList
|
||||
setSelectedPointData={setSelectedPointData}
|
||||
selectedPointData={selectedPointData}
|
||||
/>
|
||||
<div className="selected-actions-list">
|
||||
<LabledDropdown
|
||||
defaultOption="process"
|
||||
options={availableActions.options}
|
||||
onSelect={handleActionTypeChange}
|
||||
/>
|
||||
{activeOption === "process" && (
|
||||
<ProcessAction
|
||||
value={currentProcessTime}
|
||||
min={0.1}
|
||||
max={60}
|
||||
defaultValue="1"
|
||||
onChange={handleProcessTimeChange}
|
||||
swapOptions={["Default material", "Material 1", "Material 2"]}
|
||||
swapDefaultOption={currentMaterial}
|
||||
onSwapSelect={handleMaterialSelect}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="tirgger">
|
||||
<Trigger />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default MachineMechanics;
|
||||
@@ -0,0 +1,194 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||
import Trigger from "../trigger/Trigger";
|
||||
import {
|
||||
useSelectedEventData,
|
||||
useSelectedProduct,
|
||||
useSelectedAction,
|
||||
} from "../../../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
import PickAndPlaceAction from "../actions/PickAndPlaceAction";
|
||||
import ActionsList from "../components/ActionsList";
|
||||
|
||||
function RoboticArmMechanics() {
|
||||
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">(
|
||||
"default"
|
||||
);
|
||||
const [selectedPointData, setSelectedPointData] = useState<
|
||||
RoboticArmPointSchema | undefined
|
||||
>();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
|
||||
const { selectedProduct } = useSelectedProduct();
|
||||
const { selectedAction, setSelectedAction, clearSelectedAction } =
|
||||
useSelectedAction();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEventData) {
|
||||
const point = getPointByUuid(
|
||||
selectedProduct.productId,
|
||||
selectedEventData.data.modelUuid,
|
||||
selectedEventData.selectedPoint
|
||||
) as RoboticArmPointSchema | undefined;
|
||||
if (point?.actions) {
|
||||
setSelectedPointData(point);
|
||||
setActiveOption(
|
||||
point.actions[0].actionType as "default" | "pickAndPlace"
|
||||
);
|
||||
if (point.actions.length > 0 && !selectedAction.actionId) {
|
||||
setSelectedAction(
|
||||
point.actions[0].actionUuid,
|
||||
point.actions[0].actionName
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
clearSelectedAction();
|
||||
}
|
||||
}, [
|
||||
clearSelectedAction,
|
||||
getPointByUuid,
|
||||
selectedAction.actionId,
|
||||
selectedEventData,
|
||||
selectedProduct,
|
||||
setSelectedAction,
|
||||
]);
|
||||
|
||||
const handleRenameAction = (newName: string) => {
|
||||
if (!selectedAction.actionId) return;
|
||||
updateAction(selectedAction.actionId, { actionName: newName });
|
||||
|
||||
if (selectedPointData) {
|
||||
const updatedActions = selectedPointData.actions.map((action) =>
|
||||
action.actionUuid === selectedAction.actionId
|
||||
? { ...action, actionName: newName }
|
||||
: action
|
||||
);
|
||||
setSelectedPointData({
|
||||
...selectedPointData,
|
||||
actions: updatedActions,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleSpeedChange = (value: string) => {
|
||||
if (!selectedEventData) return;
|
||||
updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
|
||||
speed: parseFloat(value),
|
||||
});
|
||||
};
|
||||
|
||||
const handlePickPointChange = (value: string) => {
|
||||
if (!selectedAction.actionId || !selectedPointData) return;
|
||||
const [x, y, z] = value.split(",").map(Number);
|
||||
|
||||
updateAction(selectedAction.actionId, {
|
||||
process: {
|
||||
startPoint: [x, y, z] as [number, number, number],
|
||||
endPoint:
|
||||
selectedPointData.actions.find(
|
||||
(a) => a.actionUuid === selectedAction.actionId
|
||||
)?.process.endPoint || null,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handlePlacePointChange = (value: string) => {
|
||||
if (!selectedAction.actionId || !selectedPointData) return;
|
||||
const [x, y, z] = value.split(",").map(Number);
|
||||
|
||||
updateAction(selectedAction.actionId, {
|
||||
process: {
|
||||
startPoint:
|
||||
selectedPointData.actions.find(
|
||||
(a) => a.actionUuid === selectedAction.actionId
|
||||
)?.process.startPoint || null,
|
||||
endPoint: [x, y, z] as [number, number, number],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const availableActions = {
|
||||
defaultOption: "pickAndPlace",
|
||||
options: ["pickAndPlace"],
|
||||
};
|
||||
|
||||
const currentSpeed =
|
||||
selectedEventData?.data.type === "roboticArm"
|
||||
? selectedEventData.data.speed.toString()
|
||||
: "0.5";
|
||||
|
||||
const currentAction = selectedPointData?.actions.find(
|
||||
(a) => a.actionUuid === selectedAction.actionId
|
||||
);
|
||||
const currentPickPoint = currentAction?.process.startPoint
|
||||
? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}`
|
||||
: "";
|
||||
const currentPlacePoint = currentAction?.process.endPoint
|
||||
? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}`
|
||||
: "";
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedEventData && selectedPointData && (
|
||||
<>
|
||||
<div className="global-props">
|
||||
<div className="property-list-container">
|
||||
<div className="property-item">
|
||||
<InputWithDropDown
|
||||
label="Speed"
|
||||
value={currentSpeed}
|
||||
min={0}
|
||||
step={0.1}
|
||||
defaultValue={"0.5"}
|
||||
max={10}
|
||||
activeOption="m/s"
|
||||
onClick={() => {}}
|
||||
onChange={handleSpeedChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ActionsList
|
||||
setSelectedPointData={setSelectedPointData}
|
||||
selectedPointData={selectedPointData}
|
||||
multipleAction
|
||||
/>
|
||||
|
||||
{selectedAction.actionId && currentAction && (
|
||||
<div className="selected-actions-details">
|
||||
<div className="selected-actions-header">
|
||||
<RenameInput
|
||||
value={selectedAction.actionName}
|
||||
onRename={handleRenameAction}
|
||||
/>
|
||||
</div>
|
||||
<div className="selected-actions-list">
|
||||
<LabledDropdown
|
||||
defaultOption={activeOption}
|
||||
options={availableActions.options}
|
||||
onSelect={() => {}}
|
||||
disabled={true}
|
||||
/>
|
||||
<PickAndPlaceAction
|
||||
pickPointValue={currentPickPoint}
|
||||
pickPointOnChange={handlePickPointChange}
|
||||
placePointValue={currentPlacePoint}
|
||||
placePointOnChange={handlePlacePointChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="tirgger">
|
||||
<Trigger />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default RoboticArmMechanics;
|
||||
@@ -0,0 +1,120 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||
import Trigger from "../trigger/Trigger";
|
||||
import {
|
||||
useSelectedEventData,
|
||||
useSelectedProduct,
|
||||
} from "../../../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
import StorageAction from "../actions/StorageAction";
|
||||
import ActionsList from "../components/ActionsList";
|
||||
|
||||
function StorageMechanics() {
|
||||
const [activeOption, setActiveOption] = useState<
|
||||
"default" | "store" | "spawn"
|
||||
>("default");
|
||||
const [selectedPointData, setSelectedPointData] = useState<
|
||||
StoragePointSchema | undefined
|
||||
>();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getPointByUuid, updateAction } = useProductStore();
|
||||
const { selectedProduct } = useSelectedProduct();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEventData) {
|
||||
const point = getPointByUuid(
|
||||
selectedProduct.productId,
|
||||
selectedEventData?.data.modelUuid,
|
||||
selectedEventData?.selectedPoint
|
||||
) as StoragePointSchema | undefined;
|
||||
if (point && "action" in point) {
|
||||
setSelectedPointData(point);
|
||||
setActiveOption(point.action.actionType as "store" | "spawn");
|
||||
}
|
||||
}
|
||||
}, [selectedProduct, selectedEventData, getPointByUuid]);
|
||||
|
||||
const handleActionTypeChange = (option: string) => {
|
||||
if (!selectedEventData || !selectedPointData) return;
|
||||
const validOption = option as "store" | "spawn";
|
||||
setActiveOption(validOption);
|
||||
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
actionType: validOption,
|
||||
});
|
||||
};
|
||||
|
||||
const handleRenameAction = (newName: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
|
||||
};
|
||||
|
||||
const handleCapacityChange = (value: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
storageCapacity: parseInt(value),
|
||||
});
|
||||
};
|
||||
|
||||
// Get current values from store
|
||||
const currentActionName = selectedPointData
|
||||
? selectedPointData.action.actionName
|
||||
: "Action Name";
|
||||
|
||||
const currentCapacity = selectedPointData
|
||||
? selectedPointData.action.storageCapacity.toString()
|
||||
: "0";
|
||||
|
||||
const availableActions = {
|
||||
defaultOption: "store",
|
||||
options: ["store", "spawn"],
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedEventData && (
|
||||
<>
|
||||
<ActionsList
|
||||
setSelectedPointData={setSelectedPointData}
|
||||
selectedPointData={selectedPointData}
|
||||
/>
|
||||
<div className="selected-actions-details">
|
||||
<div className="selected-actions-header">
|
||||
<RenameInput
|
||||
value={currentActionName}
|
||||
onRename={handleRenameAction}
|
||||
/>
|
||||
</div>
|
||||
<div className="selected-actions-list">
|
||||
<LabledDropdown
|
||||
defaultOption={activeOption}
|
||||
options={availableActions.options}
|
||||
onSelect={handleActionTypeChange}
|
||||
/>
|
||||
{activeOption === "store" && (
|
||||
<StorageAction
|
||||
value={currentCapacity}
|
||||
defaultValue="0"
|
||||
min={0}
|
||||
max={20}
|
||||
onChange={handleCapacityChange}
|
||||
/>
|
||||
)}
|
||||
{activeOption === "spawn" && (
|
||||
<div className="spawn-options">
|
||||
<p>Spawn configuration options would go here</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="tirgger">
|
||||
<Trigger />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default StorageMechanics;
|
||||
@@ -0,0 +1,199 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||
import Trigger from "../trigger/Trigger";
|
||||
import {
|
||||
useSelectedEventData,
|
||||
useSelectedProduct,
|
||||
} from "../../../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
import TravelAction from "../actions/TravelAction";
|
||||
import ActionsList from "../components/ActionsList";
|
||||
|
||||
function VehicleMechanics() {
|
||||
const [activeOption, setActiveOption] = useState<"default" | "travel">(
|
||||
"default"
|
||||
);
|
||||
const [selectedPointData, setSelectedPointData] = useState<
|
||||
VehiclePointSchema | undefined
|
||||
>();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
|
||||
const { selectedProduct } = useSelectedProduct();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEventData) {
|
||||
const point = getPointByUuid(
|
||||
selectedProduct.productId,
|
||||
selectedEventData.data.modelUuid,
|
||||
selectedEventData.selectedPoint
|
||||
) as VehiclePointSchema | undefined;
|
||||
|
||||
if (point) {
|
||||
setSelectedPointData(point);
|
||||
setActiveOption(point.action.actionType as "travel");
|
||||
}
|
||||
}
|
||||
}, [selectedProduct, selectedEventData, getPointByUuid]);
|
||||
|
||||
const handleSpeedChange = (value: string) => {
|
||||
if (!selectedEventData) return;
|
||||
updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
|
||||
speed: parseFloat(value),
|
||||
});
|
||||
};
|
||||
|
||||
const handleActionTypeChange = (option: string) => {
|
||||
if (!selectedEventData || !selectedPointData) return;
|
||||
const validOption = option as "travel";
|
||||
setActiveOption(validOption);
|
||||
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
actionType: validOption,
|
||||
});
|
||||
};
|
||||
|
||||
const handleRenameAction = (newName: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
|
||||
};
|
||||
|
||||
const handleLoadCapacityChange = (value: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
loadCapacity: parseFloat(value),
|
||||
});
|
||||
};
|
||||
|
||||
const handleUnloadDurationChange = (value: string) => {
|
||||
if (!selectedPointData) return;
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
unLoadDuration: parseFloat(value),
|
||||
});
|
||||
};
|
||||
|
||||
const handlePickPointChange = (value: string) => {
|
||||
if (!selectedPointData) return;
|
||||
const [x, y, z] = value.split(",").map(Number);
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
pickUpPoint: { x, y, z },
|
||||
});
|
||||
};
|
||||
|
||||
const handleUnloadPointChange = (value: string) => {
|
||||
if (!selectedPointData) return;
|
||||
const [x, y, z] = value.split(",").map(Number);
|
||||
updateAction(selectedPointData.action.actionUuid, {
|
||||
unLoadPoint: { x, y, z },
|
||||
});
|
||||
};
|
||||
|
||||
// Get current values from store
|
||||
const currentSpeed =
|
||||
selectedEventData?.data.type === "vehicle"
|
||||
? selectedEventData.data.speed.toString()
|
||||
: "0.5";
|
||||
|
||||
const currentActionName = selectedPointData
|
||||
? selectedPointData.action.actionName
|
||||
: "Action Name";
|
||||
|
||||
const currentLoadCapacity = selectedPointData
|
||||
? selectedPointData.action.loadCapacity.toString()
|
||||
: "1";
|
||||
|
||||
const currentUnloadDuration = selectedPointData
|
||||
? selectedPointData.action.unLoadDuration.toString()
|
||||
: "1";
|
||||
|
||||
const currentPickPoint = selectedPointData?.action.pickUpPoint
|
||||
? `${selectedPointData.action.pickUpPoint.x},${selectedPointData.action.pickUpPoint.y},${selectedPointData.action.pickUpPoint.z}`
|
||||
: "";
|
||||
|
||||
const currentUnloadPoint = selectedPointData?.action.unLoadPoint
|
||||
? `${selectedPointData.action.unLoadPoint.x},${selectedPointData.action.unLoadPoint.y},${selectedPointData.action.unLoadPoint.z}`
|
||||
: "";
|
||||
|
||||
const availableActions = {
|
||||
defaultOption: "travel",
|
||||
options: ["travel"],
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{selectedEventData && (
|
||||
<>
|
||||
<div className="global-props">
|
||||
<div className="property-list-container">
|
||||
<div className="property-item">
|
||||
<InputWithDropDown
|
||||
label="Speed"
|
||||
value={currentSpeed}
|
||||
min={0}
|
||||
step={0.1}
|
||||
defaultValue={"0.5"}
|
||||
max={10}
|
||||
activeOption="m/s"
|
||||
onClick={() => {}}
|
||||
onChange={handleSpeedChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ActionsList
|
||||
setSelectedPointData={setSelectedPointData}
|
||||
selectedPointData={selectedPointData}
|
||||
/>
|
||||
<div className="selected-actions-details">
|
||||
<div className="selected-actions-header">
|
||||
<RenameInput
|
||||
value={currentActionName}
|
||||
onRename={handleRenameAction}
|
||||
/>
|
||||
</div>
|
||||
<div className="selected-actions-list">
|
||||
<LabledDropdown
|
||||
defaultOption="travel"
|
||||
options={availableActions.options}
|
||||
onSelect={handleActionTypeChange}
|
||||
/>
|
||||
|
||||
{activeOption === "travel" && (
|
||||
<TravelAction
|
||||
loadCapacity={{
|
||||
value: currentLoadCapacity,
|
||||
min: 1,
|
||||
max: 100,
|
||||
defaultValue: "1",
|
||||
onChange: handleLoadCapacityChange,
|
||||
}}
|
||||
unloadDuration={{
|
||||
value: currentUnloadDuration,
|
||||
min: 1,
|
||||
max: 60,
|
||||
defaultValue: "1",
|
||||
onChange: handleUnloadDurationChange,
|
||||
}}
|
||||
// pickPoint={{
|
||||
// value: currentPickPoint,
|
||||
// onChange: handlePickPointChange,
|
||||
// }}
|
||||
// unloadPoint={{
|
||||
// value: currentUnloadPoint,
|
||||
// onChange: handleUnloadPointChange,
|
||||
// }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="tirgger">
|
||||
<Trigger />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default VehicleMechanics;
|
||||
@@ -1,11 +1,19 @@
|
||||
import React, { useState } from "react";
|
||||
import { AddIcon, RemoveIcon } from "../../../../../icons/ExportCommonIcons";
|
||||
import React, { useRef, useState } from "react";
|
||||
import {
|
||||
AddIcon,
|
||||
RemoveIcon,
|
||||
ResizeHeightIcon,
|
||||
} from "../../../../../icons/ExportCommonIcons";
|
||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||
import { handleResize } from "../../../../../../functions/handleResizePannel";
|
||||
|
||||
const Trigger: React.FC = () => {
|
||||
// State to hold the list of triggers
|
||||
const [triggers, setTriggers] = useState<string[]>([]);
|
||||
const [triggers, setTriggers] = useState<string[]>(["Trigger 1"]);
|
||||
const [selectedTrigger, setSelectedTrigger] = useState<string>("Trigger 1");
|
||||
const [activeOption, setActiveOption] = useState("onComplete");
|
||||
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// States for dropdowns
|
||||
const [triggeredModel, setTriggeredModel] = useState<string[]>([]);
|
||||
@@ -35,70 +43,94 @@ const Trigger: React.FC = () => {
|
||||
<div className="trigger-wrapper">
|
||||
<div className="header">
|
||||
<div className="title">Trigger</div>
|
||||
<div
|
||||
<button
|
||||
className="add-button"
|
||||
onClick={addTrigger}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<AddIcon /> Add
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div className="trigger-list">
|
||||
{/* Map over triggers and render them */}
|
||||
{triggers.map((trigger, index) => (
|
||||
<div key={index} className="trigger-item">
|
||||
<div className="trigger-name">
|
||||
{trigger}
|
||||
<div
|
||||
className="lists-main-container"
|
||||
ref={triggersContainerRef}
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
{triggers.map((trigger: any, index: number) => (
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => removeTrigger(index)}
|
||||
style={{ cursor: "pointer" }}
|
||||
key={index}
|
||||
className={`list-item ${
|
||||
selectedTrigger === trigger ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSelectedTrigger(trigger)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
<button className="value" onClick={() => {}}>
|
||||
<RenameInput value={trigger} onRename={() => {}} />
|
||||
</button>
|
||||
{triggers.length > 1 && (
|
||||
<button
|
||||
className="remove-button"
|
||||
onClick={() => removeTrigger(index)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
className="resize-icon"
|
||||
id="action-resize"
|
||||
onMouseDown={(e: any) => handleResize(e, triggersContainerRef)}
|
||||
>
|
||||
<ResizeHeightIcon />
|
||||
</button>
|
||||
</div>
|
||||
<div className="trigger-item">
|
||||
<div className="trigger-name">{selectedTrigger}</div>
|
||||
<LabledDropdown
|
||||
defaultOption={activeOption}
|
||||
options={["onComplete", "onStart", "onStop", "delay"]}
|
||||
onSelect={(option) => setActiveOption(option)}
|
||||
/>
|
||||
<div className="trigger-options">
|
||||
<div>
|
||||
<LabledDropdown
|
||||
defaultOption={triggeredModel[0] || "Select Model"}
|
||||
options={["Model 1", "Model 2", "Model 3"]}
|
||||
onSelect={(option) => {
|
||||
const newModel = [...triggeredModel];
|
||||
newModel[0] = option;
|
||||
setTriggeredModel(newModel);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<LabledDropdown
|
||||
defaultOption={activeOption}
|
||||
options={["onComplete", "onStart", "onStop", "delay"]}
|
||||
onSelect={(option) => setActiveOption(option)}
|
||||
/>
|
||||
<div className="trigger-options">
|
||||
<div>
|
||||
<LabledDropdown
|
||||
defaultOption={triggeredModel[index] || "Select Model"}
|
||||
options={["Model 1", "Model 2", "Model 3"]}
|
||||
onSelect={(option) => {
|
||||
const newModel = [...triggeredModel];
|
||||
newModel[index] = option;
|
||||
setTriggeredModel(newModel);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<LabledDropdown
|
||||
defaultOption={triggeredPoint[index] || "Select Point"}
|
||||
options={["Point 1", "Point 2", "Point 3"]}
|
||||
onSelect={(option) => {
|
||||
const newPoint = [...triggeredPoint];
|
||||
newPoint[index] = option;
|
||||
setTriggeredPoint(newPoint);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<LabledDropdown
|
||||
defaultOption={triggeredAction[index] || "Select Action"}
|
||||
options={["Action 1", "Action 2", "Action 3"]}
|
||||
onSelect={(option) => {
|
||||
const newAction = [...triggeredAction];
|
||||
newAction[index] = option;
|
||||
setTriggeredAction(newAction);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<LabledDropdown
|
||||
defaultOption={triggeredPoint[0] || "Select Point"}
|
||||
options={["Point 1", "Point 2", "Point 3"]}
|
||||
onSelect={(option) => {
|
||||
const newPoint = [...triggeredPoint];
|
||||
newPoint[0] = option;
|
||||
setTriggeredPoint(newPoint);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<LabledDropdown
|
||||
defaultOption={triggeredAction[0] || "Select Action"}
|
||||
options={["Action 1", "Action 2", "Action 3"]}
|
||||
onSelect={(option) => {
|
||||
const newAction = [...triggeredAction];
|
||||
newAction[0] = option;
|
||||
setTriggeredAction(newAction);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import {
|
||||
AddIcon,
|
||||
ArrowIcon,
|
||||
@@ -7,65 +7,96 @@ import {
|
||||
} from "../../../icons/ExportCommonIcons";
|
||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||
import { handleResize } from "../../../../functions/handleResizePannel";
|
||||
import {
|
||||
useSelectedAsset,
|
||||
useSelectedProduct,
|
||||
} from "../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../store/simulation/useProductStore";
|
||||
import { generateUUID } from "three/src/math/MathUtils";
|
||||
import RenderOverlay from "../../../templates/Overlay";
|
||||
import EditWidgetOption from "../../../ui/menu/EditWidgetOption";
|
||||
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
|
||||
import { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct";
|
||||
|
||||
interface Path {
|
||||
pathName: string; // Represents the name of the path
|
||||
Children: string[]; // Represents the list of child points
|
||||
interface Event {
|
||||
pathName: string;
|
||||
}
|
||||
|
||||
interface DropListProps {
|
||||
val: Path; // Use the Path interface for the val prop
|
||||
interface ListProps {
|
||||
val: Event;
|
||||
}
|
||||
|
||||
const DropList: React.FC<DropListProps> = ({ val }) => {
|
||||
const [openDrop, setOpenDrop] = useState(false);
|
||||
const List: React.FC<ListProps> = ({ val }) => {
|
||||
return (
|
||||
<div className="process-container">
|
||||
<div
|
||||
className="value"
|
||||
onClick={() => {
|
||||
setOpenDrop(!openDrop);
|
||||
}}
|
||||
>
|
||||
{val.pathName}
|
||||
<div className={`arrow-container${openDrop ? " active" : ""}`}>
|
||||
<ArrowIcon />
|
||||
</div>
|
||||
</div>
|
||||
{val.Children && openDrop && (
|
||||
<div className="children-drop">
|
||||
{val.Children.map((child, index) => (
|
||||
<div key={index} className="value">
|
||||
{child}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div className="value">{val.pathName}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Simulations: React.FC = () => {
|
||||
const productsContainerRef = useRef<HTMLDivElement>(null);
|
||||
const [productsList, setProductsList] = useState<string[]>([]);
|
||||
const [selectedItem, setSelectedItem] = useState<string>();
|
||||
const {
|
||||
products,
|
||||
addProduct,
|
||||
removeProduct,
|
||||
renameProduct,
|
||||
addEvent,
|
||||
removeEvent,
|
||||
} = useProductStore();
|
||||
const { selectedProduct, setSelectedProduct } = useSelectedProduct();
|
||||
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||
|
||||
const handleAddAction = () => {
|
||||
setProductsList([...productsList, `Product ${productsList.length + 1}`]);
|
||||
const handleAddProduct = () => {
|
||||
addProduct(`Product ${products.length + 1}`, generateUUID());
|
||||
};
|
||||
|
||||
const handleRemoveAction = (index: number) => {
|
||||
setProductsList(productsList.filter((_, i) => i !== index));
|
||||
if (selectedItem === productsList[index]) {
|
||||
setSelectedItem("");
|
||||
const handleRemoveProduct = (productId: string) => {
|
||||
const currentIndex = products.findIndex((p) => p.productId === productId);
|
||||
const isSelected = selectedProduct.productId === productId;
|
||||
|
||||
const updatedProducts = products.filter((p) => p.productId !== productId);
|
||||
|
||||
if (isSelected) {
|
||||
if (updatedProducts.length > 0) {
|
||||
let newSelectedIndex = currentIndex;
|
||||
if (currentIndex >= updatedProducts.length) {
|
||||
newSelectedIndex = updatedProducts.length - 1;
|
||||
}
|
||||
setSelectedProduct(
|
||||
updatedProducts[newSelectedIndex].productId,
|
||||
updatedProducts[newSelectedIndex].productName
|
||||
);
|
||||
} else {
|
||||
setSelectedProduct("", "");
|
||||
}
|
||||
}
|
||||
|
||||
removeProduct(productId);
|
||||
};
|
||||
|
||||
const handleRenameProduct = (productId: string, newName: string) => {
|
||||
renameProduct(productId, newName);
|
||||
if (selectedProduct.productId === productId) {
|
||||
setSelectedProduct(productId, newName);
|
||||
}
|
||||
};
|
||||
|
||||
const Value = [
|
||||
{ pathName: "Path 1", Children: ["Point 1", "Point 2"] },
|
||||
{ pathName: "Path 2", Children: ["Point 1", "Point 2"] },
|
||||
{ pathName: "Path 3", Children: ["Point 1", "Point 2"] },
|
||||
];
|
||||
const handleRemoveEventFromProduct = () => {
|
||||
if (selectedAsset) {
|
||||
removeEvent(selectedProduct.productId, selectedAsset.modelUuid);
|
||||
clearSelectedAsset();
|
||||
}
|
||||
};
|
||||
|
||||
const selectedProductData = products.find(
|
||||
(product) => product.productId === selectedProduct.productId
|
||||
);
|
||||
|
||||
const events: Event[] =
|
||||
selectedProductData?.eventDatas.map((event) => ({
|
||||
pathName: event.modelName,
|
||||
})) || [];
|
||||
|
||||
return (
|
||||
<div className="simulations-container">
|
||||
@@ -74,7 +105,7 @@ const Simulations: React.FC = () => {
|
||||
<div className="actions">
|
||||
<div className="header">
|
||||
<div className="header-value">Products</div>
|
||||
<div className="add-button" onClick={handleAddAction}>
|
||||
<div className="add-button" onClick={handleAddProduct}>
|
||||
<AddIcon /> Add
|
||||
</div>
|
||||
</div>
|
||||
@@ -84,26 +115,42 @@ const Simulations: React.FC = () => {
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
{productsList.map((action, index) => (
|
||||
{products.map((product, index) => (
|
||||
<div
|
||||
key={index}
|
||||
key={product.productId}
|
||||
className={`list-item ${
|
||||
selectedItem === action ? "active" : ""
|
||||
selectedProduct.productId === product.productId
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className="value"
|
||||
onClick={() => setSelectedItem(action)}
|
||||
onClick={() =>
|
||||
setSelectedProduct(product.productId, product.productName)
|
||||
}
|
||||
>
|
||||
<input type="radio" name="products" id="products" />
|
||||
<RenameInput value={action} />
|
||||
</div>
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleRemoveAction(index)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
<input
|
||||
type="radio"
|
||||
name="products"
|
||||
checked={selectedProduct.productId === product.productId}
|
||||
readOnly
|
||||
/>
|
||||
<RenameInput
|
||||
value={product.productName}
|
||||
onRename={(newName) =>
|
||||
handleRenameProduct(product.productId, newName)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{products.length > 1 && (
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleRemoveProduct(product.productId)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -116,17 +163,19 @@ const Simulations: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="simulation-process">
|
||||
<div className="collapse-header-container">
|
||||
<div className="header">Operations</div>
|
||||
<div className="header">Events</div>
|
||||
<div className="arrow-container">
|
||||
<ArrowIcon />
|
||||
</div>
|
||||
</div>
|
||||
{Value.map((val, index) => (
|
||||
<DropList key={index} val={val} />
|
||||
{events.map((event, index) => (
|
||||
<List key={index} val={event} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="compare-simulations-container">
|
||||
<div className="compare-simulations-header">
|
||||
Need to Compare Layout?
|
||||
@@ -140,6 +189,26 @@ const Simulations: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{selectedAsset && (
|
||||
<RenderOverlay>
|
||||
<EditWidgetOption
|
||||
options={["Add to Product", "Remove from Product"]}
|
||||
onClick={(option) => {
|
||||
if (option === "Add to Product") {
|
||||
handleAddEventToProduct({
|
||||
selectedAsset,
|
||||
addEvent,
|
||||
selectedProduct,
|
||||
clearSelectedAsset,
|
||||
});
|
||||
} else {
|
||||
handleRemoveEventFromProduct();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</RenderOverlay>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import ChartComponent from "../../../sidebarLeft//visualization/widgets/ChartComponent";
|
||||
import ChartComponent from "../../../sidebarLeft/visualization/widgets/ChartComponent";
|
||||
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||
import { WalletIcon } from "../../../../icons/3dChartIcons";
|
||||
import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard";
|
||||
import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard";
|
||||
|
||||
interface Widget {
|
||||
id: string;
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from "../icons/ExportToolsIcons";
|
||||
import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons";
|
||||
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
|
||||
import { handleSaveTemplate } from "../../modules//visualization/functions/handleSaveTemplate";
|
||||
import { handleSaveTemplate } from "../../modules/visualization/functions/handleSaveTemplate";
|
||||
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
|
||||
import useTemplateStore from "../../store/useTemplateStore";
|
||||
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { ProductionCapacityIcon } from "../../icons/analysis";
|
||||
|
||||
const ProductionCapacity = () => {
|
||||
const ProductionCapacity = ({
|
||||
progressPercent = 10,
|
||||
avgProcessTime = "28.4 Secs/unit",
|
||||
machineUtilization = "78%",
|
||||
throughputValue = 128,
|
||||
timeRange = { startTime: "08:00 AM", endTime: "09:00 AM" },
|
||||
}) => {
|
||||
const totalBars = 6;
|
||||
const progressPercent = 50;
|
||||
|
||||
const barsToFill = Math.floor((progressPercent / 100) * totalBars);
|
||||
const partialFillPercent =
|
||||
((progressPercent / 100) * totalBars - barsToFill) * 100;
|
||||
@@ -14,8 +18,10 @@ const ProductionCapacity = () => {
|
||||
<div className="productionCapacity-wrapper analysis-card-wrapper">
|
||||
<div className="card-header">
|
||||
<div className="header">
|
||||
<div className="main-header">Throughput Summary</div>
|
||||
<div className="sub-header">08:00 - 09:00 AM</div>
|
||||
<div className="main-header">Production Capacity</div>
|
||||
<div className="sub-header">
|
||||
{timeRange.startTime} - {timeRange.endTime}
|
||||
</div>
|
||||
</div>
|
||||
<div className="icon-wrapper">
|
||||
<ProductionCapacityIcon />
|
||||
@@ -24,10 +30,10 @@ const ProductionCapacity = () => {
|
||||
|
||||
<div className="process-container">
|
||||
<div className="throughput-value">
|
||||
<span className="value">128</span> Units/hour
|
||||
<span className="value">{throughputValue}</span> Units/hour
|
||||
</div>
|
||||
|
||||
{/* Progress Bar */}
|
||||
{/* Dynamic Progress Bar */}
|
||||
<div className="progress-bar-wrapper">
|
||||
{[...Array(totalBars)].map((_, i) => (
|
||||
<div className="progress-bar" key={i}>
|
||||
@@ -47,11 +53,11 @@ const ProductionCapacity = () => {
|
||||
<div className="metrics-section">
|
||||
<div className="metric">
|
||||
<span className="label">Avg. Process Time</span>
|
||||
<span className="value">28.4 Secs/unit</span>
|
||||
<span className="value">{avgProcessTime}</span>
|
||||
</div>
|
||||
<div className="metric">
|
||||
<span className="label">Machine Utilization</span>
|
||||
<span className="value">78%</span>
|
||||
<span className="value">{machineUtilization}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,54 +1,68 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { ROISummaryIcon } from "../../icons/analysis";
|
||||
import SemiCircleProgress from "./SemiCircleProgress";
|
||||
|
||||
const ROISummary = () => {
|
||||
// Data for the cost breakdown as an array of objects
|
||||
const costBreakdownData = [
|
||||
{
|
||||
item: "Raw Material A",
|
||||
unitCost: "₹ 10/unit",
|
||||
laborCost: "₹ 0",
|
||||
totalCost: "₹ 1000",
|
||||
sellingPrice: "₹ 1500",
|
||||
},
|
||||
{
|
||||
item: "Labor",
|
||||
unitCost: "₹ 10/unit",
|
||||
laborCost: "₹ 500",
|
||||
totalCost: "₹ 500",
|
||||
sellingPrice: "N/A",
|
||||
},
|
||||
{
|
||||
item: "Product 1",
|
||||
unitCost: "₹ 10/unit",
|
||||
laborCost: "₹ 200",
|
||||
totalCost: "₹ 200",
|
||||
sellingPrice: "₹ 2000",
|
||||
},
|
||||
{
|
||||
item: "Machine",
|
||||
unitCost: "-",
|
||||
laborCost: "-",
|
||||
totalCost: "₹ 20,000",
|
||||
sellingPrice: "N/A",
|
||||
},
|
||||
{
|
||||
item: "Total",
|
||||
unitCost: "-",
|
||||
laborCost: "-",
|
||||
totalCost: "₹ 1,20,000",
|
||||
sellingPrice: "-",
|
||||
},
|
||||
{
|
||||
item: "Net Profit",
|
||||
unitCost: "-",
|
||||
laborCost: "-",
|
||||
totalCost: "₹ 1,60,000",
|
||||
sellingPrice: "-",
|
||||
},
|
||||
];
|
||||
const progressValue = 50;
|
||||
const ROISummary = ({
|
||||
roiSummaryData = {
|
||||
productName: "Product name",
|
||||
roiPercentage: 133,
|
||||
paybackPeriod: 50.3,
|
||||
totalCost: "₹ 1,20,000",
|
||||
revenueGenerated: "₹ 2,80,000",
|
||||
netProfit: "₹ 1,60,000",
|
||||
costBreakdown: [
|
||||
{
|
||||
item: "Raw Material A",
|
||||
unitCost: "₹ 10/unit",
|
||||
laborCost: "₹ 0",
|
||||
totalCost: "₹ 1000",
|
||||
sellingPrice: "₹ 1500",
|
||||
},
|
||||
{
|
||||
item: "Labor",
|
||||
unitCost: "₹ 10/unit",
|
||||
laborCost: "₹ 500",
|
||||
totalCost: "₹ 500",
|
||||
sellingPrice: "N/A",
|
||||
},
|
||||
{
|
||||
item: "Product 1",
|
||||
unitCost: "₹ 10/unit",
|
||||
laborCost: "₹ 200",
|
||||
totalCost: "₹ 200",
|
||||
sellingPrice: "₹ 2000",
|
||||
},
|
||||
{
|
||||
item: "Machine",
|
||||
unitCost: "-",
|
||||
laborCost: "-",
|
||||
totalCost: "₹ 20,000",
|
||||
sellingPrice: "N/A",
|
||||
},
|
||||
{
|
||||
item: "Total",
|
||||
unitCost: "-",
|
||||
laborCost: "-",
|
||||
totalCost: "₹ 1,20,000",
|
||||
sellingPrice: "-",
|
||||
},
|
||||
{
|
||||
item: "Net Profit",
|
||||
unitCost: "-",
|
||||
laborCost: "-",
|
||||
totalCost: "₹ 1,60,000",
|
||||
sellingPrice: "-",
|
||||
},
|
||||
],
|
||||
},
|
||||
}) => {
|
||||
const [isTableOpen, setIsTableOpen] = useState(false); // State to handle the table open/close
|
||||
|
||||
// Function to toggle the breakdown table visibility
|
||||
const toggleTable = () => {
|
||||
setIsTableOpen(!isTableOpen);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="roiSummary-container analysis-card">
|
||||
<div className="roiSummary-wrapper analysis-card-wrapper">
|
||||
@@ -63,71 +77,94 @@ const ROISummary = () => {
|
||||
</div>
|
||||
<div className="product-info">
|
||||
<div className="product-label">Product :</div>
|
||||
<div className="product-name">Product name</div>
|
||||
<div className="product-name">{roiSummaryData.productName}</div>
|
||||
</div>
|
||||
<div className="playBack">
|
||||
<div className="icon"></div>
|
||||
<div className="info">
|
||||
<span>+133%</span> ROI with payback in just <span>50.3</span> months
|
||||
<span>+{roiSummaryData.roiPercentage}%</span> ROI with payback in
|
||||
just <span>{roiSummaryData.paybackPeriod}</span> months
|
||||
</div>
|
||||
</div>
|
||||
<div className="roi-details">
|
||||
<SemiCircleProgress />
|
||||
|
||||
<div className="progress-wrapper">
|
||||
<SemiCircleProgress />
|
||||
<div className="content">
|
||||
you're on track to hit it by
|
||||
<div className="key">July 2029</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="metrics">
|
||||
<div className="metric-wrapper">
|
||||
<div className="metric-item">
|
||||
<span className="metric-label">Total Cost Incurred</span>
|
||||
<span className="metric-value">₹ 1,20,000</span>
|
||||
<span className="metric-value">{roiSummaryData.totalCost}</span>
|
||||
</div>
|
||||
<div className="metric-item">
|
||||
<span className="metric-label">Revenue Generated</span>
|
||||
<span className="metric-value">₹ 2,80,000</span>
|
||||
<span className="metric-value">
|
||||
{roiSummaryData.revenueGenerated}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="metric-item net-profit">
|
||||
<span className="metric-label">Net Profit</span>
|
||||
<span className="metric-value">₹ 1,60,000</span>
|
||||
<span className="metric-value">{roiSummaryData.netProfit}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="cost-breakdown">
|
||||
<div className="breakdown-header">
|
||||
<span className="section-number">①</span>
|
||||
<span className="section-title">Cost Breakdown</span>
|
||||
<span className="expand-icon">⌵</span>
|
||||
<div className="breakdown-header" onClick={toggleTable}>
|
||||
<div className="section-wrapper">
|
||||
<span className="section-number">①</span>
|
||||
<span className="section-title">Cost Breakdown</span>
|
||||
</div>
|
||||
|
||||
<span className={`expand-icon ${isTableOpen ? "open" : ""}`}>
|
||||
{isTableOpen ? "⌵" : "⌵"}
|
||||
</span>
|
||||
</div>
|
||||
<table className="breakdown-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>Unit Cost</th>
|
||||
<th>Labor Cost</th>
|
||||
<th>Total Cost</th>
|
||||
<th>Selling Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{costBreakdownData.map((row, index) => (
|
||||
<tr
|
||||
key={index}
|
||||
className={
|
||||
row.item === "Total"
|
||||
? "total-row"
|
||||
: row.item === "Net Profit"
|
||||
? "net-profit-row"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<td>{row.item}</td>
|
||||
<td>{row.unitCost}</td>
|
||||
<td>{row.laborCost}</td>
|
||||
<td>{row.totalCost}</td>
|
||||
<td>{row.sellingPrice}</td>
|
||||
<div
|
||||
className={`breakdown-table-wrapper ${
|
||||
isTableOpen ? "open" : "closed"
|
||||
}`}
|
||||
style={{
|
||||
transition: "max-height 0.3s ease-in-out",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<table className="breakdown-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>Unit Cost</th>
|
||||
<th>Labor Cost</th>
|
||||
<th>Total Cost</th>
|
||||
<th>Selling Price</th>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
{roiSummaryData.costBreakdown.map((row, index) => (
|
||||
<tr
|
||||
key={index}
|
||||
className={
|
||||
row.item === "Total"
|
||||
? "total-row"
|
||||
: row.item === "Net Profit"
|
||||
? "net-profit-row"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<td>{row.item}</td>
|
||||
<td>{row.unitCost}</td>
|
||||
<td>{row.laborCost}</td>
|
||||
<td>{row.totalCost}</td>
|
||||
<td>{row.sellingPrice}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div className="tips-section">
|
||||
<div className="tip-header">
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
import React from "react";
|
||||
|
||||
const SemiCircleProgress = () => {
|
||||
const progress = 10;
|
||||
const clampedProgress = Math.min(Math.max(progress, 0), 100); // clamp 0-100
|
||||
const progress = 50;
|
||||
const clampedProgress = Math.min(Math.max(progress, 0), 100);
|
||||
const gradientProgress = clampedProgress * 0.5;
|
||||
|
||||
return (
|
||||
<div className="semi-circle-wrapper">
|
||||
<div
|
||||
className="semi-circle"
|
||||
style={{
|
||||
background: `conic-gradient(
|
||||
from 180deg,
|
||||
skyblue 0% ${clampedProgress / 2}%,
|
||||
lightgray ${clampedProgress / 2}% 50%
|
||||
)`,
|
||||
background: `conic-gradient(from 270deg, skyblue 0% ${gradientProgress}%, lightgray ${gradientProgress}% 100%)`,
|
||||
}}
|
||||
>
|
||||
<div className="progress-cover"></div>
|
||||
</div>
|
||||
<div className="label">{clampedProgress}%</div>
|
||||
<div className="label-wrapper">
|
||||
<div className="label">{clampedProgress}%</div>
|
||||
<div className="label-content">Years</div>
|
||||
</div>
|
||||
<div className="content">you're on track to hit it by July 2029</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -11,21 +11,57 @@ import { PowerIcon, ThroughputSummaryIcon } from "../../icons/analysis";
|
||||
|
||||
ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement);
|
||||
|
||||
// Helper function to generate random colors
|
||||
const getRandomColor = () => {
|
||||
const letters = "0123456789ABCDEF";
|
||||
let color = "#";
|
||||
for (let i = 0; i < 6; i++) {
|
||||
color += letters[Math.floor(Math.random() * 16)];
|
||||
}
|
||||
return color;
|
||||
};
|
||||
|
||||
const ThroughputSummary = () => {
|
||||
const data = {
|
||||
// Define all data internally within the component
|
||||
const timeRange = {
|
||||
startTime: "08:00 AM",
|
||||
endTime: "09:00 AM",
|
||||
};
|
||||
|
||||
const throughputData = {
|
||||
labels: ["08:00", "08:10", "08:20", "08:30", "08:40", "08:50", "09:00"],
|
||||
data: [100, 120, 110, 130, 125, 128, 132],
|
||||
totalThroughput: 1240,
|
||||
assetUsage: 85,
|
||||
};
|
||||
|
||||
const energyConsumption = {
|
||||
energyConsumed: 456,
|
||||
unit: "KWH",
|
||||
};
|
||||
|
||||
// Dynamic shift data
|
||||
const shiftUtilization = [
|
||||
{ shift: 1, percentage: 30 },
|
||||
{ shift: 2, percentage: 40 },
|
||||
{ shift: 3, percentage: 30 },
|
||||
];
|
||||
|
||||
// Chart data configuration
|
||||
const chartData = {
|
||||
labels: throughputData.labels,
|
||||
datasets: [
|
||||
{
|
||||
label: "Units/hour",
|
||||
data: [100, 120, 110, 130, 125, 128, 132],
|
||||
data: throughputData.data,
|
||||
borderColor: "#B392F0",
|
||||
tension: 0.4,
|
||||
pointRadius: 0, // hide points
|
||||
pointRadius: 0, // Hide points
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const options = {
|
||||
const chartOptions = {
|
||||
responsive: true,
|
||||
scales: {
|
||||
x: {
|
||||
@@ -57,19 +93,15 @@ const ThroughputSummary = () => {
|
||||
},
|
||||
};
|
||||
|
||||
const shiftUtilization = {
|
||||
"shift 1": 25,
|
||||
"shift 2": 45,
|
||||
"shift 3": 15,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="throughoutSummary analysis-card">
|
||||
<div className="throughoutSummary-wrapper analysis-card-wrapper">
|
||||
<div className="card-header">
|
||||
<div className="header">
|
||||
<div className="main-header">Throughput Summary</div>
|
||||
<div className="sub-header">08:00 - 09:00 AM</div>
|
||||
<div className="sub-header">
|
||||
{timeRange.startTime} - {timeRange.endTime}
|
||||
</div>
|
||||
</div>
|
||||
<div className="icon-wrapper">
|
||||
<ThroughputSummaryIcon />
|
||||
@@ -78,14 +110,15 @@ const ThroughputSummary = () => {
|
||||
|
||||
<div className="process-container">
|
||||
<div className="throughput-value">
|
||||
<span className="value">1240</span> Units/hour
|
||||
<span className="value">{throughputData.totalThroughput}</span>{" "}
|
||||
Units/hour
|
||||
</div>
|
||||
<div className="lineChart">
|
||||
<div className="assetUsage">
|
||||
<div className="key">Asset usage</div>
|
||||
<div className="value">85%</div>
|
||||
<div className="value">{throughputData.assetUsage}%</div>
|
||||
</div>
|
||||
<Line data={data} options={options} />
|
||||
<Line data={chartData} options={chartOptions} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -97,43 +130,41 @@ const ThroughputSummary = () => {
|
||||
<PowerIcon />
|
||||
</div>
|
||||
<div className="value-wrapper">
|
||||
<div className="value">456</div>
|
||||
<div className="unit">KWH</div>
|
||||
<div className="value">{energyConsumption.energyConsumed}</div>
|
||||
<div className="unit">{energyConsumption.unit}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="shiftUtilization footer-card">
|
||||
<div className="header">Shift Utilization</div>
|
||||
<div className="value-container">
|
||||
<div className="value">85%</div>
|
||||
<div className="value">{throughputData.assetUsage}%</div>
|
||||
|
||||
<div className="progress-wrapper">
|
||||
<div
|
||||
className="progress shift-1"
|
||||
style={{ width: "30%" }}
|
||||
></div>
|
||||
<div
|
||||
className="progress shift-2"
|
||||
style={{ width: "40%" }}
|
||||
></div>
|
||||
<div
|
||||
className="progress shift-3"
|
||||
style={{ width: "30%" }}
|
||||
></div>
|
||||
{/* Dynamically create progress bars based on shiftUtilization array */}
|
||||
{shiftUtilization.map((shift) => (
|
||||
<div
|
||||
key={shift.shift}
|
||||
className={`progress shift-${shift.shift}`}
|
||||
style={{
|
||||
width: `${shift.percentage}%`,
|
||||
backgroundColor: getRandomColor(),
|
||||
}}
|
||||
></div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="progress-indicator">
|
||||
<div className="shift-wrapper">
|
||||
<span className="indicator shift-1"></span>
|
||||
<label>Shift 1</label>
|
||||
</div>
|
||||
<div className="shift-wrapper">
|
||||
<span className="indicator shift-2"></span>
|
||||
<label>Shift 2</label>
|
||||
</div>
|
||||
<div className="shift-wrapper">
|
||||
<span className="indicator shift-3"></span>
|
||||
<label>Shift 3</label>
|
||||
</div>
|
||||
{/* Dynamically create shift indicators with random colors */}
|
||||
{shiftUtilization.map((shift) => (
|
||||
<div className="shift-wrapper" key={shift.shift}>
|
||||
<span
|
||||
className={`indicator shift-${shift.shift}`}
|
||||
style={{ backgroundColor: getRandomColor() }} // Random color for indicator
|
||||
></span>
|
||||
<label>Shift {shift.shift}</label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,47 +1,72 @@
|
||||
import React, { useState } from "react";
|
||||
import LabledDropdown from "./LabledDropdown";
|
||||
import { ArrowIcon } from "../../icons/ExportCommonIcons";
|
||||
import LabledDropdown from "./LabledDropdown";
|
||||
|
||||
const PreviewSelectionWithUpload: React.FC = () => {
|
||||
const [showPreview, setSetshowPreview] = useState(false);
|
||||
interface PreviewSelectionWithUploadProps {
|
||||
preview?: boolean;
|
||||
upload?: boolean;
|
||||
label?: string;
|
||||
onSelect: (option: string) => void;
|
||||
defaultOption: string;
|
||||
options: string[];
|
||||
}
|
||||
|
||||
const PreviewSelectionWithUpload: React.FC<PreviewSelectionWithUploadProps> = ({
|
||||
preview = false,
|
||||
upload = false,
|
||||
onSelect,
|
||||
label,
|
||||
defaultOption,
|
||||
options,
|
||||
}) => {
|
||||
const [showPreview, setShowPreview] = useState(false);
|
||||
return (
|
||||
<div className="preview-selection-with-upload-wrapper">
|
||||
<div
|
||||
className="input-header-container"
|
||||
onClick={() => setSetshowPreview(!showPreview)}
|
||||
>
|
||||
<div className="input-header">Preview</div>
|
||||
<div
|
||||
className="arrow-container"
|
||||
style={{ rotate: showPreview ? "0deg" : "90deg" }}
|
||||
>
|
||||
<ArrowIcon />
|
||||
</div>
|
||||
</div>
|
||||
{showPreview && (
|
||||
<div className="canvas-wrapper">
|
||||
<div className="canvas-container"></div>
|
||||
{preview && (
|
||||
<>
|
||||
<button
|
||||
className="input-header-container"
|
||||
onClick={() => setShowPreview(!showPreview)}
|
||||
>
|
||||
<div className="input-header">Preview</div>
|
||||
<div
|
||||
className="arrow-container"
|
||||
style={{ rotate: showPreview ? "0deg" : "90deg" }}
|
||||
>
|
||||
<ArrowIcon />
|
||||
</div>
|
||||
</button>
|
||||
{showPreview && (
|
||||
<div className="canvas-wrapper">
|
||||
<div className="canvas-container"></div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{upload && (
|
||||
<div className="asset-selection-container">
|
||||
<div className="upload-custom-asset-button">
|
||||
<div className="title">Upload Product</div>
|
||||
<input
|
||||
type="file"
|
||||
accept=".glb, .gltf"
|
||||
id="simulation-product-upload"
|
||||
/>
|
||||
<label
|
||||
className="upload-button"
|
||||
htmlFor="simulation-product-upload"
|
||||
>
|
||||
Upload here
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="asset-selection-container">
|
||||
<div className="upload-custom-asset-button">
|
||||
<div className="title">Upload Product</div>
|
||||
<input
|
||||
type="file"
|
||||
accept=".glb, .gltf"
|
||||
id="simulation-product-upload"
|
||||
/>
|
||||
<label className="upload-button" htmlFor="simulation-product-upload">
|
||||
Upload here
|
||||
</label>
|
||||
</div>
|
||||
<LabledDropdown
|
||||
label="Presets"
|
||||
defaultOption={"Default material"}
|
||||
options={["Default material", "Product 1", "Product 2"]}
|
||||
onSelect={(option) => console.log(option)}
|
||||
/>
|
||||
</div>
|
||||
<LabledDropdown
|
||||
label={label}
|
||||
defaultOption={defaultOption}
|
||||
options={options}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
ArrowIcon,
|
||||
EyeIcon,
|
||||
LockIcon,
|
||||
RmoveIcon,
|
||||
RemoveIcon,
|
||||
} from "../../icons/ExportCommonIcons";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import { useFloorItems, useZoneAssetId, useZones } from "../../../store/store";
|
||||
@@ -142,9 +142,6 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
console.log('newName: ', newName);
|
||||
|
||||
}
|
||||
const checkZoneNameDuplicate = (name: string) => {
|
||||
return zones.some(
|
||||
@@ -184,7 +181,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
</div>
|
||||
{remove && (
|
||||
<div className="remove option">
|
||||
<RmoveIcon />
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
)}
|
||||
{item.assets && item.assets.length > 0 && (
|
||||
@@ -221,7 +218,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
</div>
|
||||
{remove && (
|
||||
<div className="remove option">
|
||||
<RmoveIcon />
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
import React, { useEffect } from "react";
|
||||
import {
|
||||
useEditWidgetOptionsStore,
|
||||
useLeftData,
|
||||
useRightClickSelected,
|
||||
useRightSelected,
|
||||
useTopData,
|
||||
} from "../../../store/visualization/useZone3DWidgetStore";
|
||||
|
||||
interface EditWidgetOptionProps {
|
||||
options: string[];
|
||||
onClick: (option: string) => void;
|
||||
}
|
||||
|
||||
const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({
|
||||
options,
|
||||
onClick
|
||||
}) => {
|
||||
const { top } = useTopData();
|
||||
const { left } = useLeftData();
|
||||
const { setRightSelect } = useRightSelected();
|
||||
const { setEditWidgetOptions } = useEditWidgetOptionsStore();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -38,10 +35,7 @@ const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({
|
||||
<div
|
||||
className="option"
|
||||
key={index}
|
||||
onClick={(e) => {
|
||||
setRightSelect(option);
|
||||
setEditWidgetOptions(false);
|
||||
}}
|
||||
onClick={() => onClick(option)}
|
||||
>
|
||||
{option}
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,15 @@ import {
|
||||
usePlayButtonStore,
|
||||
useResetButtonStore,
|
||||
} from "../../../store/usePlayButtonStore";
|
||||
import {
|
||||
DailyProductionIcon,
|
||||
EndIcon,
|
||||
ExpandIcon,
|
||||
HourlySimulationIcon,
|
||||
MonthlyROI,
|
||||
SpeedIcon,
|
||||
StartIcon,
|
||||
} from "../../icons/ExportCommonIcons";
|
||||
|
||||
const SimulationPlayer: React.FC = () => {
|
||||
const { speed, setSpeed } = useAnimationPlaySpeed();
|
||||
@@ -30,7 +39,7 @@ const SimulationPlayer: React.FC = () => {
|
||||
const handleExit = () => {
|
||||
setPlaySimulation(false);
|
||||
setIsPlaying(false);
|
||||
setActiveTool("cursor")
|
||||
setActiveTool("cursor");
|
||||
};
|
||||
|
||||
// Slider functions starts
|
||||
@@ -72,70 +81,277 @@ const SimulationPlayer: React.FC = () => {
|
||||
}, []);
|
||||
// Slider function ends
|
||||
|
||||
// UI-Part
|
||||
const hourlySimulation = 25;
|
||||
const dailyProduction = 75;
|
||||
const monthlyROI = 50;
|
||||
|
||||
const process = [
|
||||
{ name: "process 1", completed: 0 }, // 0% completed
|
||||
{ name: "process 2", completed: 20 }, // 20% completed
|
||||
{ name: "process 3", completed: 40 }, // 40% completed
|
||||
{ name: "process 4", completed: 60 }, // 60% completed
|
||||
{ name: "process 5", completed: 80 }, // 80% completed
|
||||
{ name: "process 6", completed: 100 }, // 100% completed
|
||||
{ name: "process 7", completed: 0 }, // 0% completed
|
||||
{ name: "process 8", completed: 50 }, // 50% completed
|
||||
{ name: "process 9", completed: 90 }, // 90% completed
|
||||
{ name: "process 10", completed: 30 }, // 30% completed
|
||||
];
|
||||
const [expand, setExpand] = useState(false);
|
||||
// Move getRandomColor out of render
|
||||
const getRandomColor = () => {
|
||||
const letters = "0123456789ABCDEF";
|
||||
let color = "#";
|
||||
for (let i = 0; i < 6; i++) {
|
||||
color += letters[Math.floor(Math.random() * 16)];
|
||||
}
|
||||
return color;
|
||||
};
|
||||
|
||||
// Store colors for each process item
|
||||
const [processColors, setProcessColors] = useState<string[]>([]);
|
||||
|
||||
// Generate colors on mount or when process changes
|
||||
useEffect(() => {
|
||||
const generatedColors = process.map(() => getRandomColor());
|
||||
setProcessColors(generatedColors);
|
||||
}, []);
|
||||
|
||||
const intervals = [10, 20, 30, 40, 50, 60]; // in minutes
|
||||
const totalSegments = intervals.length;
|
||||
const progress = 80; // percent (example)
|
||||
|
||||
const processPlayerRef = useRef<HTMLDivElement>(null);
|
||||
const processWrapperRef = useRef<HTMLDivElement>(null);
|
||||
const [playerPosition, setPlayerPosition] = useState(0);
|
||||
|
||||
const handleProcessMouseDown = (e: React.MouseEvent) => {
|
||||
if (!processWrapperRef.current) return;
|
||||
|
||||
const rect = processWrapperRef.current.getBoundingClientRect();
|
||||
let x = e.clientX - rect.left;
|
||||
x = Math.max(0, Math.min(x, rect.width));
|
||||
setPlayerPosition(x);
|
||||
|
||||
const onMouseMove = (e: MouseEvent) => {
|
||||
if (!processWrapperRef.current) return;
|
||||
const newRect = processWrapperRef.current.getBoundingClientRect();
|
||||
let newX = e.clientX - newRect.left;
|
||||
newX = Math.max(0, Math.min(newX, newRect.width));
|
||||
setPlayerPosition(newX);
|
||||
|
||||
const progressPercent = (newX / newRect.width) * 100;
|
||||
console.log(`Dragging at progress: ${progressPercent.toFixed(1)}%`);
|
||||
};
|
||||
|
||||
const onMouseUp = () => {
|
||||
document.removeEventListener("mousemove", onMouseMove);
|
||||
document.removeEventListener("mouseup", onMouseUp);
|
||||
};
|
||||
|
||||
document.addEventListener("mousemove", onMouseMove);
|
||||
document.addEventListener("mouseup", onMouseUp);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="simulation-player-wrapper">
|
||||
<div className="simulation-player-container">
|
||||
<div className={`simulation-player-container ${expand ? "open" : ""}`}>
|
||||
<div className="controls-container">
|
||||
<div
|
||||
className="simulation-button-container"
|
||||
onClick={() => {
|
||||
handleReset();
|
||||
}}
|
||||
>
|
||||
<ResetIcon />
|
||||
Reset
|
||||
</div>
|
||||
<div
|
||||
className="simulation-button-container"
|
||||
onClick={() => {
|
||||
handlePlayStop();
|
||||
}}
|
||||
>
|
||||
<PlayStopIcon />
|
||||
{playSimulation ? "Play" : "Stop"}
|
||||
</div>
|
||||
<div
|
||||
className="simulation-button-container"
|
||||
onClick={() => {
|
||||
handleExit();
|
||||
}}
|
||||
>
|
||||
<ExitIcon />
|
||||
Exit
|
||||
</div>
|
||||
</div>
|
||||
<div className="speed-control-container">
|
||||
<div className="min-value">0.5x</div>
|
||||
<div className="slider-container" ref={sliderRef}>
|
||||
<div className="marker marker-10"></div>
|
||||
<div className="marker marker-20"></div>
|
||||
<div className="marker marker-30"></div>
|
||||
<div className="marker marker-40"></div>
|
||||
<div className="marker marker-50"></div>
|
||||
<div className="marker marker-60"></div>
|
||||
<div className="marker marker-70"></div>
|
||||
<div className="marker marker-80"></div>
|
||||
<div className="marker marker-90"></div>
|
||||
<div className="custom-slider">
|
||||
<div
|
||||
className={`slider-handle ${isDragging ? "dragging" : ""}`}
|
||||
style={{ left: `${calculateHandlePosition()}%` }}
|
||||
onMouseDown={handleMouseDown}
|
||||
>
|
||||
{speed.toFixed(1)}x
|
||||
<div className="production-details">
|
||||
{/* hourlySimulation */}
|
||||
<div className="hourly-wrapper production-wrapper">
|
||||
<div className="header">
|
||||
<div className="icon">
|
||||
<HourlySimulationIcon />
|
||||
</div>
|
||||
<div className="label">Hourly Simulation</div>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min="0.5"
|
||||
max="8"
|
||||
step="0.1"
|
||||
value={speed}
|
||||
onChange={handleSpeedChange}
|
||||
className="slider-input"
|
||||
/>
|
||||
<div className="progress-wrapper">
|
||||
<div
|
||||
className="progress"
|
||||
style={{ width: hourlySimulation }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
{/* dailyProduction */}
|
||||
<div className="dailyProduction-wrapper production-wrapper">
|
||||
<div className="header">
|
||||
<div className="icon">
|
||||
<DailyProductionIcon />
|
||||
</div>
|
||||
<div className="label">Daily Production</div>
|
||||
</div>
|
||||
<div className="progress-wrapper">
|
||||
<div
|
||||
className="progress"
|
||||
style={{ width: dailyProduction }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
{/* monthlyROI */}
|
||||
<div className="monthlyROI-wrapper production-wrapper">
|
||||
<div className="header">
|
||||
<div className="icon">
|
||||
<MonthlyROI />
|
||||
</div>
|
||||
<div className="label">Monthly ROI</div>
|
||||
</div>
|
||||
<div className="progress-wrapper">
|
||||
<div className="progress" style={{ width: monthlyROI }}></div>
|
||||
</div>{" "}
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-value">8x</div>
|
||||
<div className="controls-wrapper">
|
||||
<div
|
||||
className="simulation-button-container"
|
||||
onClick={() => {
|
||||
handleReset();
|
||||
}}
|
||||
>
|
||||
<ResetIcon />
|
||||
Reset
|
||||
</div>
|
||||
<div
|
||||
className="simulation-button-container"
|
||||
onClick={() => {
|
||||
handlePlayStop();
|
||||
}}
|
||||
>
|
||||
<PlayStopIcon />
|
||||
{playSimulation ? "Play" : "Stop"}
|
||||
</div>
|
||||
<div
|
||||
className="simulation-button-container"
|
||||
onClick={() => {
|
||||
handleExit();
|
||||
}}
|
||||
>
|
||||
<ExitIcon />
|
||||
Exit
|
||||
</div>
|
||||
<div
|
||||
className="simulation-button-container"
|
||||
onClick={() => setExpand(!expand)}
|
||||
>
|
||||
<ExpandIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="progresser-wrapper">
|
||||
<div className="time-displayer">
|
||||
<div className="start-time-wrappper">
|
||||
<div className="icon">
|
||||
<StartIcon />
|
||||
</div>
|
||||
<div className="time-wrapper">
|
||||
<div className="date">23 April ,25</div>
|
||||
<div className="time">04:41 PM</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="time-progresser">
|
||||
<div className="timeline">
|
||||
{intervals.map((label, index) => {
|
||||
const segmentProgress = (index / totalSegments) * 100;
|
||||
const isFilled = progress >= segmentProgress;
|
||||
return (
|
||||
<React.Fragment key={index}>
|
||||
<div className="label-dot-wrapper">
|
||||
<div className="label">{label} mins</div>
|
||||
<div
|
||||
className={`dot ${isFilled ? "filled" : ""}`}
|
||||
></div>
|
||||
</div>
|
||||
{index < intervals.length - 1 && (
|
||||
<div
|
||||
className={`line ${
|
||||
progress >= ((index + 1) / totalSegments) * 100
|
||||
? "filled"
|
||||
: ""
|
||||
}`}
|
||||
></div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="end-time-wrappper">
|
||||
<div className="time-wrapper">
|
||||
<div className="time">00:10:20</div>
|
||||
</div>
|
||||
<div className="icon">
|
||||
<EndIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="speed-control-container">
|
||||
<div className="min-value">
|
||||
<div className="icon">
|
||||
<SpeedIcon />
|
||||
</div>
|
||||
Speed
|
||||
</div>
|
||||
<div className="slider-container" ref={sliderRef}>
|
||||
<div className="speed-label mix-value">0X</div>
|
||||
<div className="marker marker-10"></div>
|
||||
<div className="marker marker-20"></div>
|
||||
<div className="marker marker-30"></div>
|
||||
<div className="marker marker-40"></div>
|
||||
<div className="marker marker-50"></div>
|
||||
<div className="marker marker-60"></div>
|
||||
<div className="marker marker-70"></div>
|
||||
<div className="marker marker-80"></div>
|
||||
<div className="marker marker-90"></div>
|
||||
<div className="custom-slider">
|
||||
<div
|
||||
className={`slider-handle ${isDragging ? "dragging" : ""}`}
|
||||
style={{ left: `${calculateHandlePosition()}%` }}
|
||||
onMouseDown={handleMouseDown}
|
||||
>
|
||||
{speed.toFixed(1)}x
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min="0.5"
|
||||
max="8"
|
||||
step="0.1"
|
||||
value={speed}
|
||||
onChange={handleSpeedChange}
|
||||
className="slider-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="speed-label max-value">8x</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="processDisplayer">
|
||||
<div
|
||||
className="process-player"
|
||||
style={{ left: playerPosition, position: "absolute" }}
|
||||
></div>
|
||||
<div
|
||||
className="process-wrapper"
|
||||
ref={processWrapperRef}
|
||||
onMouseDown={handleProcessMouseDown}
|
||||
>
|
||||
{process.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="process"
|
||||
style={{
|
||||
width: `${item.completed}%`,
|
||||
backgroundColor: processColors[index],
|
||||
}}
|
||||
></div>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className="process-player"
|
||||
ref={processPlayerRef}
|
||||
style={{ left: playerPosition, position: "absolute" }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user