diff --git a/app/src/components/icons/ContextMenuIcons.tsx b/app/src/components/icons/ContextMenuIcons.tsx index f48cf3b..e249bad 100644 --- a/app/src/components/icons/ContextMenuIcons.tsx +++ b/app/src/components/icons/ContextMenuIcons.tsx @@ -9,31 +9,31 @@ export function FlipXAxisIcon() { > @@ -52,37 +52,38 @@ export function FlipYAxisIcon() { > ); } + export function FlipZAxisIcon() { return ( ); diff --git a/app/src/components/icons/DashboardIcon.tsx b/app/src/components/icons/DashboardIcon.tsx index 314a3c8..f1f4d7d 100644 --- a/app/src/components/icons/DashboardIcon.tsx +++ b/app/src/components/icons/DashboardIcon.tsx @@ -9,13 +9,13 @@ export function NotificationIcon() { > @@ -34,7 +34,7 @@ export function HomeIcon() { > ); @@ -51,7 +51,7 @@ export function ProjectsIcon() { > ); @@ -70,103 +70,103 @@ export function TutorialsIcon() { cx="8.157" cy="8.35866" r="6.17928" - stroke="var(--icon-default-color)" + stroke="var(--text-color)" strokeWidth="0.562865" /> @@ -184,12 +184,12 @@ export function DocumentationIcon() { > @@ -208,7 +208,7 @@ export function HelpIcon() { @@ -236,17 +236,17 @@ export function LogoutIcon() { > diff --git a/app/src/components/icons/ExportCommonIcons.tsx b/app/src/components/icons/ExportCommonIcons.tsx index c78261e..eaa7701 100644 --- a/app/src/components/icons/ExportCommonIcons.tsx +++ b/app/src/components/icons/ExportCommonIcons.tsx @@ -24,7 +24,7 @@ export function ArrowIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - + ); } @@ -40,14 +40,14 @@ export function FocusIcon() { > @@ -65,7 +65,7 @@ export function LockIcon({ isLocked }: { isLocked: boolean }) { > @@ -80,7 +80,7 @@ export function LockIcon({ isLocked }: { isLocked: boolean }) { > @@ -100,7 +100,7 @@ export function EyeIcon({ isClosed }: { isClosed: boolean }) { @@ -119,13 +119,13 @@ export function EyeIcon({ isClosed }: { isClosed: boolean }) { > @@ -142,9 +142,9 @@ export function KebebIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - - - + + + ); } @@ -160,7 +160,7 @@ export function AddIcon() { > @@ -179,12 +179,12 @@ export function CloseIcon() { > @@ -203,11 +203,11 @@ export function SettingsIcon() { @@ -255,7 +255,7 @@ export function TrashIcon() { @@ -280,32 +280,32 @@ export function FilterIcon() { > @@ -324,7 +324,7 @@ export function EyeDroperIcon({ isActive }: { isActive: boolean }) { @@ -442,7 +442,7 @@ export function RemoveIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - + ); } @@ -462,7 +462,7 @@ export function InfoIcon() { /> { cy="1.35112" rx="1.4993" ry="1.27477" - fill="var(--icon-default-color)" + fill="var(--text-color)" /> ); @@ -562,31 +562,31 @@ export const DeleteIcon = () => { > @@ -607,7 +607,7 @@ export const HourlySimulationIcon = () => { 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" + fill="var(--text-color)" /> ); @@ -624,15 +624,15 @@ export const DailyProductionIcon = () => { > ); @@ -649,14 +649,14 @@ export const MonthlyROI = () => { > ); }; -export const ExpandIcon = () => { - return ( +export const ExpandIcon = ({ isActive }: { isActive: boolean }) => { + return isActive ? ( { > + + ) : ( + + + + ); @@ -691,21 +721,21 @@ export const StartIcon = () => { > { > { /> { 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" + fill="var(--text-color)" /> ); }; -// export const DublicateIcon = () => { -// return ( -// -// -// -// ); -// }; diff --git a/app/src/components/icons/ExportModuleIcons.tsx b/app/src/components/icons/ExportModuleIcons.tsx index 1dda323..c1a8432 100644 --- a/app/src/components/icons/ExportModuleIcons.tsx +++ b/app/src/components/icons/ExportModuleIcons.tsx @@ -10,7 +10,7 @@ export function BuilderIcon({ isActive }: { isActive: boolean }) { > @@ -29,41 +29,41 @@ export function SimulationIcon({ isActive }: { isActive: boolean }) { > @@ -81,19 +81,19 @@ export function VisualizationIcon({ isActive }: { isActive: boolean }) { > @@ -112,20 +112,20 @@ export function CartIcon({ isActive }: { isActive: boolean }) { > diff --git a/app/src/components/icons/HeaderIcons.tsx b/app/src/components/icons/HeaderIcons.tsx index ef02f02..c2a0f62 100644 --- a/app/src/components/icons/HeaderIcons.tsx +++ b/app/src/components/icons/HeaderIcons.tsx @@ -9,7 +9,7 @@ export function ProjectIcon() { > @@ -31,26 +31,26 @@ export function ToggleSidebarIcon() { width="17" height="13.7273" rx="3.59091" - stroke="var(--accent-color)" + stroke="var(--text-color)" /> ); diff --git a/app/src/components/icons/RealTimeVisulationIcons.tsx b/app/src/components/icons/RealTimeVisulationIcons.tsx index d418247..84d8cca 100644 --- a/app/src/components/icons/RealTimeVisulationIcons.tsx +++ b/app/src/components/icons/RealTimeVisulationIcons.tsx @@ -10,43 +10,43 @@ export function CleanPannel() { diff --git a/app/src/components/icons/SimulationIcons.tsx b/app/src/components/icons/SimulationIcons.tsx index b4aa881..ef23c8f 100644 --- a/app/src/components/icons/SimulationIcons.tsx +++ b/app/src/components/icons/SimulationIcons.tsx @@ -9,13 +9,17 @@ export function AnalysisIcon({ isActive }: { isActive: boolean }) { > @@ -34,11 +38,15 @@ export function MechanicsIcon({ isActive }: { isActive: boolean }) { > ); @@ -55,15 +63,21 @@ export function PropertiesIcon({ isActive }: { isActive: boolean }) { > ); @@ -82,13 +96,17 @@ export function SimulationIcon({ isActive }: { isActive: boolean }) { fillRule="evenodd" clipRule="evenodd" d="M6.44104 7.04762C6.57815 6.98413 6.73614 6.98413 6.87325 7.04762L12.0161 9.42958C12.198 9.51377 12.3143 9.69589 12.3143 9.89624V15.8512C12.3143 16.0347 12.2165 16.2043 12.0577 16.2962L6.9148 19.2736C6.75547 19.3659 6.55881 19.3659 6.39949 19.2736L1.25661 16.2962C1.09779 16.2043 1 16.0347 1 15.8512V9.89624C1 9.69589 1.11635 9.51377 1.29815 9.42958L6.44104 7.04762ZM2.02857 10.7297L6.14286 12.794V17.9366L2.02857 15.5546V10.7297ZM7.17143 17.9366L11.2857 15.5546V10.7297L7.17143 12.794V17.9366ZM6.65714 11.9013L10.6163 9.91477L6.65714 8.08106L2.69798 9.91477L6.65714 11.9013Z" - fill={"var(--icon-default-color-active)"} + fill={ + isActive ? "var(--icon-default-color-active)" : "var(--text-color)" + } /> ); diff --git a/app/src/components/icons/analysis.tsx b/app/src/components/icons/analysis.tsx index d081a86..591df60 100644 --- a/app/src/components/icons/analysis.tsx +++ b/app/src/components/icons/analysis.tsx @@ -31,7 +31,7 @@ export function ProductionCapacityIcon() { 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" + fill="var(--text-color)" /> ); diff --git a/app/src/components/icons/marketPlaceIcons.tsx b/app/src/components/icons/marketPlaceIcons.tsx index 6952ae1..5a9f293 100644 --- a/app/src/components/icons/marketPlaceIcons.tsx +++ b/app/src/components/icons/marketPlaceIcons.tsx @@ -52,13 +52,13 @@ export function EyeIconBig() { > @@ -80,7 +80,7 @@ export function CommentsIcon() { fillRule="evenodd" clipRule="evenodd" d="M8 13C7.416 13 6.852 12.932 6.31 12.8165L3.956 14.2315L3.9875 11.912C2.183 10.827 1 9.033 1 7C1 3.6865 4.134 1 8 1C11.866 1 15 3.6865 15 7C15 10.314 11.866 13 8 13ZM8 0C3.582 0 0 3.1345 0 7C0 9.2095 1.1725 11.177 3 12.4595V16L6.5045 13.8735C6.9895 13.9535 7.4885 14 8 14C12.418 14 16 10.866 16 7C16 3.1345 12.418 0 8 0ZM11.5 5.5H4.5C4.224 5.5 4 5.724 4 6C4 6.2765 4.224 6.5 4.5 6.5H11.5C11.776 6.5 12 6.2765 12 6C12 5.724 11.776 5.5 11.5 5.5ZM10.5 8.5H5.5C5.224 8.5 5 8.7235 5 9C5 9.2765 5.224 9.5 5.5 9.5H10.5C10.776 9.5 11 9.2765 11 9C11 8.7235 10.776 8.5 10.5 8.5Z" - fill="var(--icon-default-color)" + fill="var(--text-color)" /> @@ -131,7 +131,7 @@ export function StarsIconSmall() { ); } -export function FiileedStarsIconSmall() { +export function FilledStarsIconSmall() { return ( { } }; return ( -
+
- {searchValue ? ( -
-
-
-

Results for {searchValue}

+
+
+ {searchValue ? ( +
+
+
+

Results for {searchValue}

+
+
+ {categoryAssets && + categoryAssets?.map((asset: any, index: number) => ( +
+ {asset.filename} + +
+ {asset.filename + .split("_") + .map( + (word: any) => + word.charAt(0).toUpperCase() + word.slice(1) + ) + .join(" ")} +
+
+ ))} +
+
-
-
- {categoryAssets && - categoryAssets?.map((asset: any, index: number) => ( + ) : selectedCategory ? ( +
+

+ {selectedCategory}{" "}
{ + setSelectedCategory(null); + setCategoryAssets([]); + }} > - {asset.filename} + ← Back +
+

+
+ {categoryAssets && + categoryAssets?.map((asset: any, index: number) => ( +
+ {asset.filename} { + setSelectedItem({ + name: asset.filename, + id: asset.AssetID, + type: + asset.type === "undefined" + ? undefined + : asset.type, + }); + }} + /> -
- {asset.filename - .split("_") - .map( - (word: any) => - word.charAt(0).toUpperCase() + word.slice(1) - ) - .join(" ")} -
-
- ))} -
-
- ) : selectedCategory ? ( -
-
{ - setSelectedCategory(null); - setCategoryAssets([]); - }} - > - ← Back -
-

{selectedCategory}

-
- {categoryAssets && - categoryAssets?.map((asset: any, index: number) => ( -
- {asset.filename} { - setSelectedItem({ - name: asset.filename, - id: asset.AssetID, - type: - asset.type === "undefined" ? undefined : asset.type, - }); - }} - /> - -
- {asset.filename - .split("_") - .map( - (word: any) => - word.charAt(0).toUpperCase() + word.slice(1) - ) - .join(" ")} -
-
- ))} -
-
- ) : ( -
-

Categories

-
- {Array.from( - new Set(categoryList.map((asset) => asset.category)) - ).map((category, index) => { - const categoryInfo = categoryList.find( - (asset) => asset.category === category - ); - return ( -
fetchCategoryAssets(category)} - > - {category} -
{category}
-
- ); - })} -
-
- )} +
+ {asset.filename + .split("_") + .map( + (word: any) => + word.charAt(0).toUpperCase() + word.slice(1) + ) + .join(" ")} +
+
+ ))} +
+
+ ) : ( +
+

Categories

+
+ {Array.from( + new Set(categoryList.map((asset) => asset.category)) + ).map((category, index) => { + const categoryInfo = categoryList.find( + (asset) => asset.category === category + ); + return ( +
fetchCategoryAssets(category)} + > + {category} +
{category}
+
+ ); + })} +
+
+ )} + +
); }; diff --git a/app/src/components/layout/sidebarLeft/Outline.tsx b/app/src/components/layout/sidebarLeft/Outline.tsx index 417f069..152c357 100644 --- a/app/src/components/layout/sidebarLeft/Outline.tsx +++ b/app/src/components/layout/sidebarLeft/Outline.tsx @@ -11,7 +11,7 @@ const Outline: React.FC = () => { }; const dropdownItems = [ - { id: "1", name: "Ground Floor" }, + { id: "1", name: "Ground Floor", active: true }, // { id: "2", name: "Floor 1" }, ]; // Example dropdown items diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx index 09017de..8aae3b2 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx @@ -35,7 +35,7 @@ const ActionsList: React.FC = ({ const handleRenameAction = (newName: string) => { if (!selectedAction.actionId) return; - const event = renameAction(selectedAction.actionId, newName); + const event = renameAction(selectedProduct.productId, selectedAction.actionId, newName); if (event) { upsertProductOrEventApi({ diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx index f68b6b8..a6a1fa9 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -72,7 +72,7 @@ function ConveyorMechanics() { const validOption = option as | "default" | "spawn" | "swap" | "delay" | "despawn"; setActiveOption(validOption); - const event = updateAction(selectedPointData.action.actionUuid, { + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { actionType: validOption, }); @@ -88,7 +88,7 @@ function ConveyorMechanics() { const handleRenameAction = (newName: string) => { if (!selectedEventData || !selectedPointData) return; - const event = updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { actionName: newName }); if (event) { updateBackend( @@ -102,7 +102,7 @@ function ConveyorMechanics() { const handleSpawnCountChange = (value: string) => { if (!selectedEventData || !selectedPointData) return; - const event = updateAction(selectedPointData.action.actionUuid, { + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { spawnCount: value === "inherit" ? "inherit" : parseFloat(value), }); @@ -118,7 +118,7 @@ function ConveyorMechanics() { const handleSpawnIntervalChange = (value: string) => { if (!selectedEventData || !selectedPointData) return; - const event = updateAction(selectedPointData.action.actionUuid, { + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { spawnInterval: value === "inherit" ? "inherit" : parseFloat(value), }); @@ -134,7 +134,7 @@ function ConveyorMechanics() { const handleMaterialSelect = (material: string) => { if (!selectedEventData || !selectedPointData) return; - const event = updateAction(selectedPointData.action.actionUuid, { material }); + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { material }); if (event) { updateBackend( @@ -148,7 +148,7 @@ function ConveyorMechanics() { const handleDelayChange = (value: string) => { if (!selectedEventData || !selectedPointData) return; - const event = updateAction(selectedPointData.action.actionUuid, { + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { delay: value === "inherit" ? "inherit" : parseFloat(value), }); @@ -271,7 +271,7 @@ function ConveyorMechanics() {
- +
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx index 993c46b..3e11e54 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -6,6 +6,7 @@ import { useSelectedEventData, useSelectedProduct } from "../../../../../../stor import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import ProcessAction from "../actions/ProcessAction"; import ActionsList from "../components/ActionsList"; +import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi"; function MachineMechanics() { const [activeOption, setActiveOption] = useState<"default" | "process">("default"); @@ -14,6 +15,9 @@ function MachineMechanics() { const { getPointByUuid, updateAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + useEffect(() => { if (selectedEventData) { const point = getPointByUuid( @@ -28,31 +32,54 @@ function MachineMechanics() { } }, [selectedProduct, selectedEventData, getPointByUuid]); + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData + }) + } + const handleActionTypeChange = (option: string) => { if (!selectedEventData || !selectedPointData) return; const validOption = option as "process"; setActiveOption(validOption); - updateAction(selectedPointData.action.actionUuid, { + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { actionType: validOption, }); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } }; const handleRenameAction = (newName: string) => { if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { actionName: newName }); }; const handleProcessTimeChange = (value: string) => { if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { processTime: parseFloat(value), }); }; const handleMaterialSelect = (material: string) => { if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { swapMaterial: material, }); }; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx index e56741f..df5c358 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -59,7 +59,7 @@ function RoboticArmMechanics() { const handleRenameAction = (newName: string) => { if (!selectedAction.actionId) return; - const event = updateAction(selectedAction.actionId, { actionName: newName }); + const event = updateAction(selectedProduct.productId, selectedAction.actionId, { actionName: newName }); if (selectedPointData) { const updatedActions = selectedPointData.actions.map((action) => @@ -101,7 +101,7 @@ function RoboticArmMechanics() { if (!selectedAction.actionId || !selectedPointData) return; const [x, y, z] = value.split(",").map(Number); - const event = updateAction(selectedAction.actionId, { + const event = updateAction(selectedProduct.productId, selectedAction.actionId, { process: { startPoint: [x, y, z] as [number, number, number], endPoint: selectedPointData.actions.find((a) => a.actionUuid === selectedAction.actionId)?.process.endPoint || null, @@ -122,7 +122,7 @@ function RoboticArmMechanics() { if (!selectedAction.actionId || !selectedPointData) return; const [x, y, z] = value.split(",").map(Number); - const event = updateAction(selectedAction.actionId, { + const event = updateAction(selectedProduct.productId, selectedAction.actionId, { process: { startPoint: selectedPointData.actions.find((a) => a.actionUuid === selectedAction.actionId)?.process.startPoint || null, endPoint: [x, y, z] as [number, number, number], @@ -181,7 +181,7 @@ function RoboticArmMechanics() { const handleDeleteAction = (actionUuid: string) => { if (!selectedPointData) return; - const event = removeAction(actionUuid); + const event = removeAction(selectedProduct.productId, actionUuid); if (event) { updateBackend( diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index c85da9f..3273ce4 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -6,6 +6,7 @@ import { useSelectedEventData, useSelectedProduct } from "../../../../../../stor import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import StorageAction from "../actions/StorageAction"; import ActionsList from "../components/ActionsList"; +import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi"; function StorageMechanics() { const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default"); @@ -14,6 +15,9 @@ function StorageMechanics() { const { getPointByUuid, updateAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + useEffect(() => { if (selectedEventData) { const point = getPointByUuid( @@ -28,26 +32,67 @@ function StorageMechanics() { } }, [selectedProduct, selectedEventData, getPointByUuid]); + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData + }) + } + const handleActionTypeChange = (option: string) => { if (!selectedEventData || !selectedPointData) return; const validOption = option as "store" | "spawn"; setActiveOption(validOption); - updateAction(selectedPointData.action.actionUuid, { + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { actionType: validOption, }); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } }; const handleRenameAction = (newName: string) => { if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { actionName: newName }); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } }; const handleCapacityChange = (value: string) => { if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { storageCapacity: parseInt(value), }); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } }; // Get current values from store diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index 28eb61f..7839168 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -10,6 +10,7 @@ import { import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import TravelAction from "../actions/TravelAction"; import ActionsList from "../components/ActionsList"; +import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi"; function VehicleMechanics() { const [activeOption, setActiveOption] = useState<"default" | "travel">("default"); @@ -18,8 +19,11 @@ function VehicleMechanics() { const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore(); const { selectedProduct } = useSelectedProduct(); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + useEffect(() => { - if (selectedEventData) { + if (selectedEventData && selectedEventData.data.type === 'vehicle') { const point = getPointByUuid( selectedProduct.productId, selectedEventData.data.modelUuid, @@ -33,11 +37,34 @@ function VehicleMechanics() { } }, [selectedProduct, selectedEventData, getPointByUuid]); + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData + }) + } + const handleSpeedChange = (value: string) => { if (!selectedEventData) return; - updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { + const event = updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { speed: parseFloat(value), }); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } }; const handleActionTypeChange = (option: string) => { @@ -45,28 +72,64 @@ function VehicleMechanics() { const validOption = option as "travel"; setActiveOption(validOption); - updateAction(selectedPointData.action.actionUuid, { + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { actionType: validOption, }); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } }; const handleRenameAction = (newName: string) => { if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { actionName: newName }); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } }; const handleLoadCapacityChange = (value: string) => { if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { loadCapacity: parseFloat(value), }); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } }; const handleUnloadDurationChange = (value: string) => { if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { + const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, { unLoadDuration: parseFloat(value), }); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } }; const handlePickPointChange = (value: string) => { diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx index 3b2549a..86e4e7b 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx @@ -1,139 +1,132 @@ -import React, { useRef, useState } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { - AddIcon, - RemoveIcon, - ResizeHeightIcon, + AddIcon, + RemoveIcon, + ResizeHeightIcon, } from "../../../../../icons/ExportCommonIcons"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import RenameInput from "../../../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../../../functions/handleResizePannel"; +import { useProductStore } from "../../../../../../store/simulation/useProductStore"; +import { useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; -const Trigger: React.FC = () => { - // State to hold the list of triggers - const [triggers, setTriggers] = useState(["Trigger 1"]); - const [selectedTrigger, setSelectedTrigger] = useState("Trigger 1"); - const [activeOption, setActiveOption] = useState("onComplete"); - const triggersContainerRef = useRef(null); +type TriggerProps = { + selectedPointData?: PointsScheme | undefined; + type?: 'Conveyor' | 'Vehicle' | 'RoboticArm' | 'Machine' | 'StorageUnit'; +}; - // States for dropdowns - const [triggeredModel, setTriggeredModel] = useState([]); - const [triggeredPoint, setTriggeredPoint] = useState([]); - const [triggeredAction, setTriggeredAction] = useState([]); +const Trigger = ({ selectedPointData, type }: TriggerProps) => { + const [currentAction, setCurrentAction] = useState(); + const { selectedProduct } = useSelectedProduct(); + const { getActionByUuid } = useProductStore(); + const [triggers, setTriggers] = useState([]); + const [selectedTrigger, setSelectedTrigger] = useState(); + const [activeOption, setActiveOption] = useState("onComplete"); + const triggersContainerRef = useRef(null); - // Function to handle adding a new trigger - const addTrigger = (): void => { - const newTrigger = `Trigger ${triggers.length + 1}`; - setTriggers([...triggers, newTrigger]); // Add new trigger to the state + useEffect(() => { + if (!selectedPointData) return; + if (type === 'Conveyor' || type === 'Vehicle' || type === 'Machine' || type === 'StorageUnit') { + setCurrentAction((selectedPointData as ConveyorPointSchema).action.actionUuid); + } + }, [selectedPointData]); - // Initialize the states for the new trigger - setTriggeredModel([...triggeredModel, ""]); - setTriggeredPoint([...triggeredPoint, ""]); - setTriggeredAction([...triggeredAction, ""]); - }; + useEffect(() => { + if (!currentAction || !selectedProduct) return; + const action = getActionByUuid(selectedProduct.productId, currentAction); + setTriggers(action?.triggers || []); + setSelectedTrigger(action?.triggers[0] || undefined); + }, [currentAction, selectedProduct]); - // Function to handle removing a trigger - const removeTrigger = (index: number): void => { - setTriggers(triggers.filter((_, i) => i !== index)); // Remove trigger by index - setTriggeredModel(triggeredModel.filter((_, i) => i !== index)); - setTriggeredPoint(triggeredPoint.filter((_, i) => i !== index)); - setTriggeredAction(triggeredAction.filter((_, i) => i !== index)); - }; + const addTrigger = (): void => { + }; - return ( -
-
-
Trigger
- -
-
-
-
- {triggers.map((trigger: any, index: number) => ( -
setSelectedTrigger(trigger)} - > - - {triggers.length > 1 && ( - - )} -
- ))} -
- +
+
+
+
+ {triggers.map((trigger) => ( +
setSelectedTrigger(trigger)} + > + + {triggers.length > 1 && ( + + )} +
+ ))} +
+ +
+
+
{selectedTrigger?.triggerName}
+ setActiveOption(option)} + /> +
+ { }} + /> + { }} + /> + { }} + /> +
+
+
-
-
{selectedTrigger}
- setActiveOption(option)} - /> -
-
- { - const newModel = [...triggeredModel]; - newModel[0] = option; - setTriggeredModel(newModel); - }} - /> -
-
- { - const newPoint = [...triggeredPoint]; - newPoint[0] = option; - setTriggeredPoint(newPoint); - }} - /> -
-
- { - const newAction = [...triggeredAction]; - newAction[0] = option; - setTriggeredAction(newAction); - }} - /> -
-
-
-
- - ); + ); }; export default Trigger; diff --git a/app/src/components/ui/analysis/ProductionCapacity.tsx b/app/src/components/ui/analysis/ProductionCapacity.tsx index 192e009..31c3a02 100644 --- a/app/src/components/ui/analysis/ProductionCapacity.tsx +++ b/app/src/components/ui/analysis/ProductionCapacity.tsx @@ -2,7 +2,7 @@ import React, { useState } from "react"; import { ProductionCapacityIcon } from "../../icons/analysis"; const ProductionCapacity = ({ - progressPercent = 10, + progressPercent = 50, avgProcessTime = "28.4 Secs/unit", machineUtilization = "78%", throughputValue = 128, diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx index b92a82d..e9946ae 100644 --- a/app/src/components/ui/analysis/ThroughputSummary.tsx +++ b/app/src/components/ui/analysis/ThroughputSummary.tsx @@ -8,6 +8,7 @@ import { PointElement, } from "chart.js"; import { PowerIcon, ThroughputSummaryIcon } from "../../icons/analysis"; +import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor"; ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement); @@ -142,13 +143,13 @@ const ThroughputSummary = () => {
{/* Dynamically create progress bars based on shiftUtilization array */} - {shiftUtilization.map((shift) => ( + {shiftUtilization.map((shift, index) => (
))} @@ -156,11 +157,11 @@ const ThroughputSummary = () => {
{/* Dynamically create shift indicators with random colors */} - {shiftUtilization.map((shift) => ( + {shiftUtilization.map((shift, index) => (
diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index d0b62e8..0d93d72 100644 --- a/app/src/components/ui/list/DropDownList.tsx +++ b/app/src/components/ui/list/DropDownList.tsx @@ -3,7 +3,6 @@ import List from "./List"; import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons"; import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect"; import { useFloorItems, useZones } from "../../../store/store"; -import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore"; interface DropDownListProps { value?: string; // Value to display in the DropDownList @@ -17,6 +16,17 @@ interface DropDownListProps { remove?: boolean; } +interface Zone { + zoneId: string; + zoneName: string; + points: [number, number, number][]; // polygon vertices +} +interface ZoneData { + id: string; + name: string; + assets: { id: string; name: string; position?: []; rotation?: {} }[]; +} + const DropDownList: React.FC = ({ value = "Dropdown", items = [], @@ -33,38 +43,30 @@ const DropDownList: React.FC = ({ remove, }) => { const [isOpen, setIsOpen] = useState(defaultOpen); - const { zones, setZones } = useZones(); + const { zones } = useZones(); const handleToggle = () => { setIsOpen((prev) => !prev); // Toggle the state }; - interface Asset { - id: string; - name: string; - position: [number, number, number]; // x, y, z - } - interface Zone { - zoneId: string; - zoneName: string; - points: [number, number, number][]; // polygon vertices - } - interface ZoneData { - id: string; - name: string; - assets: { id: string; name: string; position?: []; rotation?: {} }[]; - } const [zoneDataList, setZoneDataList] = useState([]); const { floorItems } = useFloorItems(); - const isPointInsidePolygon = (point: [number, number], polygon: [number, number][]) => { + const isPointInsidePolygon = ( + point: [number, number], + polygon: [number, number][] + ) => { let inside = false; for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { - const xi = polygon[i][0], zi = polygon[i][1]; - const xj = polygon[j][0], zj = polygon[j][1]; + const xi = polygon[i][0], + zi = polygon[i][1]; + const xj = polygon[j][0], + zj = polygon[j][1]; - const intersect = ((zi > point[1]) !== (zj > point[1])) && - (point[0] < (xj - xi) * (point[1] - zi) / (zj - zi + 0.000001) + xi); + const intersect = + // eslint-disable-next-line no-mixed-operators + zi > point[1] !== zj > point[1] && + point[0] < ((xj - xi) * (point[1] - zi)) / (zj - zi + 0.000001) + xi; if (intersect) inside = !inside; } @@ -73,18 +75,21 @@ const DropDownList: React.FC = ({ useEffect(() => { const updatedZoneList: ZoneData[] = zones?.map((zone: Zone) => { - const polygon2D = zone.points.map((p: [number, number, number]) => [p[0], p[2]]) as [number, number][]; + const polygon2D = zone.points.map((p: [number, number, number]) => [ + p[0], + p[2], + ]); const assetsInZone = floorItems .filter((item: any) => { const [x, , z] = item.position; - return isPointInsidePolygon([x, z], polygon2D); + return isPointInsidePolygon([x, z], polygon2D as [number, number][]); }) .map((item: any) => ({ id: item.modelUuid, name: item.modelName, position: item.position, - rotation: item.rotation + rotation: item.rotation, })); return { @@ -99,9 +104,9 @@ const DropDownList: React.FC = ({ return (
-
+
+
{showFocusIcon && (
@@ -118,13 +123,13 @@ const DropDownList: React.FC = ({
)} -
-
+
{isOpen && ( diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index cdd2a53..eebcaa7 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -12,7 +12,6 @@ import { LockIcon, RemoveIcon, } from "../../icons/ExportCommonIcons"; -import { useThree } from "@react-three/fiber"; import { useFloorItems, useZoneAssetId, useZones } from "../../../store/store"; import { zoneCameraUpdate } from "../../../services/visulization/zone/zoneCameraUpdation"; import { setFloorItemApi } from "../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; @@ -32,20 +31,19 @@ interface ZoneItem { interface ListProps { items?: ZoneItem[]; - placeholder?: string; remove?: boolean; } const List: React.FC = ({ items = [], remove }) => { - const { activeModule, setActiveModule } = useModuleStore(); + const { activeModule } = useModuleStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { zoneAssetId, setZoneAssetId } = useZoneAssetId(); - const { zones, setZones } = useZones(); + const { zones } = useZones(); const { setSubModule } = useSubModuleStore(); const [expandedZones, setExpandedZones] = useState>( {} ); - const { floorItems, setFloorItems } = useFloorItems(); + const { setFloorItems } = useFloorItems(); useEffect(() => { useSelectedZoneStore.getState().setSelectedZone({ @@ -70,39 +68,36 @@ const List: React.FC = ({ items = [], remove }) => { async function handleSelectZone(id: string) { try { if (selectedZone?.zoneId === id) { - return; } setSubModule("zoneProperties"); const email = localStorage.getItem("email"); - const organization = email?.split("@")[1]?.split(".")[0] || ""; + const organization = email?.split("@")[1]?.split(".")[0] ?? ""; let response = await getZoneData(id, organization); setSelectedZone({ zoneName: response?.zoneName, - activeSides: response?.activeSides || [], - panelOrder: response?.panelOrder || [], - lockedPanels: response?.lockedPanels || [], - widgets: response?.widgets || [], + activeSides: response?.activeSides ?? [], + panelOrder: response?.panelOrder ?? [], + lockedPanels: response?.lockedPanels ?? [], + widgets: response?.widgets ?? [], zoneId: response?.zoneId, - zoneViewPortTarget: response?.viewPortCenter || [], - zoneViewPortPosition: response?.viewPortposition || [], + zoneViewPortTarget: response?.viewPortCenter ?? [], + zoneViewPortPosition: response?.viewPortposition ?? [], }); - - } catch (error) { - + console.log(error); } } function handleAssetClick(asset: Asset) { - setZoneAssetId(asset) + setZoneAssetId(asset); } async function handleZoneNameChange(newName: string) { - const email = localStorage.getItem("email") || ""; + const email = localStorage.getItem("email") ?? ""; const organization = email?.split("@")[1]?.split(".")[0]; const isDuplicate = zones.some( @@ -128,12 +123,16 @@ const List: React.FC = ({ items = [], remove }) => { } async function handleZoneAssetName(newName: string) { - const email = localStorage.getItem("email") || ""; + const email = localStorage.getItem("email") ?? ""; const organization = email?.split("@")[1]?.split(".")[0]; if (zoneAssetId?.id) { - let response = await setFloorItemApi(organization, zoneAssetId.id, newName) - console.log('response: ', response); + let response = await setFloorItemApi( + organization, + zoneAssetId.id, + newName + ); + console.log("response: ", response); setFloorItems((prevFloorItems: any[]) => prevFloorItems.map((floorItems) => floorItems.modelUuid === zoneAssetId.id @@ -160,7 +159,7 @@ const List: React.FC = ({ items = [], remove }) => {
  • -
    handleSelectZone(item.id)} > @@ -169,8 +168,7 @@ const List: React.FC = ({ items = [], remove }) => { onRename={handleZoneNameChange} checkDuplicate={checkZoneNameDuplicate} /> - -
    +
    @@ -185,12 +183,12 @@ const List: React.FC = ({ items = [], remove }) => {
    )} {item.assets && item.assets.length > 0 && ( -
    toggleZoneExpansion(item.id)} > -
    + )}
    @@ -206,20 +204,26 @@ const List: React.FC = ({ items = [], remove }) => { className="list-container asset-item" >
    -
    handleAssetClick(asset)} > - -
    +
    -
    +
    -
    + +
    + {remove && ( -
    +
    + )}
    diff --git a/app/src/components/ui/menu/menu.tsx b/app/src/components/ui/menu/menu.tsx index a416c2c..39508b6 100644 --- a/app/src/components/ui/menu/menu.tsx +++ b/app/src/components/ui/menu/menu.tsx @@ -28,7 +28,7 @@ const MenuBar: React.FC = ({ setOpenMenu }) => { window.location.reload(); } - const savedTheme: string | null = localStorage.getItem("theme") || "light"; + const savedTheme: string | null = localStorage.getItem("theme") ?? "light"; return (
    { + const MAX_SPEED = 8; // Maximum speed + + const [expand, setExpand] = useState(true); + const { speed, setSpeed } = useAnimationPlaySpeed(); const [playSimulation, setPlaySimulation] = useState(false); const { setIsPlaying } = usePlayButtonStore(); @@ -29,8 +34,7 @@ const SimulationPlayer: React.FC = () => { // Button functions const handleReset = () => { - setReset(true); - // setReset(!isReset); + setReset(!isReset); setSpeed(1); }; const handlePlayStop = () => { @@ -49,7 +53,7 @@ const SimulationPlayer: React.FC = () => { }; const calculateHandlePosition = () => { - return ((speed - 0.5) / (8 - 0.5)) * 100; + return ((speed - 0.5) / (MAX_SPEED - 0.5)) * 100; }; const handleMouseDown = () => { @@ -99,7 +103,6 @@ const SimulationPlayer: React.FC = () => { { 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"; @@ -121,11 +124,11 @@ const SimulationPlayer: React.FC = () => { const intervals = [10, 20, 30, 40, 50, 60]; // in minutes const totalSegments = intervals.length; - const progress = 80; // percent (example) + const progress = 20; // percent (example) const processPlayerRef = useRef(null); const processWrapperRef = useRef(null); - const [playerPosition, setPlayerPosition] = useState(0); + const [playerPosition, setPlayerPosition] = useState(20); // initial position const handleProcessMouseDown = (e: React.MouseEvent) => { if (!processWrapperRef.current) return; @@ -204,7 +207,7 @@ const SimulationPlayer: React.FC = () => {
  • -
    { handleReset(); @@ -212,8 +215,8 @@ const SimulationPlayer: React.FC = () => { > Reset -
    -
    +
    -
    +
    -
    +
    + +
    @@ -295,7 +298,7 @@ const SimulationPlayer: React.FC = () => { Speed
    -
    0X
    +
    0.5X
    @@ -306,53 +309,57 @@ const SimulationPlayer: React.FC = () => {
    -
    {speed.toFixed(1)}x -
    +
    -
    8x
    +
    4x
    -
    +
    00:00
    +
    24:00
    - {process.map((item, index) => ( -
    - ))} +
    + {process.map((item, index) => ( +
    +
    +
    + ))} +
    -
    diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index 9515188..ee5c283 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -187,7 +187,7 @@ function processLoadedModel( }, ]); - if (item.eventData.type === "vehicle") { + if (item.eventData.type === "Vehicle") { const vehicleEvent: VehicleEventSchema = { modelUuid: item.modelUuid, modelName: item.modelName, @@ -202,7 +202,7 @@ function processLoadedModel( rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], action: { actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Vehicle Action", + actionName: "Action 1", actionType: "travel", unLoadDuration: 5, loadCapacity: 10, @@ -254,7 +254,7 @@ function processLoadedModel( rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], action: { actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Process Action", + actionName: "Action 1", actionType: "process", processTime: 10, swapMaterial: "material-id", @@ -279,7 +279,7 @@ function processLoadedModel( actions: [ { actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Pick and Place", + actionName: "Action 1", actionType: "pickAndPlace", process: { startPoint: [0, 0, 0], diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index c718ec3..64656a0 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -186,22 +186,59 @@ async function handleModelLoad( state: "idle", type: 'transfer', speed: 1, - points: data.points.map((point: THREE.Vector3, index: number) => ({ - uuid: THREE.MathUtils.generateUUID(), - position: [point.x, point.y, point.z], - rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: `Action ${index}`, - actionType: 'default', - material: 'Default Material', - delay: 0, - spawnInterval: 5, - spawnCount: 1, - triggers: [] + points: data.points.map((point: THREE.Vector3, index: number) => { + const triggers: TriggerSchema[] = []; + + if (data.points && index < data.points.length - 1) { + triggers.push({ + triggerUuid: THREE.MathUtils.generateUUID(), + triggerName: `Trigger 1`, + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: newFloorItem.modelName, + modelUuid: newFloorItem.modelUuid + }, + triggeredPoint: { + pointName: `Point`, + pointUuid: "" + }, + triggeredAction: { + actionName: `Action 1`, + actionUuid: "" + } + } + }); } - })) + + return { + uuid: THREE.MathUtils.generateUUID(), + position: [point.x, point.y, point.z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action 1`, + actionType: 'default', + material: 'Default Material', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: triggers + } + }; + }) }; + + for (let i = 0; i < ConveyorEvent.points.length - 1; i++) { + const currentPoint = ConveyorEvent.points[i]; + const nextPoint = ConveyorEvent.points[i + 1]; + + if (currentPoint.action.triggers.length > 0) { + currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint.pointUuid = nextPoint.uuid; + currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid = nextPoint.action.actionUuid; + } + } addEvent(ConveyorEvent); eventData.points = ConveyorEvent.points.map(point => ({ uuid: point.uuid, @@ -228,7 +265,7 @@ async function handleModelLoad( actionType: "travel", unLoadDuration: 5, loadCapacity: 10, - steeringAngle:0, + steeringAngle: 0, pickUpPoint: null, unLoadPoint: null, triggers: [] diff --git a/app/src/modules/market/AssetPreview.tsx b/app/src/modules/market/AssetPreview.tsx index 1d39920..a53a60d 100644 --- a/app/src/modules/market/AssetPreview.tsx +++ b/app/src/modules/market/AssetPreview.tsx @@ -1,6 +1,6 @@ import React, { Suspense, useEffect } from "react"; import assetImage from "../../assets/image/image.png"; -import { FiileedStarsIconSmall } from "../../components/icons/marketPlaceIcons"; +import { FilledStarsIconSmall } from "../../components/icons/marketPlaceIcons"; import { Canvas, useThree } from "@react-three/fiber"; import { ContactShadows, OrbitControls, Text } from "@react-three/drei"; import GltfLoader from "./GltfLoader"; @@ -98,7 +98,7 @@ const AssetPreview: React.FC = ({
    - + {selectedCard.rating}
    {selectedCard.views} views
    diff --git a/app/src/modules/market/Card.tsx b/app/src/modules/market/Card.tsx index ec9db06..a7010cc 100644 --- a/app/src/modules/market/Card.tsx +++ b/app/src/modules/market/Card.tsx @@ -3,6 +3,7 @@ import { CommentsIcon, DownloadIcon, EyeIconBig, + FilledStarsIconSmall, StarsIconSmall, VerifiedIcon, } from "../../components/icons/marketPlaceIcons"; @@ -80,7 +81,13 @@ const Card: React.FC = ({
    {[...Array(5)].map((_, index) => ( - + <> + {index < 3 ? ( + + ) : ( + + )} + ))}
    diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index d371806..cc9ce50 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -9,6 +9,7 @@ import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifie import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; +import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi"; function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) { const { camera, controls, gl, scene, pointer, raycaster } = useThree(); @@ -16,10 +17,28 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); + const { selectedProduct } = useSelectedProduct(); const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); const itemsData = useRef([]); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData + }) + } + useEffect(() => { if (!camera || !scene || toggleView || !itemsGroupRef.current) return; @@ -190,10 +209,19 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje }) } if (productData) { - useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, { + const event = useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, { position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], }) + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } } } @@ -203,9 +231,6 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje return updatedItems; }); - const email = localStorage.getItem("email"); - const organization = email ? email.split("@")[1].split(".")[0] : "default"; - //REST // await setFloorItemApi( diff --git a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx index 08667b4..7ea7045 100644 --- a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx @@ -8,6 +8,7 @@ import * as Types from "../../../../types/world/worldTypes"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; +import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi"; function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) { const { camera, controls, gl, scene, pointer, raycaster } = useThree(); @@ -15,10 +16,28 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); + const { selectedProduct } = useSelectedProduct(); const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); const itemsData = useRef([]); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData + }) + } + const prevPointerPosition = useRef(null); useEffect(() => { @@ -190,10 +209,19 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo }) } if (productData) { - useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, { + const event = useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, { position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], }) + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } } } @@ -203,9 +231,6 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo return updatedItems; }); - const email = localStorage.getItem("email"); - const organization = email ? email.split("@")[1].split(".")[0] : "default"; - //REST // await setFloorItemApi( diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index e4eaafb..5037f75 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -1,22 +1,29 @@ import React, { useEffect, useRef, useState } from "react"; import * as THREE from "three"; import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; -import useModuleStore from "../../../../../store/useModuleStore"; +import useModuleStore, { useSubModuleStore } from "../../../../../store/useModuleStore"; import { TransformControls } from "@react-three/drei"; import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys"; import { useSelectedEventSphere, useSelectedEventData, + useIsDragging, + useIsRotating, } from "../../../../../store/simulation/useSimulationStore"; +import { useThree } from "@react-three/fiber"; function PointsCreator() { + const { gl, raycaster, scene, pointer, camera } = useThree(); + const { subModule } = useSubModuleStore(); const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore(); const { activeModule } = useModuleStore(); const transformRef = useRef(null); const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere, } = useSelectedEventSphere(); - const { selectedEventData, setSelectedEventData, clearSelectedEventData } = useSelectedEventData(); + const { selectedEventData,setSelectedEventData, clearSelectedEventData } = useSelectedEventData(); + const { isDragging } = useIsDragging(); + const { isRotating } = useIsRotating(); useEffect(() => { if (selectedEventSphere) { @@ -75,6 +82,53 @@ function PointsCreator() { } }; + useEffect(() => { + const canvasElement = gl.domElement; + + let drag = false; + let isMouseDown = false; + + const onMouseDown = () => { + isMouseDown = true; + drag = false; + }; + + const onMouseUp = () => { + if (selectedEventSphere && !drag) { + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster + .intersectObjects(scene.children, true) + .filter( + (intersect) => + intersect.object.name === ('Event-Sphere') + ); + if (intersects.length === 0) { + clearSelectedEventSphere(); + setTransformMode(null); + } + } + } + + const onMouseMove = () => { + if (isMouseDown) { + drag = true; + } + }; + + if (subModule === 'mechanics') { + canvasElement.addEventListener("mousedown", onMouseDown); + canvasElement.addEventListener("mouseup", onMouseUp); + canvasElement.addEventListener("mousemove", onMouseMove); + } + + return () => { + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + }; + + }, [gl, subModule, selectedEventSphere]); + return ( <> {activeModule === "simulation" && ( @@ -133,10 +187,6 @@ function PointsCreator() { sphereRefs.current[event.point.uuid] ); }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} position={new THREE.Vector3(...event.point.position)} userData={{ modelUuid: event.modelUuid, diff --git a/app/src/modules/simulation/machine/machine.tsx b/app/src/modules/simulation/machine/machine.tsx index 32c3b8e..e9d2dea 100644 --- a/app/src/modules/simulation/machine/machine.tsx +++ b/app/src/modules/simulation/machine/machine.tsx @@ -1,7 +1,43 @@ -import React from 'react' +import React, { useEffect } from 'react' import MachineInstances from './instances/machineInstances' +import { useMachineStore } from '../../../store/simulation/useMachineStore' +import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; function Machine() { + const { addMachine, addCurrentAction, removeMachine } = useMachineStore(); + const { selectedProduct } = useSelectedProduct(); + + const machineSample: MachineEventSchema[] = [ + { + modelUuid: "machine-1234-5678-9012", + modelName: "CNC Milling Machine", + position: [10, 0, 5], + rotation: [0, 0, 0], + state: "idle", + type: "machine", + point: { + uuid: "machine-point-9876-5432-1098", + position: [10, 0.5, 5.2], + rotation: [0, 0, 0], + action: { + actionUuid: "machine-action-2468-1357-8024", + actionName: "Metal Processing", + actionType: "process", + processTime: 10, + swapMaterial: "steel", + triggers: [] + } + } + } + ]; + + useEffect(() => { + removeMachine(machineSample[0].modelUuid); + addMachine(selectedProduct.productId, machineSample[0]); + + // addCurrentAction(machineSample[0].modelUuid, machineSample[0].point.action.actionUuid); + }, []) + return ( <> diff --git a/app/src/modules/simulation/products/events/addOrRemoveEventsInProducts.tsx b/app/src/modules/simulation/products/events/addOrRemoveEventsInProducts.tsx index 9eececc..715aa37 100644 --- a/app/src/modules/simulation/products/events/addOrRemoveEventsInProducts.tsx +++ b/app/src/modules/simulation/products/events/addOrRemoveEventsInProducts.tsx @@ -53,7 +53,17 @@ function AddOrRemoveEventsInProducts() { const canvasElement = gl.domElement; if (!canvasElement) return; - let intersects = raycaster.intersectObjects(scene.children, true); + const intersects = raycaster + .intersectObjects(scene.children, true) + .filter( + (intersect) => + !intersect.object.name.includes("Roof") && + !intersect.object.name.includes("MeasurementReference") && + !intersect.object.name.includes("agv-collider") && + !(intersect.object.type === "GridHelper") && + !(intersect.object?.parent?.name.includes('zones')) && + !(intersect.object?.parent?.name.includes('Zone')) + ); if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) { let currentObject = intersects[0].object; @@ -116,6 +126,7 @@ function AddOrRemoveEventsInProducts() { }; }, [gl, subModule, selectedProduct, selectedAsset]); + return ( <> ) diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index ee1ac42..921dd96 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -7,7 +7,7 @@ import { upsertProductOrEventApi } from '../../../services/simulation/UpsertProd import { getAllProductsApi } from '../../../services/simulation/getallProductsApi'; function Products() { - const { products, addProduct, setProducts } = useProductStore(); + const { addProduct, setProducts } = useProductStore(); const { setSelectedProduct } = useSelectedProduct(); useEffect(() => { @@ -27,9 +27,6 @@ function Products() { }) }, []) - useEffect(() => { - }, []) - return ( <> diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index ff5e7e3..d4b7eaa 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -258,6 +258,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } const logStatus = (id: string, status: string) => { // + } return ( diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 5ca0ec5..757a9ef 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -23,7 +23,7 @@ function Simulation() { }, [events]) useEffect(() => { - // console.log('products: ', products); + console.log('products: ', products); }, [products]) return ( diff --git a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx index efefa0c..dcb46f4 100644 --- a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx +++ b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef, useState } from "react"; -import { useThree } from "@react-three/fiber"; +import { useFrame, useThree } from "@react-three/fiber"; import * as THREE from "three"; import { useSubModuleStore } from "../../../../store/useModuleStore"; import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore"; @@ -7,21 +7,28 @@ import { useProductStore } from "../../../../store/simulation/useProductStore"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { handleAddEventToProduct } from "../../events/points/functions/handleAddEventToProduct"; +import { QuadraticBezierLine } from "@react-three/drei"; +import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi"; +import { useDeleteTool } from "../../../../store/store"; interface ConnectionLine { id: string; - start: THREE.Vector3; - end: THREE.Vector3; - mid: THREE.Vector3; + startPointUuid: string; + endPointUuid: string; trigger: TriggerSchema; } function TriggerConnector() { - const { gl, raycaster, scene } = useThree(); + const { gl, raycaster, scene, pointer, camera } = useThree(); const { subModule } = useSubModuleStore(); - const { products, getPointByUuid, getIsEventInProduct, getActionByUuid, addTrigger, addEvent, getEventByModelUuid } = useProductStore(); + const { products, getPointByUuid, getIsEventInProduct, getActionByUuid, addTrigger, removeTrigger, addEvent, getEventByModelUuid, getProductById } = useProductStore(); const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); const { selectedProduct } = useSelectedProduct(); + const [hoveredLineKey, setHoveredLineKey] = useState(null); + const groupRefs = useRef>({}); + const [helperlineColor, setHelperLineColor] = useState("red"); + const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3; end: THREE.Vector3; mid: THREE.Vector3; } | null>(null); + const { deleteTool } = useDeleteTool(); const [firstSelectedPoint, setFirstSelectedPoint] = useState<{ productId: string; @@ -32,52 +39,99 @@ function TriggerConnector() { const [connections, setConnections] = useState([]); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData + }) + } + useEffect(() => { const newConnections: ConnectionLine[] = []; - products.forEach(product => { - product.eventDatas.forEach(event => { - if ('points' in event) { - event.points.forEach(point => { - if ('action' in point && point.action?.triggers) { - point.action.triggers.forEach(trigger => { - if (trigger.triggeredAsset) { - const targetPoint = getPointByUuid( - product.productId, - trigger.triggeredAsset.triggeredModel.modelUuid, - trigger.triggeredAsset.triggeredPoint.pointUuid - ); + const product = getProductById(selectedProduct.productId); + if (!product || products.length === 0) return; - if (targetPoint) { - const startPos = new THREE.Vector3(...point.position); - const endPos = new THREE.Vector3(...targetPoint.position); - const midPos = new THREE.Vector3() - .addVectors(startPos, endPos) - .multiplyScalar(0.5) - .add(new THREE.Vector3(0, 2, 0)); - - newConnections.push({ - id: `${point.uuid}-${targetPoint.uuid}-${trigger.triggerUuid}`, - start: startPos, - end: endPos, - mid: midPos, - trigger - }); - } - } + product.eventDatas.forEach(event => { + // Handle Conveyor points + if (event.type === "transfer" && 'points' in event) { + event.points.forEach(point => { + if (point.action?.triggers) { + point.action.triggers.forEach(trigger => { + if (trigger.triggeredAsset) { + newConnections.push({ + id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`, + startPointUuid: point.uuid, + endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid, + trigger + }); + } + }); + } + }); + } + // Handle Vehicle point + else if (event.type === "vehicle" && 'point' in event) { + const point = event.point; + if (point.action?.triggers) { + point.action.triggers.forEach(trigger => { + if (trigger.triggeredAsset) { + newConnections.push({ + id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`, + startPointUuid: point.uuid, + endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid, + trigger }); } }); } - }); + } + // Handle Robotic Arm points + else if (event.type === "roboticArm" && 'point' in event) { + const point = event.point; + point.actions?.forEach(action => { + action.triggers?.forEach(trigger => { + if (trigger.triggeredAsset) { + newConnections.push({ + id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`, + startPointUuid: point.uuid, + endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid, + trigger + }); + } + }); + }); + } + // Handle Machine point + else if (event.type === "machine" && 'point' in event) { + const point = event.point; + if (point.action?.triggers) { + point.action.triggers.forEach(trigger => { + if (trigger.triggeredAsset) { + newConnections.push({ + id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`, + startPointUuid: point.uuid, + endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid, + trigger + }); + } + }); + } + } }); setConnections(newConnections); - }, [products]); - - useEffect(() => { - console.log('connections: ', connections); - }, connections) + }, [products, selectedProduct.productId]); useEffect(() => { const canvasElement = gl.domElement; @@ -111,15 +165,31 @@ function TriggerConnector() { if (drag) return; evt.preventDefault(); - const intersects = raycaster.intersectObjects(scene.children, true); - if (intersects.length === 0) return; + const intersects = raycaster + .intersectObjects(scene.children, true) + .filter( + (intersect) => + intersect.object.name === ('Event-Sphere') + ); + if (intersects.length === 0) { + setFirstSelectedPoint(null); + return; + }; const currentObject = intersects[0].object; - if (!currentObject || currentObject.name !== 'Event-Sphere') return; + if (!currentObject || currentObject.name !== 'Event-Sphere') { + setFirstSelectedPoint(null); + return; + }; const modelUuid = currentObject.userData.modelUuid; const pointUuid = currentObject.userData.pointUuid; + if (firstSelectedPoint && firstSelectedPoint.pointUuid === pointUuid) { + setFirstSelectedPoint(null); + return; + } + if (selectedProduct && getIsEventInProduct(selectedProduct.productId, modelUuid)) { const point = getPointByUuid( @@ -128,7 +198,12 @@ function TriggerConnector() { pointUuid ); - if (!point) return; + const event = getEventByModelUuid(selectedProduct.productId, modelUuid); + + if (!point || !event) { + setFirstSelectedPoint(null); + return; + }; let actionUuid: string | undefined; if ('action' in point && point.action) { @@ -152,12 +227,12 @@ function TriggerConnector() { delay: 0, triggeredAsset: { triggeredModel: { - modelName: currentObject.parent?.parent?.name || 'Unknown', + modelName: event.modelName || 'Unknown', modelUuid: modelUuid }, triggeredPoint: { - pointName: currentObject.name, - pointUuid: pointUuid + pointName: 'Point', + pointUuid: point.uuid }, triggeredAction: actionUuid ? { actionName: getActionByUuid(selectedProduct.productId, actionUuid)?.actionName || 'Action', @@ -167,7 +242,16 @@ function TriggerConnector() { }; if (firstSelectedPoint.actionUuid) { - addTrigger(firstSelectedPoint.actionUuid, trigger); + const event = addTrigger(selectedProduct.productId, firstSelectedPoint.actionUuid, trigger); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } } setFirstSelectedPoint(null); } @@ -184,7 +268,12 @@ function TriggerConnector() { pointUuid ); - if (!point) return; + const event = getEventByModelUuid(selectedProduct.productId, modelUuid); + + if (!point || !event) { + setFirstSelectedPoint(null); + return; + }; let actionUuid: string | undefined; if ('action' in point && point.action) { @@ -200,12 +289,12 @@ function TriggerConnector() { delay: 0, triggeredAsset: { triggeredModel: { - modelName: currentObject.parent?.parent?.name || 'Unknown', + modelName: event.modelName || 'Unknown', modelUuid: modelUuid }, triggeredPoint: { - pointName: currentObject.name, - pointUuid: pointUuid + pointName: 'Point', + pointUuid: point.uuid }, triggeredAction: actionUuid ? { actionName: getActionByUuid(selectedProduct.productId, actionUuid)?.actionName || 'Action', @@ -215,13 +304,24 @@ function TriggerConnector() { }; if (firstSelectedPoint.actionUuid) { - addTrigger(firstSelectedPoint.actionUuid, trigger); + const event = addTrigger(selectedProduct.productId, firstSelectedPoint.actionUuid, trigger); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } } setFirstSelectedPoint(null); + } else if (firstSelectedPoint) { + setFirstSelectedPoint(null); } }; - if (subModule === 'simulations') { + if (subModule === 'simulations' && !deleteTool) { canvasElement.addEventListener("mousedown", onMouseDown); canvasElement.addEventListener("mouseup", onMouseUp); canvasElement.addEventListener("mousemove", onMouseMove); @@ -235,11 +335,149 @@ function TriggerConnector() { canvasElement.removeEventListener('contextmenu', handleRightClick); }; - }, [gl, subModule, selectedProduct, firstSelectedPoint]); + }, [gl, subModule, selectedProduct, firstSelectedPoint, deleteTool]); + + + useFrame(() => { + if (firstSelectedPoint) { + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects(scene.children, true).filter( + (intersect) => + !intersect.object.name.includes("Roof") && + !intersect.object.name.includes("agv-collider") && + !intersect.object.name.includes("MeasurementReference") && + !intersect.object.parent?.name.includes("Zone") && + !(intersect.object.type === "GridHelper") && + !(intersect.object.type === "Line2") + ); + + let point: THREE.Vector3 | null = null; + + if (intersects.length > 0) { + point = intersects[0].point; + if (point.y < 0.05) { + point = new THREE.Vector3(point.x, 0.05, point.z); + } + } + + const sphereIntersects = raycaster.intersectObjects(scene.children, true).filter((intersect) => intersect.object.name === ('Event-Sphere')); + + if (sphereIntersects.length > 0 && sphereIntersects[0].object.uuid === firstSelectedPoint.pointUuid) { + setHelperLineColor('red'); + setCurrentLine(null); + return; + } + + const startPoint = getWorldPositionFromScene(firstSelectedPoint.pointUuid); + + if (point && startPoint) { + if (sphereIntersects.length > 0) { + point = sphereIntersects[0].object.getWorldPosition(new THREE.Vector3()); + } + const distance = startPoint.distanceTo(point); + const heightFactor = Math.max(0.5, distance * 0.2); + const midPoint = new THREE.Vector3( + (startPoint.x + point.x) / 2, + Math.max(startPoint.y, point.y) + heightFactor, + (startPoint.z + point.z) / 2 + ); + + const endPoint = point; + + setCurrentLine({ + start: startPoint, + mid: midPoint, + end: endPoint, + }); + + setHelperLineColor(sphereIntersects.length > 0 ? "#6cf542" : "red"); + } else { + setCurrentLine(null); + } + } else { + setCurrentLine(null); + } + + }) + + const getWorldPositionFromScene = (pointUuid: string): THREE.Vector3 | null => { + const pointObj = scene.getObjectByProperty("uuid", pointUuid); + if (!pointObj) return null; + + const worldPosition = new THREE.Vector3(); + pointObj.getWorldPosition(worldPosition); + return worldPosition; + }; + + const removeConnection = (connection: ConnectionLine) => { + if (connection.trigger.triggerUuid) { + const event = removeTrigger(selectedProduct.productId, connection.trigger.triggerUuid); + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + } + }; return ( - <> - + + {connections.map((connection) => { + const startPoint = getWorldPositionFromScene(connection.startPointUuid); + const endPoint = getWorldPositionFromScene(connection.endPointUuid); + + if (!startPoint || !endPoint) return null; + + const distance = startPoint.distanceTo(endPoint); + const heightFactor = Math.max(0.5, distance * 0.2); + const midPoint = new THREE.Vector3( + (startPoint.x + endPoint.x) / 2, + Math.max(startPoint.y, endPoint.y) + heightFactor, + (startPoint.z + endPoint.z) / 2 + ); + + return ( + (groupRefs.current[connection.id] = el!)} + start={startPoint.toArray()} + end={endPoint.toArray()} + mid={midPoint.toArray()} + color={deleteTool && hoveredLineKey === connection.id ? "red" : "#42a5f5"} + lineWidth={4} + dashed={deleteTool && hoveredLineKey === connection.id ? false : true} + dashSize={0.75} + dashScale={20} + onPointerOver={() => setHoveredLineKey(connection.id)} + onPointerOut={() => setHoveredLineKey(null)} + onClick={() => { + if (deleteTool) { + setHoveredLineKey(null); + setCurrentLine(null); + removeConnection(connection); + } + }} + userData={connection.trigger} + /> + ); + })} + + {currentLine && ( + + )} + ); } diff --git a/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx index 5dec724..2a124cd 100644 --- a/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx +++ b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx @@ -1,12 +1,16 @@ import React, { useEffect, useRef, useState } from 'react'; +import * as Types from "../../../../types/world/worldTypes"; import startPoint from "../../../../assets/gltf-glb/arrow_green.glb"; -import startEnd from "../../../../assets/gltf-glb/arrow_red.glb"; import * as THREE from "three"; +import startEnd from "../../../../assets/gltf-glb/arrow_red.glb"; import { useGLTF } from '@react-three/drei'; import { useFrame, useThree } from '@react-three/fiber'; -import { useSelectedEventSphere } from '../../../../store/simulation/useSimulationStore'; +import { useSelectedEventSphere, useIsDragging, useIsRotating } from '../../../../store/simulation/useSimulationStore'; import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; -import * as Types from "../../../../types/world/worldTypes"; +import { useProductStore } from '../../../../store/simulation/useProductStore'; +import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; +import { upsertProductOrEventApi } from '../../../../services/simulation/UpsertProductOrEventApi'; + const VehicleUI = () => { const { scene: startScene } = useGLTF(startPoint) as any; const { scene: endScene } = useGLTF(startEnd) as any; @@ -14,67 +18,60 @@ const VehicleUI = () => { const endMarker = useRef(null); const prevMousePos = useRef({ x: 0, y: 0 }); const { selectedEventSphere } = useSelectedEventSphere(); - const { vehicles, updateVehicle } = useVehicleStore(); + const { selectedProduct } = useSelectedProduct(); + const { getVehicleById } = useVehicleStore(); + const { updateEvent } = useProductStore(); const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 0, 0]); const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 0, 0]); const [startRotation, setStartRotation] = useState<[number, number, number]>([0, 0, 0]); const [endRotation, setEndRotation] = useState<[number, number, number]>([0, 0, 0]); - const [isDragging, setIsDragging] = useState<"start" | "end" | null>(null); - const [isRotating, setIsRotating] = useState<"start" | "end" | null>(null); + const { isDragging, setIsDragging } = useIsDragging(); + const { isRotating, setIsRotating } = useIsRotating(); const { raycaster } = useThree(); const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); const state: Types.ThreeState = useThree(); const controls: any = state.controls; + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData + }) + } + useEffect(() => { if (!selectedEventSphere) return; - const selectedVehicle = vehicles.find( - (vehicle: any) => vehicle.modelUuid === selectedEventSphere.userData.modelUuid - ); + const selectedVehicle = getVehicleById(selectedEventSphere.userData.modelUuid); if (selectedVehicle?.point?.action) { const { pickUpPoint, unLoadPoint } = selectedVehicle.point.action; if (pickUpPoint) { - const pickupPosition = new THREE.Vector3( - pickUpPoint.position.x, - pickUpPoint.position.y, - pickUpPoint.position.z - ); - const pickupRotation = new THREE.Vector3( - pickUpPoint.rotation.x, - pickUpPoint.rotation.y, - pickUpPoint.rotation.z - ); - pickupPosition.y = 0; - setStartPosition([pickupPosition.x, 0, pickupPosition.z]); - setStartRotation([pickupRotation.x, pickupRotation.y, pickupRotation.z]); + setStartPosition([pickUpPoint.position.x, 0, pickUpPoint.position.z]); + setStartRotation([pickUpPoint.rotation.x, pickUpPoint.rotation.y, pickUpPoint.rotation.z]); } else { const defaultLocal = new THREE.Vector3(0, 0, 1.5); const defaultWorld = selectedEventSphere.localToWorld(defaultLocal); - defaultWorld.y = 0; setStartPosition([defaultWorld.x, 0, defaultWorld.z]); setStartRotation([0, 0, 0]); } if (unLoadPoint) { - const unLoadPosition = new THREE.Vector3( - unLoadPoint.position.x, - unLoadPoint.position.y, - unLoadPoint.position.z - ); - const unLoadRotation = new THREE.Vector3( - unLoadPoint.rotation.x, - unLoadPoint.rotation.y, - unLoadPoint.position.z - ); - unLoadPosition.y = 0; // Force y to 0 - setEndPosition([unLoadPosition.x, 0, unLoadPosition.z]); - setEndRotation([unLoadRotation.x, unLoadRotation.y, unLoadRotation.z]); + setEndPosition([unLoadPoint.position.x, 0, unLoadPoint.position.z]); + setEndRotation([unLoadPoint.rotation.x, unLoadPoint.rotation.y, unLoadPoint.rotation.z]); } else { const defaultLocal = new THREE.Vector3(0, 0, -1.5); const defaultWorld = selectedEventSphere.localToWorld(defaultLocal); - defaultWorld.y = 0; // Force y to 0 setEndPosition([defaultWorld.x, 0, defaultWorld.z]); setEndRotation([0, 0, 0]); } @@ -87,7 +84,6 @@ const VehicleUI = () => { const intersects = raycaster.ray.intersectPlane(plane.current, intersectPoint); if (intersects) { - intersectPoint.y = 0; // Force y to 0 if (isDragging === "start") { setStartPosition([intersectPoint.x, 0, intersectPoint.z]); } @@ -108,12 +104,12 @@ const VehicleUI = () => { if (marker) { const rotationSpeed = 10; - marker.rotation.y += deltaX * rotationSpeed; if (isRotating === 'start') { - setStartRotation([marker.rotation.x, marker.rotation.y, marker.rotation.z]) + const y = startRotation[1] + deltaX * rotationSpeed; + setStartRotation([0, y, 0]); } else { - - setEndRotation([marker.rotation.x, marker.rotation.y, marker.rotation.z]) + const y = endRotation[1] + deltaX * rotationSpeed; + setEndRotation([0, y, 0]); } } }); @@ -142,43 +138,34 @@ const VehicleUI = () => { setIsRotating(null); if (selectedEventSphere?.userData.modelUuid) { - const updatedVehicle = vehicles.find( - (vehicle) => vehicle.modelUuid === selectedEventSphere.userData.modelUuid - ); + const updatedVehicle = getVehicleById(selectedEventSphere.userData.modelUuid); if (updatedVehicle) { - updateVehicle(selectedEventSphere.userData.modelUuid, { + const event = updateEvent(selectedProduct.productId, selectedEventSphere.userData.modelUuid, { point: { ...updatedVehicle.point, action: { ...updatedVehicle.point?.action, pickUpPoint: { - position: { - x: startPosition[0], - y: startPosition[1], - z: startPosition[2], - }, - rotation: { - x: startRotation[0], - y: startRotation[1], - z: startRotation[2], - }, + position: { x: startPosition[0], y: startPosition[1], z: startPosition[2], }, + rotation: { x: 0, y: startRotation[1], z: 0, }, }, unLoadPoint: { - position: { - x: endPosition[0], - y: endPosition[1], - z: endPosition[2], - }, - rotation: { - x: endRotation[0], - y: endRotation[1], - z: endRotation[2], - }, + position: { x: endPosition[0], y: endPosition[1], z: endPosition[2], }, + rotation: { x: 0, y: endRotation[1], z: 0, }, }, }, }, - }); + }) + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } } } }; @@ -208,6 +195,7 @@ const VehicleUI = () => { object={startScene} ref={startMarker} position={startPosition} + rotation={startRotation} onPointerDown={(e: any) => { e.stopPropagation(); handlePointerDown(e, "start", "start"); @@ -224,6 +212,7 @@ const VehicleUI = () => { object={endScene} ref={endMarker} position={endPosition} + rotation={endRotation} onPointerDown={(e: any) => { e.stopPropagation(); handlePointerDown(e, "end", "end"); diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index 2f0b235..9ca7355 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -11,7 +11,7 @@ interface VehicleAnimatorProps { reset: () => void; currentPhase: string; agvUuid: number; - agvDetail: any; + agvDetail: VehicleStatus; } function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) { @@ -32,7 +32,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai let startTime: number; let fixedInterval: number; let coveredDistance = progressRef.current; - let objectRotation = (agvDetail.point?.action?.pickUpPoint?.rotation || { x: 0, y: 0, z: 0 }) as { x: number; y: number; z: number }; + let objectRotation = (agvDetail.point?.action?.pickUpPoint?.rotation || { x: 0, y: 0, z: 0 }) as { x: number; y: number; z: number } | undefined; useEffect(() => { @@ -67,10 +67,9 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai setRestingRotation(true); decrementVehicleLoad(agvDetail.modelUuid, 0); const object = scene.getObjectByProperty('uuid', agvUuid); - console.log('currentPhase: ', currentPhase); if (object) { object.position.set(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]); - object.rotation.set(objectRotation.x, objectRotation.y, objectRotation.z); + object.rotation.set(agvDetail.rotation[0], agvDetail.rotation[1], agvDetail.rotation[2]); } } }, [isReset, isPlaying]) @@ -132,7 +131,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai } if (progressRef.current >= totalDistance) { - if (restRotation) { + if (restRotation && objectRotation) { const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(objectRotation.x, objectRotation.y, objectRotation.z)); object.quaternion.slerp(targetQuaternion, delta * 2); const angleDiff = object.quaternion.angleTo(targetQuaternion); diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 6a81d3a..412a4ba 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -30,7 +30,8 @@ function VehicleInstance({ agvDetail }: any) { ); function vehicleStatus(modelId: string, status: string) { - // console.log(`${modelId} , ${status}); + // console.log(`${modelId} , ${status}`); + } // Function to reset everything @@ -44,7 +45,7 @@ function VehicleInstance({ agvDetail }: any) { const increment = () => { if (isIncrememtable.current) { - incrementVehicleLoad(agvDetail.modelUuid, 2); + incrementVehicleLoad(agvDetail.modelUuid, 10); isIncrememtable.current = false; } } @@ -69,6 +70,7 @@ function VehicleInstance({ agvDetail }: any) { increment(); }, 5000); + if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) { const toDrop = computePath( agvDetail.point.action.pickUpPoint.position, diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 7badec5..19f049c 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -1,220 +1,48 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; import VehicleInstances from "./instances/vehicleInstances"; import { useVehicleStore } from "../../../store/simulation/useVehicleStore"; -import { useFloorItems } from "../../../store/store"; -import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; +import { useSelectedEventData, useSelectedEventSphere, useSelectedProduct } from "../../../store/simulation/useSimulationStore"; import VehicleUI from "../ui/vehicle/vehicleUI"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; -function Vehicles() { +import { useProductStore } from "../../../store/simulation/useProductStore"; - const { vehicles, addVehicle } = useVehicleStore(); +function Vehicles() { + const { products, getProductById } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + const { vehicles, addVehicle, clearvehicles } = useVehicleStore(); const { selectedEventSphere } = useSelectedEventSphere(); const { selectedEventData } = useSelectedEventData(); - const { floorItems } = useFloorItems(); const { isPlaying } = usePlayButtonStore(); - const [vehicleStatusSample, setVehicleStatusSample] = useState< - VehicleEventSchema[] - >([ - { - modelUuid: "9356f710-4727-4b50-bdb2-9c1e747ecc74", - modelName: "AGV", - position: [97.9252965204558, 0, 37.96138815638661], - rotation: [0, 0, 0], - state: "idle", - type: "vehicle", - speed: 2.5, - point: { - uuid: "point-789", - position: [0, 1, 0], - rotation: [0, 0, 0], - action: { - actionUuid: "action-456", - actionName: "Deliver to Zone A", - actionType: "travel", - unLoadDuration: 10, - loadCapacity: 2, - steeringAngle:0, - pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, - unLoadPoint: { position: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, - triggers: [ - { - triggerUuid: "trig-001", - triggerName: "Start Travel", - triggerType: "onComplete", - delay: 0, - triggeredAsset: { - triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, - triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } - } - }, - { - triggerUuid: "trig-002", - triggerName: "Complete Travel", - triggerType: "onComplete", - delay: 2, - triggeredAsset: null - } - ] - } + useEffect(() => { + if (selectedProduct.productId) { + const product = getProductById(selectedProduct.productId); + if (product) { + clearvehicles(); + product.eventDatas.forEach(events => { + if (events.type === 'vehicle') { + addVehicle(selectedProduct.productId, events); + } + }); } - }, - { - modelUuid: "b06960bb-3d2e-41f7-a646-335f389c68b4", - modelName: "AGV", - position: [89.61609306554463, 0, 33.634136622267356], - rotation: [0, 0, 0], - state: "idle", - type: "vehicle", - speed: 2.5, - point: { - uuid: "point-789", - position: [0, 1, 0], - rotation: [0, 0, 0], - action: { - actionUuid: "action-456", - actionName: "Deliver to Zone A", - actionType: "travel", - unLoadDuration: 10, - loadCapacity: 2, - steeringAngle:0, - pickUpPoint: null, - unLoadPoint: null, - triggers: [ - { - triggerUuid: "trig-001", - triggerName: "Start Travel", - triggerType: "onStart", - delay: 0, - triggeredAsset: { - triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, - triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } - } - }, - { - triggerUuid: "trig-002", - triggerName: "Complete Travel", - triggerType: "onComplete", - delay: 2, - triggeredAsset: null - } - ] - } - } - }, - // { - // modelUuid: "cd7d0584-0684-42b4-b051-9e882c1914aa", - // modelName: "AGV", - // position: [105.90938758014703, 0, 31.584209911095215], - // rotation: [0, 0, 0], - // state: "idle", - // type: "vehicle", - // speed: 2.5, - // point: { - // uuid: "point-789", - // position: [0, 1, 0], - // rotation: [0, 0, 0], - // action: { - // actionUuid: "action-456", - // actionName: "Deliver to Zone A", - // actionType: "travel", - // unLoadDuration: 10, - // loadCapacity: 2, - // steeringAngle:0, - // pickUpPoint: null, - // unLoadPoint: null, - // triggers: [ - // { - // triggerUuid: "trig-001", - // triggerName: "Start Travel", - // triggerType: "onStart", - // delay: 0, - // triggeredAsset: { - // triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - // triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, - // triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } - // } - // }, - // { - // triggerUuid: "trig-002", - // triggerName: "Complete Travel", - // triggerType: "onComplete", - // delay: 2, - // triggeredAsset: null - // } - // ] - // } - // } - // }, - // { - // modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79", - // modelName: "forklift", - // position: [98.85729337188162, 0, 38.36616546567653], - // rotation: [0, 0, 0], - // state: "idle", - // type: "vehicle", - // speed: 2.5, - // point: { - // uuid: "point-789", - // position: [0, 1, 0], - // rotation: [0, 0, 0], - // action: { - // actionUuid: "action-456", - // actionName: "Deliver to Zone A", - // actionType: "travel", - // unLoadDuration: 15, - // loadCapacity: 5, - // steeringAngle:0, - // pickUpPoint: null, - // unLoadPoint: null, - // triggers: [ - // { - // triggerUuid: "trig-001", - // triggerName: "Start Travel", - // triggerType: "onStart", - // delay: 0, - // triggeredAsset: { - // triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - // triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, - // triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } - // } - // }, - // { - // triggerUuid: "trig-002", - // triggerName: "Complete Travel", - // triggerType: "onComplete", - // delay: 2, - // triggeredAsset: null - // } - // ] - // } - // } - // } - ]); + } + }, [selectedProduct, products]); + useEffect(() => { // console.log('vehicles: ', vehicles); }, [vehicles]) - useEffect(() => { - addVehicle("123", vehicleStatusSample[0]); - addVehicle('123', vehicleStatusSample[1]); - // addVehicle('123', vehicleStatusSample[2]); - }, []); - - return ( <> + + {selectedEventSphere && selectedEventData?.data.type === "vehicle" && !isPlaying && < VehicleUI /> } + ); } -export default Vehicles; - - - +export default Vehicles; \ No newline at end of file diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index 05f7371..56e3054 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -11,10 +11,7 @@ import { useDroppedObjectsStore, useFloatingWidget, } from "../../store/visualization/useDroppedObjectsStore"; -import { - useSocketStore, - useWidgetSubOption, -} from "../../store/store"; +import { useSocketStore, useWidgetSubOption } from "../../store/store"; import { getZone2dData } from "../../services/visulization/zone/getZoneData"; import { generateUniqueId } from "../../functions/generateUniqueId"; import { determinePosition } from "./functions/determinePosition"; @@ -76,6 +73,7 @@ const RealTimeVisulization: React.FC = () => { const { widgetSubOption } = useWidgetSubOption(); const { visualizationSocket } = useSocketStore(); const { setSelectedChartId } = useWidgetStore(); + const [waitingPanels, setWaitingPanels] = useState(null); OuterClick({ contextClassName: [ @@ -377,6 +375,8 @@ const RealTimeVisulization: React.FC = () => { setHiddenPanels={setHiddenPanels} selectedZone={selectedZone} setSelectedZone={setSelectedZone} + waitingPanels={waitingPanels} + setWaitingPanels={setWaitingPanels} /> )} @@ -385,6 +385,7 @@ const RealTimeVisulization: React.FC = () => { setSelectedZone={setSelectedZone} hiddenPanels={hiddenPanels} setZonesData={setZonesData} + waitingPanels={waitingPanels} /> )} diff --git a/app/src/modules/visualization/widgets/panel/AddButtons.tsx b/app/src/modules/visualization/widgets/panel/AddButtons.tsx index 4877824..6968c2e 100644 --- a/app/src/modules/visualization/widgets/panel/AddButtons.tsx +++ b/app/src/modules/visualization/widgets/panel/AddButtons.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState } from "react"; import { CleanPannel, EyeIcon, @@ -6,8 +6,6 @@ import { } from "../../../../components/icons/RealTimeVisulationIcons"; import { AddIcon } from "../../../../components/icons/ExportCommonIcons"; import { useSocketStore } from "../../../../store/store"; -import { clearPanel } from "../../../../services/visulization/zone/clearPanel"; -import { lockPanel } from "../../../../services/visulization/zone/lockPanel"; // Define the type for `Side` type Side = "top" | "bottom" | "left" | "right"; @@ -57,6 +55,8 @@ interface ButtonsProps { >; hiddenPanels: HiddenPanels; // Updated prop type setHiddenPanels: React.Dispatch>; // Updated prop type + waitingPanels: any; + setWaitingPanels: any; } const AddButtons: React.FC = ({ @@ -64,6 +64,8 @@ const AddButtons: React.FC = ({ setSelectedZone, setHiddenPanels, hiddenPanels, + waitingPanels, + setWaitingPanels, }) => { const { visualizationSocket } = useSocketStore(); @@ -174,65 +176,62 @@ const AddButtons: React.FC = ({ // Function to handle "+" button click const handlePlusButtonClick = async (side: Side) => { + const zoneId = selectedZone.zoneId; + if (selectedZone.activeSides.includes(side)) { - console.log("open"); - // Panel already exists: Remove widgets from that side and update activeSides - const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value + // Already active: Schedule removal - // Remove all widgets associated with the side and update active sides - const cleanedWidgets = selectedZone.widgets.filter( - (widget) => widget.panel !== side - ); - const newActiveSides = selectedZone.activeSides.filter((s) => s !== side); + setWaitingPanels(side); // Mark as waiting - const updatedZone = { - ...selectedZone, - widgets: cleanedWidgets, - activeSides: newActiveSides, - panelOrder: newActiveSides, - }; + setTimeout(() => { + console.log("Removing after wait..."); - let deletePanel = { - organization: organization, - panelName: side, - zoneId: selectedZone.zoneId, - }; - if (visualizationSocket) { - visualizationSocket.emit("v2:viz-panel:delete", deletePanel); - } - setSelectedZone(updatedZone); - - if (hiddenPanels[selectedZone.zoneId]?.includes(side)) { - setHiddenPanels((prev) => ({ - ...prev, - [selectedZone.zoneId]: prev[selectedZone.zoneId].filter( - (s) => s !== side - ), - })); - } - - // if(hiddenPanels[selectedZone.zoneId].includes(side)) - - // API call to delete the panel - // try { - // const response = await deletePanelApi(selectedZone.zoneId, side, organization); - // - // if (response.message === "Panel deleted successfully") { - // } else { - // - // } - // } catch (error) { - // - // } - } else { - // Panel does not exist: Create panel - try { - // Get email and organization safely with a default fallback const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0]; + const organization = email?.split("@")[1]?.split(".")[0] || ""; + + // Remove widgets for that side + const cleanedWidgets = selectedZone.widgets.filter( + (widget) => widget.panel !== side + ); + const newActiveSides = selectedZone.activeSides.filter( + (s) => s !== side + ); + + const updatedZone = { + ...selectedZone, + widgets: cleanedWidgets, + activeSides: newActiveSides, + panelOrder: newActiveSides, + }; + + const deletePanel = { + organization, + panelName: side, + zoneId, + }; + + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-panel:delete", deletePanel); + } + + setSelectedZone(updatedZone); + + if (hiddenPanels[zoneId]?.includes(side)) { + setHiddenPanels((prev) => ({ + ...prev, + [zoneId]: prev[zoneId].filter((s) => s !== side), + })); + } + + // Remove from waiting state + setWaitingPanels(null); + }, 500); // Wait for 2 seconds + } else { + // Panel does not exist: Add it + try { + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] || ""; - // Prevent duplicate side entries const newActiveSides = selectedZone.activeSides.includes(side) ? [...selectedZone.activeSides] : [...selectedZone.activeSides, side]; @@ -242,32 +241,31 @@ const AddButtons: React.FC = ({ activeSides: newActiveSides, panelOrder: newActiveSides, }; - let addPanel = { - organization: organization, - zoneId: selectedZone.zoneId, + + const addPanel = { + organization, + zoneId, panelOrder: newActiveSides, }; + if (visualizationSocket) { visualizationSocket.emit("v2:viz-panel:add", addPanel); } - setSelectedZone(updatedZone); - // API call to create panels - // const response = await panelData(organization, selectedZone.zoneId, newActiveSides); - // - // if (response.message === "Panels created successfully") { - // } else { - // - // } - } catch (error) {} + setSelectedZone(updatedZone); + } catch (error) { + console.error("Error adding panel:", error); + } } }; + return ( <>
    {(["top", "right", "bottom", "left"] as Side[]).map((side) => (
    {/* "+" Button */} +