diff --git a/app/src/assets/gltf-glb/arrow_green.glb b/app/src/assets/gltf-glb/arrow_green.glb new file mode 100644 index 0000000..8e02527 Binary files /dev/null and b/app/src/assets/gltf-glb/arrow_green.glb differ diff --git a/app/src/assets/gltf-glb/arrow_red.glb b/app/src/assets/gltf-glb/arrow_red.glb new file mode 100644 index 0000000..02bfea4 Binary files /dev/null and b/app/src/assets/gltf-glb/arrow_red.glb differ 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..8e03fd0 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,7 +649,7 @@ export const MonthlyROI = () => { > ); @@ -666,15 +666,15 @@ export const ExpandIcon = () => { > ); @@ -691,21 +691,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 ( // @@ -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/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 88ae240..4fa9105 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -1,9 +1,8 @@ import React, { useEffect, useState } from "react"; import { - useSelectedAsset, - useSelectedEventData, - useSelectedEventSphere, - useSelectedProduct, + useSelectedEventData, + useSelectedEventSphere, + useSelectedProduct, } from "../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import ConveyorMechanics from "./mechanics/conveyorMechanics"; @@ -13,120 +12,117 @@ import MachineMechanics from "./mechanics/machineMechanics"; import StorageMechanics from "./mechanics/storageMechanics"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import { handleAddEventToProduct } from "../../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; +import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; const EventProperties: React.FC = () => { - const { selectedEventData } = useSelectedEventData(); - const { getEventByModelUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); - const [currentEventData, setCurrentEventData] = useState( - null - ); - const [assetType, setAssetType] = useState(null); - const { products, addEvent } = useProductStore(); - const { selectedEventSphere } = useSelectedEventSphere(); + const { selectedEventData } = useSelectedEventData(); + const { getEventByModelUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + const [currentEventData, setCurrentEventData] = useState(null); + const [assetType, setAssetType] = useState(null); + const { products, addEvent } = useProductStore(); + const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); - useEffect(() => { - const event = getCurrentEventData(); - setCurrentEventData(event); + useEffect(() => { + const event = getCurrentEventData(); + setCurrentEventData(event); - const type = determineAssetType(event); - setAssetType(type); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedEventData, selectedProduct]); + const type = determineAssetType(event); + setAssetType(type); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedEventData, selectedProduct]); + + const getCurrentEventData = () => { + if (!selectedEventData?.data || !selectedProduct) return null; + return ( + getEventByModelUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid + ) ?? null + ); + }; + + const determineAssetType = (event: EventsSchema | null) => { + if (!event) return null; + + switch (event.type) { + case "transfer": + return "conveyor"; + case "vehicle": + return "vehicle"; + case "roboticArm": + return "roboticArm"; + case "machine": + return "machine"; + case "storageUnit": + return "storageUnit"; + default: + return null; + } + }; - const getCurrentEventData = () => { - if (!selectedEventData?.data || !selectedProduct) return null; return ( - getEventByModelUuid( - selectedProduct.productId, - selectedEventData.data.modelUuid - ) ?? null +
+ {currentEventData && ( + <> +
+
+ {selectedEventData?.data.modelName} +
+
+ {assetType === "conveyor" && } + {assetType === "vehicle" && } + {assetType === "roboticArm" && } + {assetType === "machine" && } + {assetType === "storageUnit" && } + + )} + {!currentEventData && selectedEventSphere && ( +
+

+ Oops! It looks like this object doesn't have an + event assigned yet. To continue, please link it to one of the + products below. +

+ +
+

+ Here are some products you can add it to: +

+
    + {products.map((product) => ( +
  • + +
  • + ))} +
+
+
+ ) + } + {!selectedEventSphere && ( +
+

+ Oops! It looks like you haven't selected an event + point yet. Please select an event to view its properties. +

+
+ )} +
); - }; - - const determineAssetType = (event: EventsSchema | null) => { - if (!event) return null; - - switch (event.type) { - case "transfer": - return "conveyor"; - case "vehicle": - return "vehicle"; - case "roboticArm": - return "roboticArm"; - case "machine": - return "machine"; - case "storageUnit": - return "storageUnit"; - default: - return null; - } - }; - - return ( -
- {currentEventData && ( - <> -
-
- {selectedEventData?.data.modelName} -
-
- {assetType === "conveyor" && } - {assetType === "vehicle" && } - {assetType === "roboticArm" && } - {assetType === "machine" && } - {assetType === "storageUnit" && } - - )} - {!currentEventData && selectedEventSphere && ( -
-

- Oops! It looks like this object doesn't have an - event assigned yet. To continue, please link it to one of the - products below. -

- -
-

- Here are some products you can add it to: -

-
    - {products.map((product) => ( -
  • - -
  • - ))} -
-
-
- )} - {!selectedEventSphere && ( -
-

- Oops! It looks like you haven't selected an event - point yet. Please select an event to view its properties. -

-
- )} -
- ); }; export default EventProperties; 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 6d2c3de..09017de 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx @@ -1,202 +1,149 @@ import React, { useRef } from "react"; import { - AddIcon, - RemoveIcon, - ResizeHeightIcon, + AddIcon, + RemoveIcon, + ResizeHeightIcon, } from "../../../../../icons/ExportCommonIcons"; import RenameInput from "../../../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../../../functions/handleResizePannel"; -import { - useSelectedAction, - useSelectedEventData, - useSelectedProduct, -} from "../../../../../../store/simulation/useSimulationStore"; -import { MathUtils } from "three"; +import { useSelectedAction, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; +import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi"; interface ActionsListProps { - setSelectedPointData: (data: any) => void; // You can replace `any` with a more specific type if you have one - selectedPointData: any; // You can replace `any` with a more specific type if you have one - // ui control props - multipleAction?: boolean; + selectedPointData: any; + multipleAction?: boolean; + handleAddAction?: () => void; + handleDeleteAction?: (actionUuid: string) => void; } const ActionsList: React.FC = ({ - setSelectedPointData, - selectedPointData, - multipleAction = false, + selectedPointData, + multipleAction = false, + handleAddAction, + handleDeleteAction, }) => { - const actionsContainerRef = useRef(null); + const actionsContainerRef = useRef(null); - // store - const { selectedEventData } = useSelectedEventData(); - const { updateAction, addAction, removeAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); - const { selectedAction, setSelectedAction, clearSelectedAction } = - useSelectedAction(); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; - const handleAddAction = () => { - if (!selectedEventData || !selectedPointData) return; + // store + const { renameAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + const { selectedAction, setSelectedAction } = useSelectedAction(); - const newAction = { - actionUuid: MathUtils.generateUUID(), - actionName: `Action ${selectedPointData.actions.length + 1}`, - actionType: "pickAndPlace" as const, - process: { - startPoint: null, - endPoint: null, - }, - triggers: [] as TriggerSchema[], + const handleRenameAction = (newName: string) => { + if (!selectedAction.actionId) return; + const event = renameAction(selectedAction.actionId, newName); + + if (event) { + upsertProductOrEventApi({ + productName: selectedProduct.productName, + productId: selectedProduct.productId, + organization: organization, + eventDatas: event + }) + } }; - addAction( - selectedProduct.productId, - selectedEventData.data.modelUuid, - selectedEventData.selectedPoint, - newAction - ); - - const updatedPoint = { - ...selectedPointData, - actions: [...selectedPointData.actions, newAction], + const handleActionSelect = (actionUuid: string, actionName: string) => { + setSelectedAction(actionUuid, actionName); }; - setSelectedPointData(updatedPoint); - setSelectedAction(newAction.actionUuid, newAction.actionName); - }; - const handleDeleteAction = (actionUuid: string) => { - if (!selectedPointData) return; + return ( +
+
+
+
Actions
- removeAction(actionUuid); - const newActions = selectedPointData.actions.filter( - (a: any) => a.actionUuid !== actionUuid - ); - - const updatedPoint = { - ...selectedPointData, - actions: newActions, - }; - setSelectedPointData(updatedPoint); - - if (selectedAction.actionId === actionUuid) { - if (newActions.length > 0) { - setSelectedAction(newActions[0].actionUuid, newActions[0].actionName); - } else { - clearSelectedAction(); - } - } - }; - - const handleRenameAction = (newName: string) => { - if (!selectedAction.actionId) return; - updateAction(selectedAction.actionId, { actionName: newName }); - - if (selectedPointData?.actions) { - const updatedActions = selectedPointData.actions.map((action: any) => - action.actionUuid === selectedAction.actionId - ? { ...action, actionName: newName } - : action - ); - setSelectedPointData({ - ...selectedPointData, - actions: updatedActions, - }); - } else { - // write logic for single action - return; - } - }; - - const handleActionSelect = (actionUuid: string, actionName: string) => { - setSelectedAction(actionUuid, actionName); - }; - - return ( -
-
-
-
Actions
- - -
-
-
- {multipleAction && - selectedPointData.actions.map((action: any) => ( -
- - {selectedPointData.actions.length > 1 && ( - )}
- ))} - {!multipleAction && selectedPointData && ( -
- -
- )} -
- {multipleAction && ( - - )} +
+ {multipleAction && selectedPointData && + selectedPointData.actions.map((action: any) => ( +
+ + {selectedPointData.actions.length > 1 && ( + + )} +
+ ))} + {!multipleAction && selectedPointData && ( +
+ +
+ )} +
+ {multipleAction && ( + + )} +
+
-
-
- ); + ); }; export default ActionsList; 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 7a0bc07..f68b6b8 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -8,218 +8,274 @@ import SwapAction from "../actions/SwapAction"; import SpawnAction from "../actions/SpawnAction"; import DefaultAction from "../actions/DefaultAction"; import Trigger from "../trigger/Trigger"; -import { - useSelectedEventData, - useSelectedProduct, -} from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import ActionsList from "../components/ActionsList"; +import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi"; function ConveyorMechanics() { - const [activeOption, setActiveOption] = useState< - "default" | "spawn" | "swap" | "delay" | "despawn" - >("default"); - const [selectedPointData, setSelectedPointData] = useState< - ConveyorPointSchema | undefined - >(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateEvent, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint - ) as ConveyorPointSchema | undefined; - if (point && "action" in point) { - setSelectedPointData(point); - setActiveOption( - point.action.actionType as - | "default" - | "spawn" - | "swap" - | "delay" - | "despawn" - ); - } + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as ConveyorPointSchema | undefined; + if (point && "action" in point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as | "default" | "spawn" | "swap" | "delay" | "despawn"); + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); + + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData + }) } - }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleSpeedChange = (value: string) => { - if (!selectedEventData) return; - updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { - speed: parseFloat(value), - }); - }; + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + const event = updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { + speed: parseFloat(value), + }); - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as - | "default" - | "spawn" - | "swap" - | "delay" - | "despawn"; - setActiveOption(validOption); + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + }; - updateAction(selectedPointData.action.actionUuid, { - actionType: validOption, - }); - }; + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as | "default" | "spawn" | "swap" | "delay" | "despawn"; + setActiveOption(validOption); - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { actionName: newName }); - }; + const event = updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); - const handleSpawnCountChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - spawnCount: value === "inherit" ? "inherit" : parseFloat(value), - }); - }; + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + }; - const handleSpawnIntervalChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - spawnInterval: value === "inherit" ? "inherit" : parseFloat(value), - }); - }; + const handleRenameAction = (newName: string) => { + if (!selectedEventData || !selectedPointData) return; + const event = updateAction(selectedPointData.action.actionUuid, { actionName: newName }); - const handleMaterialSelect = (material: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { material }); - }; + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + }; - const handleDelayChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - delay: value === "inherit" ? "inherit" : parseFloat(value), - }); - }; + const handleSpawnCountChange = (value: string) => { + if (!selectedEventData || !selectedPointData) return; + const event = updateAction(selectedPointData.action.actionUuid, { + spawnCount: value === "inherit" ? "inherit" : parseFloat(value), + }); - const availableActions = { - defaultOption: "default", - options: ["default", "spawn", "swap", "delay", "despawn"], - }; + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + }; - // Get current values from store - const currentSpeed = - selectedEventData?.data.type === "transfer" - ? selectedEventData.data.speed.toString() - : "0.5"; + const handleSpawnIntervalChange = (value: string) => { + if (!selectedEventData || !selectedPointData) return; + const event = updateAction(selectedPointData.action.actionUuid, { + spawnInterval: value === "inherit" ? "inherit" : parseFloat(value), + }); - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + }; - const currentMaterial = selectedPointData - ? selectedPointData.action.material - : "Default material"; + const handleMaterialSelect = (material: string) => { + if (!selectedEventData || !selectedPointData) return; + const event = updateAction(selectedPointData.action.actionUuid, { material }); - const currentSpawnCount = selectedPointData - ? selectedPointData.action.spawnCount?.toString() || "1" - : "1"; + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + }; - const currentSpawnInterval = selectedPointData - ? selectedPointData.action.spawnInterval?.toString() || "1" - : "1"; + const handleDelayChange = (value: string) => { + if (!selectedEventData || !selectedPointData) return; + const event = updateAction(selectedPointData.action.actionUuid, { + delay: value === "inherit" ? "inherit" : parseFloat(value), + }); - const currentDelay = selectedPointData - ? selectedPointData.action.delay?.toString() || "0" - : "0"; + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + }; - return ( - <> - {selectedEventData && ( + const availableActions = { + defaultOption: "default", + options: ["default", "spawn", "swap", "delay", "despawn"], + }; + + // Get current values from store + const currentSpeed = (getEventByModelUuid( + selectedProduct.productId, selectedEventData?.data.modelUuid || "" + ) as ConveyorEventSchema | undefined)?.speed?.toString() || "0.5"; + + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; + + const currentMaterial = selectedPointData + ? selectedPointData.action.material + : "Default material"; + + const currentSpawnCount = selectedPointData + ? selectedPointData.action.spawnCount?.toString() || "1" + : "1"; + + const currentSpawnInterval = selectedPointData + ? selectedPointData.action.spawnInterval?.toString() || "1" + : "1"; + + const currentDelay = selectedPointData + ? selectedPointData.action.delay?.toString() || "0" + : "0"; + + return ( <> -
-
-
- {}} - onChange={handleSpeedChange} - /> -
+
+
+
+ { }} + onChange={handleSpeedChange} + /> +
+
-
-
- +
+ -
-
- -
-
- - {activeOption === "default" && } - {activeOption === "spawn" && ( - - )} - {activeOption === "swap" && ( - - )} - {activeOption === "despawn" && } - {activeOption === "delay" && ( - - )} -
-
-
- -
-
+
+
+ +
+
+ + {activeOption === "default" && } + {activeOption === "spawn" && ( + + )} + {activeOption === "swap" && ( + + )} + {activeOption === "despawn" && } + {activeOption === "delay" && ( + + )} +
+
+
+ +
+
- )} - - ); + ); } export default 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 db785da..993c46b 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -2,128 +2,120 @@ import { useEffect, useState } from "react"; import RenameInput from "../../../../../ui/inputs/RenameInput"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import Trigger from "../trigger/Trigger"; -import { - useSelectedEventData, - useSelectedProduct, -} from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import ProcessAction from "../actions/ProcessAction"; import ActionsList from "../components/ActionsList"; function MachineMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "process">( - "default" - ); - const [selectedPointData, setSelectedPointData] = useState< - MachinePointSchema | undefined - >(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState<"default" | "process">("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint - ) as MachinePointSchema | undefined; - if (point && "action" in point) { - setSelectedPointData(point); - setActiveOption(point.action.actionType as "process"); - } - } - }, [selectedProduct, selectedEventData, getPointByUuid]); + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as MachinePointSchema | undefined; + if (point && "action" in point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "process"); + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as "process"; - setActiveOption(validOption); + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "process"; + setActiveOption(validOption); - updateAction(selectedPointData.action.actionUuid, { - actionType: validOption, - }); - }; + updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); + }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { actionName: newName }); - }; + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + }; - const handleProcessTimeChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - processTime: parseFloat(value), - }); - }; + const handleProcessTimeChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + processTime: parseFloat(value), + }); + }; - const handleMaterialSelect = (material: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - swapMaterial: material, - }); - }; + const handleMaterialSelect = (material: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + swapMaterial: material, + }); + }; - // Get current values from store - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + // Get current values from store + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; - const currentProcessTime = selectedPointData - ? selectedPointData.action.processTime.toString() - : "1"; + const currentProcessTime = selectedPointData + ? selectedPointData.action.processTime.toString() + : "1"; - const currentMaterial = selectedPointData - ? selectedPointData.action.swapMaterial - : "Default material"; + const currentMaterial = selectedPointData + ? selectedPointData.action.swapMaterial + : "Default material"; - const availableActions = { - defaultOption: "process", - options: ["process"], - }; + const availableActions = { + defaultOption: "process", + options: ["process"], + }; - return ( - <> - {selectedEventData && ( -
-
-
- -
- -
- - {activeOption === "process" && ( - - )} -
-
-
- -
-
- )} - - ); + return ( + <> + {selectedEventData && ( +
+
+
+ +
+ +
+ + {activeOption === "process" && ( + + )} +
+
+
+ +
+
+ )} + + ); } export default MachineMechanics; 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 acf65ae..e56741f 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -1,195 +1,292 @@ import { useEffect, useState } from "react"; +import { MathUtils } from "three"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; import RenameInput from "../../../../../ui/inputs/RenameInput"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import Trigger from "../trigger/Trigger"; -import { - useSelectedEventData, - useSelectedProduct, - useSelectedAction, -} from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedEventData, useSelectedProduct, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import PickAndPlaceAction from "../actions/PickAndPlaceAction"; import ActionsList from "../components/ActionsList"; +import { upsertProductOrEventApi } from "../../../../../../services/simulation/UpsertProductOrEventApi"; function RoboticArmMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">( - "default" - ); - const [selectedPointData, setSelectedPointData] = useState< - RoboticArmPointSchema | undefined - >(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateEvent, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); - const { selectedAction, setSelectedAction, clearSelectedAction } = - useSelectedAction(); + const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction, addAction, removeAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData.data.modelUuid, - selectedEventData.selectedPoint - ) as RoboticArmPointSchema | undefined; - if (point?.actions) { - setSelectedPointData(point); - setActiveOption( - point.actions[0].actionType as "default" | "pickAndPlace" - ); - if (point.actions.length > 0 && !selectedAction.actionId) { - setSelectedAction( - point.actions[0].actionUuid, - point.actions[0].actionName - ); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint + ) as RoboticArmPointSchema | undefined; + if (point?.actions) { + setSelectedPointData(point); + setActiveOption(point.actions[0].actionType as "default" | "pickAndPlace"); + if (point.actions.length > 0 && !selectedAction.actionId) { + setSelectedAction( + point.actions[0].actionUuid, + point.actions[0].actionName + ); + } + } + } else { + clearSelectedAction(); } - } - } else { - clearSelectedAction(); + }, [clearSelectedAction, getPointByUuid, selectedAction.actionId, selectedEventData, selectedProduct, setSelectedAction,]); + + const updateBackend = ( + productName: string, + productId: string, + organization: string, + eventData: EventsSchema + ) => { + upsertProductOrEventApi({ + productName: productName, + productId: productId, + organization: organization, + eventDatas: eventData + }) } - }, [ - clearSelectedAction, - getPointByUuid, - selectedAction.actionId, - selectedEventData, - selectedProduct, - setSelectedAction, - ]); - const handleRenameAction = (newName: string) => { - if (!selectedAction.actionId) return; - updateAction(selectedAction.actionId, { actionName: newName }); + const handleRenameAction = (newName: string) => { + if (!selectedAction.actionId) return; + const event = updateAction(selectedAction.actionId, { actionName: newName }); - if (selectedPointData) { - const updatedActions = selectedPointData.actions.map((action) => - action.actionUuid === selectedAction.actionId - ? { ...action, actionName: newName } - : action - ); - setSelectedPointData({ - ...selectedPointData, - actions: updatedActions, - }); - } - }; + if (selectedPointData) { + const updatedActions = selectedPointData.actions.map((action) => + action.actionUuid === selectedAction.actionId ? { ...action, actionName: newName } : action + ); + setSelectedPointData({ + ...selectedPointData, + actions: updatedActions, + }); + } - const handleSpeedChange = (value: string) => { - if (!selectedEventData) return; - updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { - speed: parseFloat(value), - }); - }; + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + }; - const handlePickPointChange = (value: string) => { - if (!selectedAction.actionId || !selectedPointData) return; - const [x, y, z] = value.split(",").map(Number); + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + const event = updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { + speed: parseFloat(value), + }); - updateAction(selectedAction.actionId, { - process: { - startPoint: [x, y, z] as [number, number, number], - endPoint: - selectedPointData.actions.find( - (a) => a.actionUuid === selectedAction.actionId - )?.process.endPoint || null, - }, - }); - }; + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + }; - const handlePlacePointChange = (value: string) => { - if (!selectedAction.actionId || !selectedPointData) return; - const [x, y, z] = value.split(",").map(Number); + const handlePickPointChange = (value: string) => { + if (!selectedAction.actionId || !selectedPointData) return; + const [x, y, z] = value.split(",").map(Number); - updateAction(selectedAction.actionId, { - process: { - startPoint: - selectedPointData.actions.find( - (a) => a.actionUuid === selectedAction.actionId - )?.process.startPoint || null, - endPoint: [x, y, z] as [number, number, number], - }, - }); - }; + const event = updateAction(selectedAction.actionId, { + process: { + startPoint: [x, y, z] as [number, number, number], + endPoint: selectedPointData.actions.find((a) => a.actionUuid === selectedAction.actionId)?.process.endPoint || null, + }, + }); - const availableActions = { - defaultOption: "pickAndPlace", - options: ["pickAndPlace"], - }; + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + }; - const currentSpeed = - selectedEventData?.data.type === "roboticArm" - ? selectedEventData.data.speed.toString() - : "0.5"; + const handlePlacePointChange = (value: string) => { + if (!selectedAction.actionId || !selectedPointData) return; + const [x, y, z] = value.split(",").map(Number); - const currentAction = selectedPointData?.actions.find( - (a) => a.actionUuid === selectedAction.actionId - ); - const currentPickPoint = currentAction?.process.startPoint - ? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}` - : ""; - const currentPlacePoint = currentAction?.process.endPoint - ? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}` - : ""; + const event = updateAction(selectedAction.actionId, { + process: { + startPoint: selectedPointData.actions.find((a) => a.actionUuid === selectedAction.actionId)?.process.startPoint || null, + endPoint: [x, y, z] as [number, number, number], + }, + }); - return ( - <> - {selectedEventData && selectedPointData && ( + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + }; + + + const handleAddAction = () => { + if (!selectedEventData || !selectedPointData) return; + + const newAction = { + actionUuid: MathUtils.generateUUID(), + actionName: `Action ${selectedPointData.actions.length + 1}`, + actionType: "pickAndPlace" as const, + process: { + startPoint: null, + endPoint: null, + }, + triggers: [] as TriggerSchema[], + }; + + const event = addAction( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint, + newAction + ); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + + const updatedPoint = { + ...selectedPointData, + actions: [...selectedPointData.actions, newAction], + }; + setSelectedPointData(updatedPoint); + setSelectedAction(newAction.actionUuid, newAction.actionName); + }; + + const handleDeleteAction = (actionUuid: string) => { + if (!selectedPointData) return; + + const event = removeAction(actionUuid); + + if (event) { + updateBackend( + selectedProduct.productName, + selectedProduct.productId, + organization, + event + ); + } + + const newActions = selectedPointData.actions.filter( + (a: any) => a.actionUuid !== actionUuid + ); + + const updatedPoint = { + ...selectedPointData, + actions: newActions, + }; + setSelectedPointData(updatedPoint); + + if (selectedAction.actionId === actionUuid) { + if (newActions.length > 0) { + setSelectedAction(newActions[0].actionUuid, newActions[0].actionName); + } else { + clearSelectedAction(); + } + } + }; + + const availableActions = { + defaultOption: "pickAndPlace", + options: ["pickAndPlace"], + }; + + const currentSpeed = (getEventByModelUuid( + selectedProduct.productId, selectedEventData?.data.modelUuid || "" + ) as RoboticArmEventSchema | undefined)?.speed?.toString() || "0.5"; + + const currentAction = selectedPointData?.actions.find((a) => a.actionUuid === selectedAction.actionId); + + const currentPickPoint = currentAction?.process.startPoint + ? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}` + : ""; + const currentPlacePoint = currentAction?.process.endPoint + ? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}` + : ""; + + return ( <> -
-
-
- {}} - onChange={handleSpeedChange} - /> -
+
+
+
+ { }} + onChange={handleSpeedChange} + /> +
+
-
-
- +
- {selectedAction.actionId && currentAction && ( -
-
- -
-
- {}} - disabled={true} - /> - -
-
- -
-
- )} -
+ + + {selectedAction.actionId && currentAction && ( +
+
+ +
+
+ { }} + disabled={true} + /> + +
+
+ +
+
+ )} +
- )} - - ); + ); } export default RoboticArmMechanics; 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 ae7a498..c85da9f 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -2,119 +2,111 @@ import { useEffect, useState } from "react"; import RenameInput from "../../../../../ui/inputs/RenameInput"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import Trigger from "../trigger/Trigger"; -import { - useSelectedEventData, - useSelectedProduct, -} from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import StorageAction from "../actions/StorageAction"; import ActionsList from "../components/ActionsList"; function StorageMechanics() { - const [activeOption, setActiveOption] = useState< - "default" | "store" | "spawn" - >("default"); - const [selectedPointData, setSelectedPointData] = useState< - StoragePointSchema | undefined - >(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint - ) as StoragePointSchema | undefined; - if (point && "action" in point) { - setSelectedPointData(point); - setActiveOption(point.action.actionType as "store" | "spawn"); - } - } - }, [selectedProduct, selectedEventData, getPointByUuid]); + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as StoragePointSchema | undefined; + if (point && "action" in point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "store" | "spawn"); + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as "store" | "spawn"; - setActiveOption(validOption); + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "store" | "spawn"; + setActiveOption(validOption); - updateAction(selectedPointData.action.actionUuid, { - actionType: validOption, - }); - }; + updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); + }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { actionName: newName }); - }; + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + }; - const handleCapacityChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - storageCapacity: parseInt(value), - }); - }; + const handleCapacityChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + storageCapacity: parseInt(value), + }); + }; - // Get current values from store - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + // Get current values from store + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; - const currentCapacity = selectedPointData - ? selectedPointData.action.storageCapacity.toString() - : "0"; + const currentCapacity = selectedPointData + ? selectedPointData.action.storageCapacity.toString() + : "0"; - const availableActions = { - defaultOption: "store", - options: ["store", "spawn"], - }; + const availableActions = { + defaultOption: "store", + options: ["store", "spawn"], + }; - return ( - <> - {selectedEventData && ( -
- -
-
- -
-
- - {activeOption === "store" && ( - - )} - {activeOption === "spawn" && ( -
-

Spawn configuration options would go here

-
- )} -
-
-
- -
-
- )} - - ); + return ( + <> + {selectedEventData && ( +
+ +
+
+ +
+
+ + {activeOption === "store" && ( + + )} + {activeOption === "spawn" && ( +
+

Spawn configuration options would go here

+
+ )} +
+
+
+ +
+
+ )} + + ); } export default StorageMechanics; 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 d8456e5..28eb61f 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -4,186 +4,181 @@ import RenameInput from "../../../../../ui/inputs/RenameInput"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import Trigger from "../trigger/Trigger"; import { - useSelectedEventData, - useSelectedProduct, + useSelectedEventData, + useSelectedProduct, } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import TravelAction from "../actions/TravelAction"; import ActionsList from "../components/ActionsList"; function VehicleMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "travel">( - "default" - ); - const [selectedPointData, setSelectedPointData] = useState< - VehiclePointSchema | undefined - >(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateEvent, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState<"default" | "travel">("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData.data.modelUuid, - selectedEventData.selectedPoint - ) as VehiclePointSchema | undefined; + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint + ) as VehiclePointSchema | undefined; - if (point) { - setSelectedPointData(point); - setActiveOption(point.action.actionType as "travel"); - } - } - }, [selectedProduct, selectedEventData, getPointByUuid]); + if (point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "travel"); + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleSpeedChange = (value: string) => { - if (!selectedEventData) return; - updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { - speed: parseFloat(value), - }); - }; + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { + speed: parseFloat(value), + }); + }; - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as "travel"; - setActiveOption(validOption); + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "travel"; + setActiveOption(validOption); - updateAction(selectedPointData.action.actionUuid, { - actionType: validOption, - }); - }; + updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); + }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { actionName: newName }); - }; + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + }; - const handleLoadCapacityChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - loadCapacity: parseFloat(value), - }); - }; + const handleLoadCapacityChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + loadCapacity: parseFloat(value), + }); + }; - const handleUnloadDurationChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - unLoadDuration: parseFloat(value), - }); - }; + const handleUnloadDurationChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + unLoadDuration: parseFloat(value), + }); + }; - const handlePickPointChange = (value: string) => { - if (!selectedPointData) return; - }; + const handlePickPointChange = (value: string) => { + if (!selectedPointData) return; + }; - const handleUnloadPointChange = (value: string) => { - if (!selectedPointData) return; - }; + const handleUnloadPointChange = (value: string) => { + if (!selectedPointData) return; + }; - // Get current values from store - const currentSpeed = - selectedEventData?.data.type === "vehicle" - ? selectedEventData.data.speed.toString() - : "0.5"; + // Get current values from store - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + const currentSpeed = (getEventByModelUuid( + selectedProduct.productId, selectedEventData?.data.modelUuid || "" + ) as VehicleEventSchema | undefined)?.speed?.toString() || "0.5"; - const currentLoadCapacity = selectedPointData - ? selectedPointData.action.loadCapacity.toString() - : "1"; + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; - const currentUnloadDuration = selectedPointData - ? selectedPointData.action.unLoadDuration.toString() - : "1"; + const currentLoadCapacity = selectedPointData + ? selectedPointData.action.loadCapacity.toString() + : "1"; - const currentPickPoint = selectedPointData?.action.pickUpPoint; + const currentUnloadDuration = selectedPointData + ? selectedPointData.action.unLoadDuration.toString() + : "1"; - const currentUnloadPoint = selectedPointData?.action.unLoadPoint; + const currentPickPoint = selectedPointData?.action.pickUpPoint; - const availableActions = { - defaultOption: "travel", - options: ["travel"], - }; + const currentUnloadPoint = selectedPointData?.action.unLoadPoint; - return ( - <> - {selectedEventData && ( + const availableActions = { + defaultOption: "travel", + options: ["travel"], + }; + + return ( <> -
-
-
- {}} - onChange={handleSpeedChange} - /> -
-
-
-
- -
-
- -
-
- + {selectedEventData && ( + <> +
+
+
+ { }} + onChange={handleSpeedChange} + /> +
+
+
+
+ +
+
+ +
+
+ - {activeOption === "travel" && ( - - )} -
-
-
- -
-
+ {activeOption === "travel" && ( + + )} +
+
+
+ +
+
+ + )} - )} - - ); + ); } export default VehicleMechanics; 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..1434446 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx @@ -91,44 +91,42 @@ const Trigger: React.FC = () => {
{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); - }} - /> -
+ { + const newModel = [...triggeredModel]; + newModel[0] = option; + setTriggeredModel(newModel); + }} + /> + { + const newPoint = [...triggeredPoint]; + newPoint[0] = option; + setTriggeredPoint(newPoint); + }} + /> + { + const newAction = [...triggeredAction]; + newAction[0] = option; + setTriggeredAction(newAction); + }} + />
diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index a8957d1..1280693 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -1,220 +1,227 @@ import React, { useEffect, useRef, useState } from "react"; import { - AddIcon, - ArrowIcon, - RemoveIcon, - ResizeHeightIcon, + AddIcon, + ArrowIcon, + RemoveIcon, + ResizeHeightIcon, } from "../../../icons/ExportCommonIcons"; import RenameInput from "../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../functions/handleResizePannel"; import { - useSelectedAsset, - useSelectedProduct, + useSelectedAsset, + useSelectedProduct, } from "../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { generateUUID } from "three/src/math/MathUtils"; import RenderOverlay from "../../../templates/Overlay"; import EditWidgetOption from "../../../ui/menu/EditWidgetOption"; -import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi"; import { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { deleteEventDataApi } from "../../../../services/simulation/deleteEventDataApi"; +import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi"; +import { deleteProductApi } from "../../../../services/simulation/deleteProductApi"; interface Event { - pathName: string; + pathName: string; } interface ListProps { - val: Event; + val: Event; } const List: React.FC = ({ val }) => { - return ( -
-
{val.pathName}
-
- ); + return ( +
+
{val.pathName}
+
+ ); }; const Simulations: React.FC = () => { - const productsContainerRef = useRef(null); - const { - products, - addProduct, - removeProduct, - renameProduct, - addEvent, - removeEvent, - } = useProductStore(); - const { selectedProduct, setSelectedProduct } = useSelectedProduct(); - const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); + const productsContainerRef = useRef(null); + const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent, } = useProductStore(); + const { selectedProduct, setSelectedProduct } = useSelectedProduct(); + const { getEventByModelUuid } = useEventsStore(); + const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + const [openObjects, setOpenObjects] = useState(true); - const [openObjects, setOpenObjects] = useState(true); + const handleAddProduct = () => { + const id = generateUUID(); + const name = `Product ${products.length + 1}`; + addProduct(name, id); + upsertProductOrEventApi({ productName: name, productId: id, organization: organization }); + }; - const handleAddProduct = () => { - addProduct(`Product ${products.length + 1}`, generateUUID()); - }; + const handleRemoveProduct = (productId: string) => { + const currentIndex = products.findIndex((p) => p.productId === productId); + const isSelected = selectedProduct.productId === productId; - const handleRemoveProduct = (productId: string) => { - const currentIndex = products.findIndex((p) => p.productId === productId); - const isSelected = selectedProduct.productId === productId; + const updatedProducts = products.filter((p) => p.productId !== productId); - const updatedProducts = products.filter((p) => p.productId !== productId); - - if (isSelected) { - if (updatedProducts.length > 0) { - let newSelectedIndex = currentIndex; - if (currentIndex >= updatedProducts.length) { - newSelectedIndex = updatedProducts.length - 1; + if (isSelected) { + if (updatedProducts.length > 0) { + let newSelectedIndex = currentIndex; + if (currentIndex >= updatedProducts.length) { + newSelectedIndex = updatedProducts.length - 1; + } + setSelectedProduct( + updatedProducts[newSelectedIndex].productId, + updatedProducts[newSelectedIndex].productName + ); + } else { + setSelectedProduct("", ""); + } } - setSelectedProduct( - updatedProducts[newSelectedIndex].productId, - updatedProducts[newSelectedIndex].productName - ); - } else { - setSelectedProduct("", ""); - } - } - removeProduct(productId); - }; + removeProduct(productId); + deleteProductApi(productId, organization); + }; - const handleRenameProduct = (productId: string, newName: string) => { - renameProduct(productId, newName); - if (selectedProduct.productId === productId) { - setSelectedProduct(productId, newName); - } - }; + const handleRenameProduct = (productId: string, newName: string) => { + renameProduct(productId, newName); + if (selectedProduct.productId === productId) { + setSelectedProduct(productId, newName); + } + }; - const handleRemoveEventFromProduct = () => { - if (selectedAsset) { - removeEvent(selectedProduct.productId, selectedAsset.modelUuid); - clearSelectedAsset(); - } - }; + const handleRemoveEventFromProduct = () => { + if (selectedAsset) { + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + deleteEventDataApi({ + productId: selectedProduct.productId, + modelUuid: selectedAsset.modelUuid, + organization: organization + }); + removeEvent(selectedProduct.productId, selectedAsset.modelUuid); + clearSelectedAsset(); + } + }; - const selectedProductData = products.find( - (product) => product.productId === selectedProduct.productId - ); + const selectedProductData = products.find( + (product) => product.productId === selectedProduct.productId + ); - const events: Event[] = - selectedProductData?.eventDatas.map((event) => ({ - pathName: event.modelName, + const events: Event[] = selectedProductData?.eventDatas.map((event) => ({ + pathName: event.modelName, })) || []; - return ( -
-
Simulations
-
-
-
-
Products
-
- Add -
-
-
-
- {products.map((product, index) => ( -
-
- setSelectedProduct(product.productId, product.productName) - } - > - - - handleRenameProduct(product.productId, newName) - } - /> -
- {products.length > 1 && ( -
handleRemoveProduct(product.productId)} - > - + return ( +
+
Simulations
+
+
+
+
Products
+
+ Add +
+
+
+
+ {products.map((product, index) => ( +
+
+ setSelectedProduct(product.productId, product.productName) + } + > + + + handleRenameProduct(product.productId, newName) + } + /> +
+ {products.length > 1 && ( +
handleRemoveProduct(product.productId)} + > + +
+ )} +
+ ))} +
+
handleResize(e, productsContainerRef)} + > + +
- )}
- ))} -
-
handleResize(e, productsContainerRef)} - > - -
-
-
-
- + {openObjects && + events.map((event, index) => )} +
+ +
+
+ Need to Compare Layout? +
+
+ Click 'Compare' to review and analyze the layout + differences between them. +
+
+ +
+
- - {openObjects && - events.map((event, index) => )} -
-
-
- Need to Compare Layout? -
-
- Click 'Compare' to review and analyze the layout - differences between them. -
-
- -
+ {selectedAsset && ( + + { + if (option === "Add to Product") { + handleAddEventToProduct({ + event: getEventByModelUuid(selectedAsset.modelUuid), + addEvent, + selectedProduct, + clearSelectedAsset + }); + } else { + handleRemoveEventFromProduct(); + } + }} + /> + + )}
-
- - {selectedAsset && ( - - { - if (option === "Add to Product") { - handleAddEventToProduct({ - selectedAsset, - addEvent, - selectedProduct, - clearSelectedAsset, - }); - } else { - handleRemoveEventFromProduct(); - } - }} - /> - - )} -
- ); + ) }; export default Simulations; 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/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index 0416a9e..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, + 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 06419af..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,16 +123,20 @@ 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 - ? { ...floorItems, modelname: response.modelname } + floorItems.modelUuid === zoneAssetId.id + ? { ...floorItems, modelName: response.modelName } : floorItems ) ); @@ -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 (
    { // Button functions const handleReset = () => { setReset(true); + // setReset(!isReset); setSpeed(1); }; const handlePlayStop = () => { @@ -120,7 +121,7 @@ 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); @@ -294,7 +295,7 @@ const SimulationPlayer: React.FC = () => { Speed
    -
    0X
    +
    0.5X
    diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index c46c0e7..a351d73 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -72,7 +72,7 @@ async function loadInitialFloorItems( // Check Three.js Cache const cachedModel = THREE.Cache.get(item.modelfileID!); if (cachedModel) { - // console.log(`[Cache] Fetching ${item.modelname}`); + // console.log(`[Cache] Fetching ${item.modelName}`); processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, addEvent); modelsLoaded++; checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); @@ -82,7 +82,7 @@ async function loadInitialFloorItems( // Check IndexedDB const indexedDBModel = await retrieveGLTF(item.modelfileID!); if (indexedDBModel) { - // console.log(`[IndexedDB] Fetching ${item.modelname}`); + // console.log(`[IndexedDB] Fetching ${item.modelName}`); const blobUrl = URL.createObjectURL(indexedDBModel); loader.load(blobUrl, (gltf) => { URL.revokeObjectURL(blobUrl); @@ -94,7 +94,7 @@ async function loadInitialFloorItems( }, undefined, (error) => { - toast.error(`[IndexedDB] Error loading ${item.modelname}:`); + toast.error(`[IndexedDB] Error loading ${item.modelName}:`); URL.revokeObjectURL(blobUrl); resolve(); } @@ -103,7 +103,7 @@ async function loadInitialFloorItems( } // Fetch from Backend - // console.log(`[Backend] Fetching ${item.modelname}`); + // console.log(`[Backend] Fetching ${item.modelName}`); const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`; loader.load(modelUrl, async (gltf) => { const modelBlob = await fetch(modelUrl).then((res) => res.blob()); @@ -115,18 +115,18 @@ async function loadInitialFloorItems( }, undefined, (error) => { - toast.error(`[Backend] Error loading ${item.modelname}:`); + toast.error(`[Backend] Error loading ${item.modelName}:`); resolve(); } ); }); } else { - // console.log(`Item ${item.modelname} is not near`); + // console.log(`Item ${item.modelName} is not near`); setFloorItems((prevItems) => [ ...(prevItems || []), { - modeluuid: item.modeluuid, - modelname: item.modelname, + modelUuid: item.modelUuid, + modelName: item.modelName, position: item.position, rotation: item.rotation, modelfileID: item.modelfileID, @@ -154,9 +154,9 @@ function processLoadedModel( addEvent: (event: EventsSchema) => void, ) { const model = gltf.clone(); - model.uuid = item.modeluuid; + model.uuid = item.modelUuid; model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); - model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid }; + model.userData = { name: item.modelName, modelId: item.modelfileID, modelUuid: item.modelUuid, eventData: item.eventData }; model.position.set(...item.position); model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z); @@ -170,256 +170,142 @@ function processLoadedModel( } }); - itemsGroup?.current?.add(model); - setFloorItems((prevItems) => [ - ...(prevItems || []), - { - modeluuid: item.modeluuid, - modelname: item.modelname, - position: item.position, - rotation: item.rotation, - modelfileID: item.modelfileID, - isLocked: item.isLocked, - isVisible: item.isVisible, - }, - ]); + if (item.eventData) { + setFloorItems((prevItems) => [ + ...(prevItems || []), + { + modelUuid: item.modelUuid, + modelName: item.modelName, + position: item.position, + rotation: item.rotation, + modelfileID: item.modelfileID, + isLocked: item.isLocked, + isVisible: item.isVisible, + eventData: item.eventData, + }, + ]); - if (item.modelfileID === "a1ee92554935007b10b3eb05") { - const data = PointsCalculator( - 'Vehicle', - gltf.clone(), - new THREE.Vector3(...model.rotation) - ); - - if (!data || !data.points) return; - - const vehicleEvent: VehicleEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - state: "idle", - type: "vehicle", - speed: 1, - point: { - uuid: THREE.MathUtils.generateUUID(), - position: [data.points[0].x, data.points[0].y, data.points[0].z], - rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Vehicle Action", - actionType: "travel", - unLoadDuration: 5, - loadCapacity: 10, - pickUpPoint: null, - unLoadPoint: null, - triggers: [] - } - } - }; - addEvent(vehicleEvent); - } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { - const data = PointsCalculator( - 'Conveyor', - gltf.clone(), - new THREE.Vector3(...model.rotation) - ); - - if (!data || !data.points) return; - - const ConveyorEvent: ConveyorEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - 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 + 1}`, - actionType: 'default', - material: 'Default material', - delay: 0, - spawnInterval: 5, - spawnCount: 1, - triggers: [] - } - })) - }; - addEvent(ConveyorEvent); - } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { - // const data = PointsCalculator( - // 'Conveyor', - // gltf.clone(), - // new THREE.Vector3(...model.rotation) - // ); - - // if (!data || !data.points) return; - - // const points: ConveyorPointSchema[] = data.points.map((point: THREE.Vector3, index: number) => { - // const actionUuid = THREE.MathUtils.generateUUID(); - // return { - // uuid: THREE.MathUtils.generateUUID(), - // position: [point.x, point.y, point.z], - // rotation: [0, 0, 0], - // action: { - // actionUuid, - // actionName: `Action ${index}`, - // actionType: 'default', - // material: 'inherit', - // delay: 0, - // spawnInterval: 5, - // spawnCount: 1, - // triggers: [] - // } - // }; - // }); - - // points.forEach((point, index) => { - // if (index < points.length - 1) { - // const nextPoint = points[index + 1]; - // point.action.triggers.push({ - // triggerUuid: THREE.MathUtils.generateUUID(), - // triggerName: `Trigger 1`, - // triggerType: "onComplete", - // delay: 0, - // triggeredAsset: { - // triggeredModel: { - // modelName: item.modelname, - // modelUuid: item.modeluuid - // }, - // triggeredPoint: { - // pointName: `Point ${index + 1}`, - // pointUuid: nextPoint.uuid - // }, - // triggeredAction: { - // actionName: nextPoint.action.actionName, - // actionUuid: nextPoint.action.actionUuid - // } - // } - // }); - // } - // }); - - // const ConveyorEvent: ConveyorEventSchema = { - // modelUuid: item.modeluuid, - // modelName: item.modelname, - // position: item.position, - // rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - // state: "idle", - // type: "transfer", - // speed: 1, - // points - // }; - // addEvent(ConveyorEvent); - } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { - const data = PointsCalculator( - 'Conveyor', - gltf.clone(), - new THREE.Vector3(...model.rotation) - ); - - if (!data || !data.points) return; - - const ConveyorEvent: ConveyorEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - 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: 'inherit', - delay: 0, - spawnInterval: 5, - spawnCount: 1, - triggers: [] - } - })) - }; - addEvent(ConveyorEvent); - } else if (item.modelfileID === "29dee78715ad5b853f5c346d") { - const data = PointsCalculator( - 'StaticMachine', - gltf.clone(), - new THREE.Vector3(...model.rotation) - ); - - if (!data || !data.points) return; - - const machineEvent: MachineEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - state: "idle", - type: "machine", - point: { - uuid: THREE.MathUtils.generateUUID(), - position: [data.points[0].x, data.points[0].y, data.points[0].z], - rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Process Action", - actionType: "process", - processTime: 10, - swapMaterial: "material-id", - triggers: [] - } - } - }; - addEvent(machineEvent); - } else if (item.modelfileID === "52e6681fbb743a890d96c914") { - const data = PointsCalculator( - 'ArmBot', - gltf.clone(), - new THREE.Vector3(...model.rotation) - ); - - if (!data || !data.points) return; - - const roboticArmEvent: RoboticArmEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - state: "idle", - type: "roboticArm", - speed: 1, - point: { - uuid: THREE.MathUtils.generateUUID(), - position: [data.points[0].x, data.points[0].y, data.points[0].z], - rotation: [0, 0, 0], - actions: [ - { + if (item.eventData.type === "vehicle") { + const vehicleEvent: VehicleEventSchema = { + modelUuid: item.modelUuid, + modelName: item.modelName, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "vehicle", + speed: 1, + point: { + uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), + position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], + 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: "Pick and Place", - actionType: "pickAndPlace", - process: { - startPoint: [0, 0, 0], - endPoint: [0, 0, 0] - }, + actionName: "Vehicle Action", + actionType: "travel", + unLoadDuration: 5, + loadCapacity: 10, + steeringAngle:0, + pickUpPoint: null, + unLoadPoint: null, triggers: [] } - ] - } - }; - addEvent(roboticArmEvent); + } + }; + addEvent(vehicleEvent); + } else if (item.eventData.type === "Conveyor") { + const ConveyorEvent: ConveyorEventSchema = { + modelUuid: item.modelUuid, + modelName: item.modelName, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "transfer", + speed: 1, + points: item.eventData.points?.map((point: any, index: number) => ({ + uuid: point.uuid || THREE.MathUtils.generateUUID(), + position: [point.position[0], point.position[1], point.position[2]], + rotation: [point.rotation[0], point.rotation[1], point.rotation[2]], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${index + 1}`, + actionType: 'default', + material: 'Default material', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: [] + } + })) || [], + }; + addEvent(ConveyorEvent); + } else if (item.eventData.type === "StaticMachine") { + const machineEvent: MachineEventSchema = { + modelUuid: item.modelUuid, + modelName: item.modelName, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "machine", + point: { + uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), + position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], + 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", + actionType: "process", + processTime: 10, + swapMaterial: "material-id", + triggers: [] + } + } + }; + addEvent(machineEvent); + } else if (item.eventData.type === "ArmBot") { + const roboticArmEvent: RoboticArmEventSchema = { + modelUuid: item.modelUuid, + modelName: item.modelName, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "roboticArm", + speed: 1, + point: { + uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), + position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], + rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Pick and Place", + actionType: "pickAndPlace", + process: { + startPoint: [0, 0, 0], + endPoint: [0, 0, 0] + }, + triggers: [] + } + ] + } + }; + addEvent(roboticArmEvent); + + } + } else { + setFloorItems((prevItems) => [ + ...(prevItems || []), + { + modelUuid: item.modelUuid, + modelName: item.modelName, + position: item.position, + rotation: item.rotation, + modelfileID: item.modelfileID, + isLocked: item.isLocked, + isVisible: item.isVisible, + }, + ]); } gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' }); diff --git a/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts b/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts index 34273af..f9799a8 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts @@ -22,9 +22,9 @@ async function loadInitialWallItems( const loadedWallItems = await Promise.all(storedWallItems.map(async (item) => { const loader = new GLTFLoader(); return new Promise((resolve) => { - loader.load(AssetConfigurations[item.modelname!].modelUrl, (gltf) => { + loader.load(AssetConfigurations[item.modelName!].modelUrl, (gltf) => { const model = gltf.scene; - model.uuid = item.modeluuid!; + model.uuid = item.modelUuid!; model.children[0].children.forEach((child: any) => { if (child.name !== "CSG_REF") { @@ -36,7 +36,7 @@ async function loadInitialWallItems( resolve({ type: item.type, model: model, - modelname: item.modelname, + modelName: item.modelName, scale: item.scale, csgscale: item.csgscale, csgposition: item.csgposition, diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index d7c278c..c718ec3 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -117,7 +117,7 @@ async function handleModelLoad( socket: Socket ) { const model = gltf.scene.clone(); - model.userData = { name: selectedItem.name, modelId: selectedItem.id, modeluuid: model.uuid }; + model.userData = { name: selectedItem.name, modelId: selectedItem.id, modelUuid: model.uuid }; model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); @@ -137,8 +137,8 @@ async function handleModelLoad( } const newFloorItem: Types.FloorItemType = { - modeluuid: model.uuid, - modelname: selectedItem.name, + modelUuid: model.uuid, + modelName: selectedItem.name, modelfileID: selectedItem.id, position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z], rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, @@ -153,8 +153,8 @@ async function handleModelLoad( // await setFloorItemApi( // organization, - // newFloorItem.modeluuid, - // newFloorItem.modelname, + // newFloorItem.modelUuid, + // newFloorItem.modelName, // newFloorItem.modelfileID, // newFloorItem.position, // { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, @@ -164,18 +164,6 @@ async function handleModelLoad( // SOCKET - const data = { - organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, - modelfileID: newFloorItem.modelfileID, - position: newFloorItem.position, - rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, - isLocked: false, - isVisible: true, - socketId: socket.id - }; - if (selectedItem.type) { const data = PointsCalculator( selectedItem.type, @@ -185,10 +173,14 @@ async function handleModelLoad( if (!data || !data.points) return; + const eventData: any = { + type: selectedItem.type, + }; + if (selectedItem.type === "Conveyor") { const ConveyorEvent: ConveyorEventSchema = { - modelUuid: newFloorItem.modeluuid, - modelName: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", @@ -209,12 +201,18 @@ async function handleModelLoad( triggers: [] } })) - } + }; addEvent(ConveyorEvent); + eventData.points = ConveyorEvent.points.map(point => ({ + uuid: point.uuid, + position: point.position, + rotation: point.rotation + })); + } else if (selectedItem.type === "Vehicle") { const vehicleEvent: VehicleEventSchema = { - modelUuid: newFloorItem.modeluuid, - modelName: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", @@ -230,6 +228,7 @@ async function handleModelLoad( actionType: "travel", unLoadDuration: 5, loadCapacity: 10, + steeringAngle:0, pickUpPoint: null, unLoadPoint: null, triggers: [] @@ -237,10 +236,16 @@ async function handleModelLoad( } }; addEvent(vehicleEvent); + eventData.point = { + uuid: vehicleEvent.point.uuid, + position: vehicleEvent.point.position, + rotation: vehicleEvent.point.rotation + }; + } else if (selectedItem.type === "ArmBot") { const roboticArmEvent: RoboticArmEventSchema = { - modelUuid: newFloorItem.modeluuid, - modelName: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", @@ -265,10 +270,16 @@ async function handleModelLoad( } }; addEvent(roboticArmEvent); + eventData.point = { + uuid: roboticArmEvent.point.uuid, + position: roboticArmEvent.point.position, + rotation: roboticArmEvent.point.rotation + }; + } else if (selectedItem.type === "StaticMachine") { const machineEvent: MachineEventSchema = { - modelUuid: newFloorItem.modeluuid, - modelName: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", @@ -288,19 +299,65 @@ async function handleModelLoad( } }; addEvent(machineEvent); + eventData.point = { + uuid: machineEvent.point.uuid, + position: machineEvent.point.position, + rotation: machineEvent.point.rotation + }; } + + const completeData = { + organization, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id, + eventData: eventData + }; + + model.userData.eventData = eventData; + + newFloorItem.eventData = eventData; + + setFloorItems((prevItems) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + socket.emit("v2:model-asset:add", completeData); + + gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); + gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } }); + } else { + + const data = { + organization, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id + }; + + setFloorItems((prevItems) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + socket.emit("v2:model-asset:add", data); + + gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); + gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } }); } - - setFloorItems((prevItems) => { - const updatedItems = [...(prevItems || []), newFloorItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; - }); - - socket.emit("v2:model-asset:add", data); - - gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); - gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } }); } export default addAssetModel; diff --git a/app/src/modules/builder/geomentries/assets/assetManager.ts b/app/src/modules/builder/geomentries/assets/assetManager.ts index 5ff75a3..5f7798e 100644 --- a/app/src/modules/builder/geomentries/assets/assetManager.ts +++ b/app/src/modules/builder/geomentries/assets/assetManager.ts @@ -58,7 +58,7 @@ export default async function assetManager( // Check Three.js Cache const cachedModel = THREE.Cache.get(item.modelfileID!); if (cachedModel) { - // console.log(`[Cache] Fetching ${item.modelname}`); + // console.log(`[Cache] Fetching ${item.modelName}`); processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve); return; } @@ -66,7 +66,7 @@ export default async function assetManager( // Check IndexedDB const indexedDBModel = await retrieveGLTF(item.modelfileID!); if (indexedDBModel) { - // console.log(`[IndexedDB] Fetching ${item.modelname}`); + // console.log(`[IndexedDB] Fetching ${item.modelName}`); const blobUrl = URL.createObjectURL(indexedDBModel); loader.load( blobUrl, @@ -78,7 +78,7 @@ export default async function assetManager( }, undefined, (error) => { - toast.error(`[IndexedDB] Error loading ${item.modelname}:`); + toast.error(`[IndexedDB] Error loading ${item.modelName}:`); resolve(); } ); @@ -86,7 +86,7 @@ export default async function assetManager( } // Fetch from Backend - // console.log(`[Backend] Fetching ${item.modelname}`); + // console.log(`[Backend] Fetching ${item.modelName}`); loader.load( modelUrl, async (gltf) => { @@ -97,7 +97,7 @@ export default async function assetManager( }, undefined, (error) => { - toast.error(`[Backend] Error loading ${item.modelname}:`); + toast.error(`[Backend] Error loading ${item.modelName}:`); resolve(); } ); @@ -112,16 +112,16 @@ export default async function assetManager( ) { if (!activePromises.get(taskId)) return; // Stop processing if task is canceled - const existingModel = itemsGroup?.current?.getObjectByProperty("uuid", item.modeluuid); + const existingModel = itemsGroup?.current?.getObjectByProperty("uuid", item.modelUuid); if (existingModel) { - // console.log(`Model ${item.modelname} already exists in the scene.`); + // console.log(`Model ${item.modelName} already exists in the scene.`); resolve(); return; } const model = gltf; - model.uuid = item.modeluuid; - model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid }; + model.uuid = item.modelUuid; + model.userData = { name: item.modelName, modelId: item.modelfileID, modelUuid: item.modelUuid }; model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); model.position.set(...item.position); model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z); diff --git a/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts b/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts index 18136b3..f13ebee 100644 --- a/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts +++ b/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts @@ -5,6 +5,8 @@ import * as Types from "../../../../types/world/worldTypes"; // import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi'; import { Socket } from 'socket.io-client'; import { getFloorAssets } from '../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi'; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { useProductStore } from "../../../../store/simulation/useProductStore"; async function DeleteFloorItems( itemsGroup: Types.RefGroup, @@ -22,7 +24,7 @@ async function DeleteFloorItems( const items = await getFloorAssets(organization); const removedItem = items.find( - (item: { modeluuid: string }) => item.modeluuid === hoveredDeletableFloorItem.current?.uuid + (item: { modelUuid: string }) => item.modelUuid === hoveredDeletableFloorItem.current?.uuid ); if (!removedItem) { @@ -31,26 +33,29 @@ async function DeleteFloorItems( //REST - // const response = await deleteFloorItem(organization, removedItem.modeluuid, removedItem.modelname); + // const response = await deleteFloorItem(organization, removedItem.modelUuid, removedItem.modelName); //SOCKET const data = { organization: organization, - modeluuid: removedItem.modeluuid, - modelname: removedItem.modelname, + modelUuid: removedItem.modelUuid, + modelName: removedItem.modelName, socketId: socket.id } const response = socket.emit('v2:model-asset:delete', data) + useEventsStore.getState().removeEvent(removedItem.modelUuid); + useProductStore.getState().deleteEvent(removedItem.modelUuid); + if (response) { const updatedItems = items.filter( - (item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid + (item: { modelUuid: string }) => item.modelUuid !== hoveredDeletableFloorItem.current?.uuid ); const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]'); - const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid); + const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => item.modelUuid !== hoveredDeletableFloorItem.current?.uuid); localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); if (hoveredDeletableFloorItem.current) { diff --git a/app/src/modules/builder/geomentries/walls/addWallItems.ts b/app/src/modules/builder/geomentries/walls/addWallItems.ts index 9c578aa..fd9eb48 100644 --- a/app/src/modules/builder/geomentries/walls/addWallItems.ts +++ b/app/src/modules/builder/geomentries/walls/addWallItems.ts @@ -43,7 +43,7 @@ async function AddWallItems( const newWallItem = { type: config.type, model: model, - modelname: selected, + modelName: selected, scale: config.scale, csgscale: config.csgscale, csgposition: config.csgposition, @@ -59,7 +59,7 @@ async function AddWallItems( // await setWallItem( // organization, // model.uuid, - // newWallItem.modelname, + // newWallItem.modelName, // newWallItem.type!, // newWallItem.csgposition!, // newWallItem.csgscale!, @@ -72,8 +72,8 @@ async function AddWallItems( const data = { organization: organization, - modeluuid: model.uuid, - modelname: newWallItem.modelname, + modelUuid: model.uuid, + modelName: newWallItem.modelName, type: newWallItem.type!, csgposition: newWallItem.csgposition!, csgscale: newWallItem.csgscale!, @@ -92,7 +92,7 @@ async function AddWallItems( const { model, ...rest } = item; return { ...rest, - modeluuid: model?.uuid, + modelUuid: model?.uuid, }; }); diff --git a/app/src/modules/builder/geomentries/walls/deleteWallItems.ts b/app/src/modules/builder/geomentries/walls/deleteWallItems.ts index abbf0c8..b5d40f4 100644 --- a/app/src/modules/builder/geomentries/walls/deleteWallItems.ts +++ b/app/src/modules/builder/geomentries/walls/deleteWallItems.ts @@ -28,14 +28,14 @@ function DeleteWallItems( //REST - // await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelname!) + // await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelName!) //SOCKET const data = { organization: organization, - modeluuid: removedItem?.model?.uuid!, - modelname: removedItem?.modelname!, + modelUuid: removedItem?.model?.uuid!, + modelName: removedItem?.modelName!, socketId: socket.id } @@ -45,7 +45,7 @@ function DeleteWallItems( const { model, ...rest } = item; return { ...rest, - modeluuid: model?.uuid, + modelUuid: model?.uuid, }; }); diff --git a/app/src/modules/builder/groups/wallItemsGroup.tsx b/app/src/modules/builder/groups/wallItemsGroup.tsx index 43845e7..f993754 100644 --- a/app/src/modules/builder/groups/wallItemsGroup.tsx +++ b/app/src/modules/builder/groups/wallItemsGroup.tsx @@ -91,7 +91,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable const { model, ...rest } = item; return { ...rest, - modeluuid: model?.uuid, + modelUuid: model?.uuid, }; }); @@ -110,7 +110,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable // await setWallItem( // organization, // currentItem?.model?.uuid, - // currentItem.modelname, + // currentItem.modelName, // currentItem.type!, // currentItem.csgposition!, // currentItem.csgscale!, @@ -123,8 +123,8 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable const data = { organization: organization, - modeluuid: currentItem.model?.uuid!, - modelname: currentItem.modelname!, + modelUuid: currentItem.model?.uuid!, + modelName: currentItem.modelName!, type: currentItem.type!, csgposition: currentItem.csgposition!, csgscale: currentItem.csgscale!, diff --git a/app/src/modules/collaboration/socket/socketResponses.dev.tsx b/app/src/modules/collaboration/socket/socketResponses.dev.tsx index 3d9cddf..86e41c2 100644 --- a/app/src/modules/collaboration/socket/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socket/socketResponses.dev.tsx @@ -99,13 +99,13 @@ export default function SocketResponses({ try { isTempLoader.current = true; - const cachedModel = THREE.Cache.get(data.data.modelname); + const cachedModel = THREE.Cache.get(data.data.modelName); let url; if (cachedModel) { - // console.log(`Getting ${data.data.modelname} from cache`); + // console.log(`Getting ${data.data.modelName} from cache`); const model = cachedModel.scene.clone(); - model.uuid = data.data.modeluuid; - model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; + model.uuid = data.data.modelUuid; + model.userData = { name: data.data.modelName, modelId: data.data.modelfileID, modelUuid: data.data.modelUuid }; model.position.set(...data.data.position as [number, number, number]); model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); @@ -130,8 +130,8 @@ export default function SocketResponses({ } const newFloorItem: Types.FloorItemType = { - modeluuid: data.data.modeluuid, - modelname: data.data.modelname, + modelUuid: data.data.modelUuid, + modelName: data.data.modelName, modelfileID: data.data.modelfileID, position: [...data.data.position as [number, number, number]], rotation: { @@ -153,12 +153,12 @@ export default function SocketResponses({ gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } }); } else { - const indexedDBModel = await retrieveGLTF(data.data.modelname); + const indexedDBModel = await retrieveGLTF(data.data.modelName); if (indexedDBModel) { - // console.log(`Getting ${data.data.modelname} from IndexedDB`); + // console.log(`Getting ${data.data.modelName} from IndexedDB`); url = URL.createObjectURL(indexedDBModel); } else { - // console.log(`Getting ${data.data.modelname} from Backend`); + // console.log(`Getting ${data.data.modelName} from Backend`); url = `${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`; const modelBlob = await fetch(url).then((res) => res.blob()); await storeGLTF(data.data.modelfileID, modelBlob); @@ -178,8 +178,8 @@ export default function SocketResponses({ URL.revokeObjectURL(url); THREE.Cache.remove(url); const model = gltf.scene; - model.uuid = data.data.modeluuid; - model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; + model.uuid = data.data.modelUuid; + model.userData = { name: data.data.modelName, modelId: data.data.modelfileID, modelUuid: data.data.modelUuid }; model.position.set(...data.data.position as [number, number, number]); model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); @@ -204,8 +204,8 @@ export default function SocketResponses({ } const newFloorItem: Types.FloorItemType = { - modeluuid: data.data.modeluuid, - modelname: data.data.modelname, + modelUuid: data.data.modelUuid, + modelName: data.data.modelName, modelfileID: data.data.modelfileID, position: [...data.data.position as [number, number, number]], rotation: { @@ -226,7 +226,7 @@ export default function SocketResponses({ gsap.to(model.position, { y: data.data.position[1], duration: 1.5, ease: 'power2.out' }); gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } }); - THREE.Cache.add(data.data.modelname, gltf); + THREE.Cache.add(data.data.modelName, gltf); }, () => { TempLoader(new THREE.Vector3(...data.data.position), isTempLoader, tempLoader, itemsGroup); }); @@ -234,7 +234,7 @@ export default function SocketResponses({ } else if (data.message === "Model updated successfully") { itemsGroup.current?.children.forEach((item: THREE.Group) => { - if (item.uuid === data.data.modeluuid) { + if (item.uuid === data.data.modelUuid) { item.position.set(...data.data.position as [number, number, number]); item.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); } @@ -246,7 +246,7 @@ export default function SocketResponses({ } let updatedItem: any = null; const updatedItems = prevItems.map((item) => { - if (item.modeluuid === data.data.modeluuid) { + if (item.modelUuid === data.data.modelUuid) { updatedItem = { ...item, position: [...data.data.position] as [number, number, number], @@ -269,15 +269,15 @@ export default function SocketResponses({ return } if (data.message === "Model deleted successfully") { - const deletedUUID = data.data.modeluuid; + const deletedUUID = data.data.modelUuid; let items = JSON.parse(localStorage.getItem("FloorItems")!); const updatedItems = items.filter( - (item: { modeluuid: string }) => item.modeluuid !== deletedUUID + (item: { modelUuid: string }) => item.modelUuid !== deletedUUID ); const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]'); - const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== deletedUUID); + const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => item.modelUuid !== deletedUUID); localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); itemsGroup.current.children.forEach((item: any) => { @@ -519,7 +519,7 @@ export default function SocketResponses({ return } if (data.message === "wallitem deleted") { - const deletedUUID = data.data.modeluuid; + const deletedUUID = data.data.modelUuid; let WallItemsRef = wallItems; const Items = WallItemsRef.filter((item: any) => item.model?.uuid !== deletedUUID); @@ -531,7 +531,7 @@ export default function SocketResponses({ const { model, ...rest } = item; return { ...rest, - modeluuid: model?.uuid, + modelUuid: model?.uuid, }; }); @@ -550,9 +550,9 @@ export default function SocketResponses({ } if (data.message === "wallIitem created") { const loader = new GLTFLoader(); - loader.load(AssetConfigurations[data.data.modelname].modelUrl, async (gltf) => { + loader.load(AssetConfigurations[data.data.modelName].modelUrl, async (gltf) => { const model = gltf.scene; - model.uuid = data.data.modeluuid; + model.uuid = data.data.modelUuid; model.children[0].children.forEach((child) => { if (child.name !== "CSG_REF") { child.castShadow = true; @@ -563,7 +563,7 @@ export default function SocketResponses({ const newWallItem = { type: data.data.type, model: model, - modelname: data.data.modelname, + modelName: data.data.modelName, scale: data.data.scale, csgscale: data.data.csgscale, csgposition: data.data.csgposition, @@ -578,7 +578,7 @@ export default function SocketResponses({ const { model, ...rest } = item; return { ...rest, - modeluuid: model?.uuid, + modelUuid: model?.uuid, }; }); @@ -589,7 +589,7 @@ export default function SocketResponses({ }); }); } else if (data.message === "wallIitem updated") { - const updatedUUID = data.data.modeluuid; + const updatedUUID = data.data.modelUuid; setWallItems((prevItems: any) => { const updatedItems = prevItems.map((item: any) => { @@ -610,7 +610,7 @@ export default function SocketResponses({ const { model, ...rest } = item; return { ...rest, - modeluuid: model?.uuid, + modelUuid: model?.uuid, }; }); 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/copyPasteControls.tsx b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx index 9ca4dd0..fa6ec16 100644 --- a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx @@ -6,6 +6,7 @@ import { toast } from "react-toastify"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import * as Types from "../../../../types/world/worldTypes"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, selectionGroup, setDuplicatedObjects, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => { const { camera, controls, gl, scene, pointer, raycaster } = useThree(); @@ -13,7 +14,8 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas const { selectedAssets, setSelectedAssets } = useSelectedAssets(); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const { floorItems, setFloorItems } = useFloorItems(); - const { socket } = useSocketStore() + const { socket } = useSocketStore(); + const { addEvent } = useEventsStore(); useEffect(() => { if (!camera || !scene || toggleView) return; @@ -138,55 +140,252 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas if (itemsGroupRef.current) { const newFloorItem: Types.FloorItemType = { - modeluuid: obj.uuid, - modelname: obj.userData.name, + modelUuid: obj.uuid, + modelName: obj.userData.name, modelfileID: obj.userData.modelId, position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, isLocked: false, - isVisible: true - }; - - setFloorItems((prevItems: Types.FloorItems) => { - const updatedItems = [...(prevItems || []), newFloorItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; - }); - - const email = localStorage.getItem("email"); - const organization = email ? email.split("@")[1].split(".")[0] : "default"; - - //REST - - // await setFloorItemApi( - // organization, - // obj.uuid, - // obj.userData.name, - // [worldPosition.x, worldPosition.y, worldPosition.z], - // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, - // obj.userData.modelId, - // false, - // true, - // ); - - //SOCKET - - const data = { - organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, - modelfileID: newFloorItem.modelfileID, - position: newFloorItem.position, - rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, - isLocked: false, isVisible: true, - socketId: socket.id, }; - socket.emit("v2:model-asset:add", data); + let updatedEventData = null; + if (obj.userData.eventData) { + updatedEventData = JSON.parse(JSON.stringify(obj.userData.eventData)); + updatedEventData.modelUuid = newFloorItem.modelUuid; - obj.userData.modeluuid = newFloorItem.modeluuid; - itemsGroupRef.current.add(obj); + const eventData: any = { + type: obj.userData.eventData.type, + }; + + if (obj.userData.eventData.type === "Conveyor") { + const ConveyorEvent: ConveyorEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: 'transfer', + speed: 1, + points: updatedEventData.points.map((point: any, index: number) => ({ + uuid: THREE.MathUtils.generateUUID(), + position: [point.position[0], point.position[1], point.position[2]], + rotation: [point.rotation[0], point.rotation[1], point.rotation[2]], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${index}`, + actionType: 'default', + material: 'Default Material', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: [] + } + })) + }; + addEvent(ConveyorEvent); + eventData.points = ConveyorEvent.points.map(point => ({ + uuid: point.uuid, + position: point.position, + rotation: point.rotation + })); + + } else if (obj.userData.eventData.type === "Vehicle") { + const vehicleEvent: VehicleEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: "vehicle", + speed: 1, + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]], + rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "travel", + unLoadDuration: 5, + loadCapacity: 10, + steeringAngle: 0, + pickUpPoint: null, + unLoadPoint: null, + triggers: [] + } + } + }; + addEvent(vehicleEvent); + eventData.point = { + uuid: vehicleEvent.point.uuid, + position: vehicleEvent.point.position, + rotation: vehicleEvent.point.rotation + }; + + } else if (obj.userData.eventData.type === "ArmBot") { + const roboticArmEvent: RoboticArmEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: "roboticArm", + speed: 1, + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]], + rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]], + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "pickAndPlace", + process: { + startPoint: null, + endPoint: null + }, + triggers: [] + } + ] + } + }; + addEvent(roboticArmEvent); + eventData.point = { + uuid: roboticArmEvent.point.uuid, + position: roboticArmEvent.point.position, + rotation: roboticArmEvent.point.rotation + }; + + } else if (obj.userData.eventData.type === "StaticMachine") { + const machineEvent: MachineEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: "machine", + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]], + rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "process", + processTime: 10, + swapMaterial: "Default Material", + triggers: [] + } + } + }; + addEvent(machineEvent); + eventData.point = { + uuid: machineEvent.point.uuid, + position: machineEvent.point.position, + rotation: machineEvent.point.rotation + }; + } + + obj.userData.eventData = eventData; + + newFloorItem.eventData = eventData; + + + setFloorItems((prevItems: Types.FloorItems) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : "default"; + + //REST + + // await setFloorItemApi( + // organization, + // obj.uuid, + // obj.userData.name, + // [worldPosition.x, worldPosition.y, worldPosition.z], + // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, + // obj.userData.modelId, + // false, + // true, + // ); + + //SOCKET + + const data = { + organization, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id, + eventData: eventData, + }; + + socket.emit("v2:model-asset:add", data); + + obj.userData = { + name: newFloorItem.modelName, + modelId: newFloorItem.modelfileID, + modelUuid: newFloorItem.modelUuid, + }; + + itemsGroupRef.current.add(obj); + + } else { + setFloorItems((prevItems: Types.FloorItems) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : "default"; + + //REST + + // await setFloorItemApi( + // organization, + // obj.uuid, + // obj.userData.name, + // [worldPosition.x, worldPosition.y, worldPosition.z], + // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, + // obj.userData.modelId, + // false, + // true, + // ); + + //SOCKET + + const data = { + organization, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id, + }; + + socket.emit("v2:model-asset:add", data); + + obj.userData = { + name: newFloorItem.modelName, + modelId: newFloorItem.modelfileID, + modelUuid: newFloorItem.modelUuid, + }; + + itemsGroupRef.current.add(obj); + } } }); @@ -205,7 +404,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas setSelectedAssets([]); } - return null; // No visible output, but the component handles copy-paste functionality + return null; }; export default CopyPasteControls; \ No newline at end of file diff --git a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx index 39c3e49..ffe560c 100644 --- a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx @@ -7,6 +7,7 @@ import { toast } from "react-toastify"; import * as Types from "../../../../types/world/worldTypes"; import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedObjects, setpastedObjects, selectionGroup, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => { const { camera, controls, gl, scene, pointer, raycaster } = useThree(); @@ -15,6 +16,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); + const { addEvent } = useEventsStore(); useEffect(() => { if (!camera || !scene || toggleView) return; @@ -116,55 +118,252 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb if (itemsGroupRef.current) { const newFloorItem: Types.FloorItemType = { - modeluuid: obj.uuid, - modelname: obj.userData.name, + modelUuid: obj.uuid, + modelName: obj.userData.name, modelfileID: obj.userData.modelId, position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, isLocked: false, - isVisible: true - }; - - setFloorItems((prevItems: Types.FloorItems) => { - const updatedItems = [...(prevItems || []), newFloorItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; - }); - - const email = localStorage.getItem("email"); - const organization = email ? email.split("@")[1].split(".")[0] : "default"; - - //REST - - // await setFloorItemApi( - // organization, - // obj.uuid, - // obj.userData.name, - // [worldPosition.x, worldPosition.y, worldPosition.z], - // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, - // obj.userData.modelId, - // false, - // true, - // ); - - //SOCKET - - const data = { - organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, - modelfileID: newFloorItem.modelfileID, - position: newFloorItem.position, - rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, - isLocked: false, isVisible: true, - socketId: socket.id, }; - socket.emit("v2:model-asset:add", data); + let updatedEventData = null; + if (obj.userData.eventData) { + updatedEventData = JSON.parse(JSON.stringify(obj.userData.eventData)); + updatedEventData.modelUuid = newFloorItem.modelUuid; - obj.userData.modeluuid = newFloorItem.modeluuid; - itemsGroupRef.current.add(obj); + const eventData: any = { + type: obj.userData.eventData.type, + }; + + if (obj.userData.eventData.type === "Conveyor") { + const ConveyorEvent: ConveyorEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: 'transfer', + speed: 1, + points: updatedEventData.points.map((point: any, index: number) => ({ + uuid: THREE.MathUtils.generateUUID(), + position: [point.position[0], point.position[1], point.position[2]], + rotation: [point.rotation[0], point.rotation[1], point.rotation[2]], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${index}`, + actionType: 'default', + material: 'Default Material', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: [] + } + })) + }; + addEvent(ConveyorEvent); + eventData.points = ConveyorEvent.points.map(point => ({ + uuid: point.uuid, + position: point.position, + rotation: point.rotation + })); + + } else if (obj.userData.eventData.type === "Vehicle") { + const vehicleEvent: VehicleEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: "vehicle", + speed: 1, + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]], + rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "travel", + unLoadDuration: 5, + loadCapacity: 10, + steeringAngle: 0, + pickUpPoint: null, + unLoadPoint: null, + triggers: [] + } + } + }; + addEvent(vehicleEvent); + eventData.point = { + uuid: vehicleEvent.point.uuid, + position: vehicleEvent.point.position, + rotation: vehicleEvent.point.rotation + }; + + } else if (obj.userData.eventData.type === "ArmBot") { + const roboticArmEvent: RoboticArmEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: "roboticArm", + speed: 1, + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]], + rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]], + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "pickAndPlace", + process: { + startPoint: null, + endPoint: null + }, + triggers: [] + } + ] + } + }; + addEvent(roboticArmEvent); + eventData.point = { + uuid: roboticArmEvent.point.uuid, + position: roboticArmEvent.point.position, + rotation: roboticArmEvent.point.rotation + }; + + } else if (obj.userData.eventData.type === "StaticMachine") { + const machineEvent: MachineEventSchema = { + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: "machine", + point: { + uuid: THREE.MathUtils.generateUUID(), + position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]], + rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "process", + processTime: 10, + swapMaterial: "Default Material", + triggers: [] + } + } + }; + addEvent(machineEvent); + eventData.point = { + uuid: machineEvent.point.uuid, + position: machineEvent.point.position, + rotation: machineEvent.point.rotation + }; + } + + obj.userData.eventData = eventData; + + newFloorItem.eventData = eventData; + + + setFloorItems((prevItems: Types.FloorItems) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : "default"; + + //REST + + // await setFloorItemApi( + // organization, + // obj.uuid, + // obj.userData.name, + // [worldPosition.x, worldPosition.y, worldPosition.z], + // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, + // obj.userData.modelId, + // false, + // true, + // ); + + //SOCKET + + const data = { + organization, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id, + eventData: eventData, + }; + + socket.emit("v2:model-asset:add", data); + + obj.userData = { + name: newFloorItem.modelName, + modelId: newFloorItem.modelfileID, + modelUuid: newFloorItem.modelUuid, + }; + + itemsGroupRef.current.add(obj); + + } else { + setFloorItems((prevItems: Types.FloorItems) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : "default"; + + //REST + + // await setFloorItemApi( + // organization, + // obj.uuid, + // obj.userData.name, + // [worldPosition.x, worldPosition.y, worldPosition.z], + // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, + // obj.userData.modelId, + // false, + // true, + // ); + + //SOCKET + + const data = { + organization, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id, + }; + + socket.emit("v2:model-asset:add", data); + + obj.userData = { + name: newFloorItem.modelName, + modelId: newFloorItem.modelfileID, + modelUuid: newFloorItem.modelUuid, + }; + + itemsGroupRef.current.add(obj); + } } }); @@ -183,7 +382,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb setSelectedAssets([]); } - return null; // This component does not render any UI + return null; }; export default DuplicationControls; \ No newline at end of file diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index 2cde3e4..d371806 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -1,11 +1,14 @@ import * as THREE from "three"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useEffect, useMemo, useRef } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import { toast } from "react-toastify"; import * as Types from "../../../../types/world/worldTypes"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { useProductStore } from "../../../../store/simulation/useProductStore"; +import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) { const { camera, controls, gl, scene, pointer, raycaster } = useThree(); @@ -62,7 +65,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje if (keyCombination === "G") { if (selectedAssets.length > 0) { moveAssets(); - itemsData.current = floorItems.filter((item: { modeluuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modeluuid)); + itemsData.current = floorItems.filter((item: { modelUuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)); } } if (keyCombination === "ESCAPE") { @@ -148,7 +151,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje const moveAssets = () => { - const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modeluuid)); + const updatedItems = floorItems.filter((item: { modelUuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)); setFloorItems(updatedItems); setMovedObjects(selectedAssets); selectedAssets.forEach((asset: any) => { selectionGroup.current.attach(asset); }); @@ -167,8 +170,8 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje if (itemsGroupRef.current) { const newFloorItem: Types.FloorItemType = { - modeluuid: obj.uuid, - modelname: obj.userData.name, + modelUuid: obj.uuid, + modelName: obj.userData.name, modelfileID: obj.userData.modelId, position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, @@ -176,6 +179,24 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje isVisible: true }; + if (obj.userData.eventData) { + const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modelUuid); + const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid); + + if (eventData) { + useEventsStore.getState().updateEvent(obj.userData.modelUuid, { + position: [worldPosition.x, worldPosition.y, worldPosition.z], + rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], + }) + } + if (productData) { + 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], + }) + } + } + setFloorItems((prevItems: Types.FloorItems) => { const updatedItems = [...(prevItems || []), newFloorItem]; localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); @@ -202,8 +223,8 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje const data = { organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, modelfileID: newFloorItem.modelfileID, position: newFloorItem.position, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, @@ -234,7 +255,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje setSelectedAssets([]); } - return null; // No need to return anything, as this component is used for its side effects + return null; } export default MoveControls \ No newline at end of file diff --git a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx index 5dfaf08..08667b4 100644 --- a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx @@ -1,11 +1,13 @@ import * as THREE from "three"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useEffect, useMemo, useRef } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import { toast } from "react-toastify"; import * as Types from "../../../../types/world/worldTypes"; -import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { useProductStore } from "../../../../store/simulation/useProductStore"; +import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) { const { camera, controls, gl, scene, pointer, raycaster } = useThree(); @@ -62,7 +64,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo if (event.key.toLowerCase() === "r") { if (selectedAssets.length > 0) { rotateAssets(); - itemsData.current = floorItems.filter((item: { modeluuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modeluuid)); + itemsData.current = floorItems.filter((item: { modelUuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)); } } if (event.key.toLowerCase() === "escape") { @@ -126,7 +128,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo }); const rotateAssets = () => { - const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modeluuid)); + const updatedItems = floorItems.filter((item: { modelUuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)); setFloorItems(updatedItems); const box = new THREE.Box3(); @@ -168,8 +170,8 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo if (itemsGroupRef.current) { const newFloorItem: Types.FloorItemType = { - modeluuid: obj.uuid, - modelname: obj.userData.name, + modelUuid: obj.uuid, + modelName: obj.userData.name, modelfileID: obj.userData.modelId, position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, @@ -177,6 +179,24 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo isVisible: true }; + if (obj.userData.eventData) { + const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modelUuid); + const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid); + + if (eventData) { + useEventsStore.getState().updateEvent(obj.userData.modelUuid, { + position: [worldPosition.x, worldPosition.y, worldPosition.z], + rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], + }) + } + if (productData) { + 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], + }) + } + } + setFloorItems((prevItems: Types.FloorItems) => { const updatedItems = [...(prevItems || []), newFloorItem]; localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); @@ -203,8 +223,8 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo const data = { organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, modelfileID: newFloorItem.modelfileID, position: newFloorItem.position, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, @@ -235,7 +255,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo setSelectedAssets([]); } - return null; // No need to return anything, as this component is used for its side effects + return null; } export default RotateControls \ No newline at end of file diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx index 49b86d2..33a35c9 100644 --- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx @@ -14,6 +14,8 @@ import CopyPasteControls from "./copyPasteControls"; import MoveControls from "./moveControls"; import RotateControls from "./rotateControls"; import useModuleStore from "../../../../store/useModuleStore"; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { useProductStore } from "../../../../store/simulation/useProductStore"; const SelectionControls: React.FC = () => { const { camera, controls, gl, scene, pointer } = useThree(); @@ -206,7 +208,7 @@ const SelectionControls: React.FC = () => { const storedItems = JSON.parse(localStorage.getItem("FloorItems") || "[]"); const selectedUUIDs = selectedAssets.map((mesh: THREE.Object3D) => mesh.uuid); - const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => !selectedUUIDs.includes(item.modeluuid)); + const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => !selectedUUIDs.includes(item.modelUuid)); localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); selectedAssets.forEach((selectedMesh: THREE.Object3D) => { @@ -218,13 +220,16 @@ const SelectionControls: React.FC = () => { const data = { organization: organization, - modeluuid: selectedMesh.uuid, - modelname: selectedMesh.userData.name, + modelUuid: selectedMesh.uuid, + modelName: selectedMesh.userData.name, socketId: socket.id, }; socket.emit("v2:model-asset:delete", data); + useEventsStore.getState().removeEvent(selectedMesh.uuid); + useProductStore.getState().deleteEvent(selectedMesh.uuid); + selectedMesh.traverse((child: THREE.Object3D) => { if (child instanceof THREE.Mesh) { if (child.geometry) child.geometry.dispose(); @@ -243,7 +248,7 @@ const SelectionControls: React.FC = () => { itemsGroupRef.current?.remove(selectedMesh); }); - const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedUUIDs.includes(item.modeluuid)); + const updatedItems = floorItems.filter((item: { modelUuid: string }) => !selectedUUIDs.includes(item.modelUuid)); setFloorItems(updatedItems); } toast.success("Selected models removed!"); diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index c5025dd..c6ec316 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -1,10 +1,13 @@ -import React, { useEffect, useRef, useState } from 'react'; -import * as THREE from 'three'; -import { useEventsStore } from '../../../../../store/simulation/useEventsStore'; -import useModuleStore from '../../../../../store/useModuleStore'; -import { TransformControls } from '@react-three/drei'; -import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys'; -import { useSelectedEventSphere, useSelectedEventData } from '../../../../../store/simulation/useSimulationStore'; +import React, { useEffect, useRef, useState } from "react"; +import * as THREE from "three"; +import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; +import useModuleStore from "../../../../../store/useModuleStore"; +import { TransformControls } from "@react-three/drei"; +import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys"; +import { + useSelectedEventSphere, + useSelectedEventData, +} from "../../../../../store/simulation/useSimulationStore"; function PointsCreator() { const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore(); @@ -12,8 +15,8 @@ function PointsCreator() { 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 { setSelectedEventData, clearSelectedEventData } = useSelectedEventData(); + const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere, } = useSelectedEventSphere(); + const { selectedEventData, setSelectedEventData, clearSelectedEventData } = useSelectedEventData(); useEffect(() => { if (selectedEventSphere) { @@ -47,37 +50,57 @@ function PointsCreator() { }, [selectedEventSphere]); const updatePointToState = (selectedEventSphere: THREE.Mesh) => { - let point = JSON.parse(JSON.stringify(getPointByUuid(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid))); + let point = JSON.parse( + JSON.stringify( + getPointByUuid( + selectedEventSphere.userData.modelUuid, + selectedEventSphere.userData.pointUuid + ) + ) + ); if (point) { - point.position = [selectedEventSphere.position.x, selectedEventSphere.position.y, selectedEventSphere.position.z]; - updatePoint(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid, point) + point.position = [ + selectedEventSphere.position.x, + selectedEventSphere.position.y, + selectedEventSphere.position.z, + ]; + updatePoint( + selectedEventSphere.userData.modelUuid, + selectedEventSphere.userData.pointUuid, + point + ); } - } + }; return ( <> - {activeModule === 'simulation' && + {activeModule === "simulation" && ( <> - + {events.map((event, i) => { - if (event.type === 'transfer') { + if (event.type === "transfer") { return ( - + {event.points.map((point, j) => ( (sphereRefs.current[point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[point.uuid]); + setSelectedEventSphere( + sphereRefs.current[point.uuid] + ); }} onPointerMissed={() => { - clearSelectedEventSphere(); + if (selectedEventData?.data.type !== 'vehicle') { + clearSelectedEventSphere(); + } setTransformMode(null); }} key={`${i}-${j}`} position={new THREE.Vector3(...point.position)} + // rotation={new THREE.Euler(...point.rotation)} userData={{ modelUuid: event.modelUuid, pointUuid: point.uuid }} > @@ -86,22 +109,25 @@ function PointsCreator() { ))} ); - } else if (event.type === 'vehicle') { + } else if (event.type === "vehicle") { return ( - + (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[event.point.uuid]); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); }} onPointerMissed={() => { clearSelectedEventSphere(); setTransformMode(null); }} position={new THREE.Vector3(...event.point.position)} + // rotation={new THREE.Euler(...event.point.rotation)} userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} > @@ -109,22 +135,25 @@ function PointsCreator() { ); - } else if (event.type === 'roboticArm') { + } else if (event.type === "roboticArm") { return ( - + (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[event.point.uuid]); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); }} onPointerMissed={() => { clearSelectedEventSphere(); setTransformMode(null); }} position={new THREE.Vector3(...event.point.position)} + // rotation={new THREE.Euler(...event.point.rotation)} userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} > @@ -132,22 +161,25 @@ function PointsCreator() { ); - } else if (event.type === 'machine') { + } else if (event.type === "machine") { return ( - + (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[event.point.uuid]); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); }} onPointerMissed={() => { clearSelectedEventSphere(); setTransformMode(null); }} position={new THREE.Vector3(...event.point.position)} + // rotation={new THREE.Euler(...event.point.rotation)} userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} > @@ -160,11 +192,18 @@ function PointsCreator() { } })} - {(selectedEventSphere && transformMode) && - { updatePointToState(selectedEventSphere) }} /> - } + {selectedEventSphere && transformMode && ( + { + updatePointToState(selectedEventSphere); + }} + /> + )} - } + )} ); } diff --git a/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts b/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts index 7943c1c..9928578 100644 --- a/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts +++ b/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts @@ -1,28 +1,38 @@ +import { upsertProductOrEventApi } from "../../../../../services/simulation/UpsertProductOrEventApi"; + interface HandleAddEventToProductParams { - selectedAsset: any; // Replace `any` with specific type if you have it - addEvent: (productId: string, asset: any) => void; + event: EventsSchema | undefined; + addEvent: (productId: string, event: EventsSchema) => void; selectedProduct: { productId: string; productName: string; - // Add other fields if needed - }; - clearSelectedAsset: () => void; + } + clearSelectedAsset?: () => void; } export const handleAddEventToProduct = ({ - selectedAsset, + event, addEvent, selectedProduct, - clearSelectedAsset, + clearSelectedAsset }: HandleAddEventToProductParams) => { - console.log('selectedProduct: ', selectedProduct); - if (selectedAsset) { - addEvent(selectedProduct.productId, selectedAsset); - // upsertProductOrEventApi({ - // productName: selectedProduct.productName, - // productId: selectedProduct.productId, - // eventDatas: selectedAsset - // }); - clearSelectedAsset(); + if (event && selectedProduct.productId) { + addEvent(selectedProduct.productId, event); + + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + upsertProductOrEventApi({ + productName: selectedProduct.productName, + productId: selectedProduct.productId, + organization: organization, + eventDatas: event + }).then((data) => { + // console.log(data); + }) + + if (clearSelectedAsset) { + clearSelectedAsset(); + } } }; diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index 38175e2..ee1ac42 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -7,28 +7,27 @@ import { upsertProductOrEventApi } from '../../../services/simulation/UpsertProd import { getAllProductsApi } from '../../../services/simulation/getallProductsApi'; function Products() { - const { products, addProduct } = useProductStore(); + const { products, addProduct, setProducts } = useProductStore(); const { setSelectedProduct } = useSelectedProduct(); useEffect(() => { - if (products.length === 0) { - const id = THREE.MathUtils.generateUUID(); - const name = 'Product 1'; - addProduct(name, id); - // upsertProductOrEventApi({ productName: name, productId: id }).then((data) => { - // console.log('data: ', data); - // }); - setSelectedProduct(id, name); - } - }, [products]) + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + getAllProductsApi(organization).then((data) => { + if (data.length === 0) { + const id = THREE.MathUtils.generateUUID(); + const name = 'Product 1'; + addProduct(name, id); + upsertProductOrEventApi({ productName: name, productId: id, organization: organization }) + setSelectedProduct(id, name); + } else { + setProducts(data); + setSelectedProduct(data[0].productId, data[0].productName); + } + }) + }, []) useEffect(() => { - // const email = localStorage.getItem('email') - // const organization = (email!.split("@")[1]).split(".")[0]; - // console.log(organization); - // getAllProductsApi(organization).then((data) => { - // console.log('data: ', data); - // }) }, []) return ( diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 3fe8af1..6bde587 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -36,12 +36,12 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { useEffect(() => { let armItems = floorItems?.filter((val: any) => - val.modeluuid === "3abf5d46-b59e-4e6b-9c02-a4634b64b82d" + val.modelUuid === "3abf5d46-b59e-4e6b-9c02-a4634b64b82d" ); // Get the first matching item let armItem = armItems?.[0]; if (armItem) { - const targetMesh = scene?.getObjectByProperty("uuid", armItem.modeluuid); + const targetMesh = scene?.getObjectByProperty("uuid", armItem.modelUuid); if (targetMesh) { targetMesh.visible = activeModule !== "simulation" } diff --git a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx index f836ea4..efefa0c 100644 --- a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx +++ b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx @@ -1,19 +1,85 @@ -import { useEffect } from "react"; +import { useEffect, useRef, useState } from "react"; import { useThree } from "@react-three/fiber"; +import * as THREE from "three"; import { useSubModuleStore } from "../../../../store/useModuleStore"; import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore"; 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"; + +interface ConnectionLine { + id: string; + start: THREE.Vector3; + end: THREE.Vector3; + mid: THREE.Vector3; + trigger: TriggerSchema; +} function TriggerConnector() { const { gl, raycaster, scene } = useThree(); const { subModule } = useSubModuleStore(); - const { getPointByUuid, getIsEventInProduct } = useProductStore(); + const { products, getPointByUuid, getIsEventInProduct, getActionByUuid, addTrigger, addEvent, getEventByModelUuid } = useProductStore(); const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); const { selectedProduct } = useSelectedProduct(); - useEffect(() => { + const [firstSelectedPoint, setFirstSelectedPoint] = useState<{ + productId: string; + modelUuid: string; + pointUuid: string; + actionUuid?: string; + } | null>(null); + const [connections, setConnections] = useState([]); + + 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 + ); + + 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 + }); + } + } + }); + } + }); + } + }); + }); + + setConnections(newConnections); + }, [products]); + + useEffect(() => { + console.log('connections: ', connections); + }, connections) + + useEffect(() => { const canvasElement = gl.domElement; let drag = false; @@ -44,37 +110,114 @@ function TriggerConnector() { const handleRightClick = (evt: MouseEvent) => { if (drag) return; evt.preventDefault(); - const canvasElement = gl.domElement; - if (!canvasElement) return; - let intersects = raycaster.intersectObjects(scene.children, true); - 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; + const intersects = raycaster.intersectObjects(scene.children, true); + if (intersects.length === 0) return; - if (currentObject && currentObject.name === 'Event-Sphere') { + const currentObject = intersects[0].object; + if (!currentObject || currentObject.name !== 'Event-Sphere') return; - const isInProduct = getIsEventInProduct( - selectedProduct.productId, - currentObject.userData.modelUuid - ); + const modelUuid = currentObject.userData.modelUuid; + const pointUuid = currentObject.userData.pointUuid; - // You left Here + if (selectedProduct && getIsEventInProduct(selectedProduct.productId, modelUuid)) { - if (isInProduct) { + const point = getPointByUuid( + selectedProduct.productId, + modelUuid, + pointUuid + ); - const event = getPointByUuid( - selectedProduct.productId, - currentObject.userData.modelUuid, - currentObject.userData.pointUuid - ); - console.log('event: ', event); - } else { + if (!point) return; - } + let actionUuid: string | undefined; + if ('action' in point && point.action) { + actionUuid = point.action.actionUuid; + } else if ('actions' in point && point.actions.length === 1) { + actionUuid = point.actions[0].actionUuid; } - } else { + if (!firstSelectedPoint) { + setFirstSelectedPoint({ + productId: selectedProduct.productId, + modelUuid, + pointUuid, + actionUuid + }); + } else { + const trigger: TriggerSchema = { + triggerUuid: THREE.MathUtils.generateUUID(), + triggerName: `Trigger ${firstSelectedPoint.pointUuid.slice(0, 4)} → ${pointUuid.slice(0, 4)}`, + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: currentObject.parent?.parent?.name || 'Unknown', + modelUuid: modelUuid + }, + triggeredPoint: { + pointName: currentObject.name, + pointUuid: pointUuid + }, + triggeredAction: actionUuid ? { + actionName: getActionByUuid(selectedProduct.productId, actionUuid)?.actionName || 'Action', + actionUuid: actionUuid + } : null + } + }; + if (firstSelectedPoint.actionUuid) { + addTrigger(firstSelectedPoint.actionUuid, trigger); + } + setFirstSelectedPoint(null); + } + } else if (!getIsEventInProduct(selectedProduct.productId, modelUuid) && firstSelectedPoint) { + handleAddEventToProduct({ + event: useEventsStore.getState().getEventByModelUuid(modelUuid), + addEvent, + selectedProduct, + }) + + const point = getPointByUuid( + selectedProduct.productId, + modelUuid, + pointUuid + ); + + if (!point) return; + + let actionUuid: string | undefined; + if ('action' in point && point.action) { + actionUuid = point.action.actionUuid; + } else if ('actions' in point && point.actions.length === 1) { + actionUuid = point.actions[0].actionUuid; + } + + const trigger: TriggerSchema = { + triggerUuid: THREE.MathUtils.generateUUID(), + triggerName: `Trigger ${firstSelectedPoint.pointUuid.slice(0, 4)} → ${pointUuid.slice(0, 4)}`, + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: currentObject.parent?.parent?.name || 'Unknown', + modelUuid: modelUuid + }, + triggeredPoint: { + pointName: currentObject.name, + pointUuid: pointUuid + }, + triggeredAction: actionUuid ? { + actionName: getActionByUuid(selectedProduct.productId, actionUuid)?.actionName || 'Action', + actionUuid: actionUuid + } : null + } + }; + + if (firstSelectedPoint.actionUuid) { + addTrigger(firstSelectedPoint.actionUuid, trigger); + } + setFirstSelectedPoint(null); } }; @@ -92,12 +235,12 @@ function TriggerConnector() { canvasElement.removeEventListener('contextmenu', handleRightClick); }; - }, [gl, subModule]); + }, [gl, subModule, selectedProduct, firstSelectedPoint]); return ( <> - ) + ); } -export default TriggerConnector \ No newline at end of file +export default TriggerConnector; \ No newline at end of file diff --git a/app/src/modules/simulation/ui/vehicle/useDraggableGLTF.ts b/app/src/modules/simulation/ui/vehicle/useDraggableGLTF.ts new file mode 100644 index 0000000..b7e9272 --- /dev/null +++ b/app/src/modules/simulation/ui/vehicle/useDraggableGLTF.ts @@ -0,0 +1,131 @@ +import { useRef } from "react"; +import * as THREE from "three"; +import { ThreeEvent, useThree } from "@react-three/fiber"; + +type OnUpdateCallback = (object: THREE.Object3D) => void; + +export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { + const { camera, gl, controls, scene } = useThree(); + const activeObjRef = useRef(null); + const planeRef = useRef( + new THREE.Plane(new THREE.Vector3(0, 1, 0), 0) + ); + const offsetRef = useRef(new THREE.Vector3()); + const initialPositionRef = useRef(new THREE.Vector3()); + + const raycaster = new THREE.Raycaster(); + const pointer = new THREE.Vector2(); + + const handlePointerDown = (e: ThreeEvent) => { + e.stopPropagation(); + + let obj: THREE.Object3D | null = e.object; + + // Traverse up until we find modelUuid in userData + while (obj && !obj.userData?.modelUuid) { + obj = obj.parent; + } + + if (!obj) return; + + // Disable orbit controls while dragging + if (controls) (controls as any).enabled = false; + + activeObjRef.current = obj; + initialPositionRef.current.copy(obj.position); + + // Get world position + const objectWorldPos = new THREE.Vector3(); + obj.getWorldPosition(objectWorldPos); + + // Set plane at the object's Y level + planeRef.current.set(new THREE.Vector3(0, 1, 0), -objectWorldPos.y); + + // Convert pointer to NDC + const rect = gl.domElement.getBoundingClientRect(); + pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1; + pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1; + + // Raycast to intersection + raycaster.setFromCamera(pointer, camera); + const intersection = new THREE.Vector3(); + raycaster.ray.intersectPlane(planeRef.current, intersection); + + // Calculate offset + offsetRef.current.copy(objectWorldPos).sub(intersection); + + // Start listening for drag + gl.domElement.addEventListener("pointermove", handlePointerMove); + gl.domElement.addEventListener("pointerup", handlePointerUp); + }; + + const handlePointerMove = (e: PointerEvent) => { + if (!activeObjRef.current) return; + + // Check if Shift key is pressed + const isShiftKeyPressed = e.shiftKey; + + // Get the mouse position relative to the canvas + const rect = gl.domElement.getBoundingClientRect(); + pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1; + pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1; + + // Update raycaster to point to the mouse position + raycaster.setFromCamera(pointer, camera); + + // Create a vector to store intersection point + const intersection = new THREE.Vector3(); + const intersects = raycaster.ray.intersectPlane(planeRef.current, intersection); + if (!intersects) return; + + // Add offset for dragging + intersection.add(offsetRef.current); + console.log('intersection: ', intersection); + + // Get the parent's world matrix if exists + const parent = activeObjRef.current.parent; + const targetPosition = new THREE.Vector3(); + + if (isShiftKeyPressed) { + console.log('isShiftKeyPressed: ', isShiftKeyPressed); + // For Y-axis only movement, maintain original X and Z + console.log('initialPositionRef: ', initialPositionRef); + console.log('intersection.y: ', intersection); + targetPosition.set( + initialPositionRef.current.x, + intersection.y, + initialPositionRef.current.z + ); + } else { + // For free movement + targetPosition.copy(intersection); + } + + // Convert world position to local if object is nested inside a parent + if (parent) { + parent.worldToLocal(targetPosition); + } + + // Update object position + activeObjRef.current.position.copy(targetPosition); + }; + + const handlePointerUp = () => { + if (controls) (controls as any).enabled = true; + + if (activeObjRef.current) { + // Pass the updated position to the onUpdate callback to persist it + onUpdate(activeObjRef.current); + } + + gl.domElement.removeEventListener("pointermove", handlePointerMove); + gl.domElement.removeEventListener("pointerup", handlePointerUp); + + activeObjRef.current = null; + }; + + return { handlePointerDown }; +} + + + diff --git a/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx new file mode 100644 index 0000000..5dec724 --- /dev/null +++ b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx @@ -0,0 +1,243 @@ +import React, { useEffect, useRef, useState } from 'react'; +import startPoint from "../../../../assets/gltf-glb/arrow_green.glb"; +import startEnd from "../../../../assets/gltf-glb/arrow_red.glb"; +import * as THREE from "three"; +import { useGLTF } from '@react-three/drei'; +import { useFrame, useThree } from '@react-three/fiber'; +import { useSelectedEventSphere } from '../../../../store/simulation/useSimulationStore'; +import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; +import * as Types from "../../../../types/world/worldTypes"; +const VehicleUI = () => { + const { scene: startScene } = useGLTF(startPoint) as any; + const { scene: endScene } = useGLTF(startEnd) as any; + const startMarker = useRef(null); + const endMarker = useRef(null); + const prevMousePos = useRef({ x: 0, y: 0 }); + const { selectedEventSphere } = useSelectedEventSphere(); + const { vehicles, updateVehicle } = useVehicleStore(); + 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 { 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; + + useEffect(() => { + if (!selectedEventSphere) return; + const selectedVehicle = vehicles.find( + (vehicle: any) => vehicle.modelUuid === 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]); + } 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]); + } 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]); + } + } + }, [selectedEventSphere]); + + useFrame(() => { + if (!isDragging) return; + const intersectPoint = new THREE.Vector3(); + 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]); + } + if (isDragging === "end") { + setEndPosition([intersectPoint.x, 0, intersectPoint.z]); + } + } + }); + + useFrame((state) => { + if (!isRotating) return; + + const currentPointerX = state.pointer.x; + const deltaX = currentPointerX - prevMousePos.current.x; + prevMousePos.current.x = currentPointerX; + + const marker = isRotating === "start" ? startMarker.current : endMarker.current; + + if (marker) { + const rotationSpeed = 10; + marker.rotation.y += deltaX * rotationSpeed; + if (isRotating === 'start') { + setStartRotation([marker.rotation.x, marker.rotation.y, marker.rotation.z]) + } else { + + setEndRotation([marker.rotation.x, marker.rotation.y, marker.rotation.z]) + } + } + }); + + + const handlePointerDown = (e: any, state: "start" | "end", rotation: "start" | "end") => { + + if (e.object.name === "handle") { + const normalizedX = (e.clientX / window.innerWidth) * 2 - 1; + const normalizedY = -(e.clientY / window.innerHeight) * 2 + 1; + prevMousePos.current = { x: normalizedX, y: normalizedY }; + setIsRotating(rotation); + if (controls) controls.enabled = false; + setIsDragging(null); + + } else { + setIsDragging(state); + setIsRotating(null); + if (controls) controls.enabled = false; + } + }; + + const handlePointerUp = () => { + controls.enabled = true; + setIsDragging(null); + setIsRotating(null); + + if (selectedEventSphere?.userData.modelUuid) { + const updatedVehicle = vehicles.find( + (vehicle) => vehicle.modelUuid === selectedEventSphere.userData.modelUuid + ); + + if (updatedVehicle) { + updateVehicle(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], + }, + }, + unLoadPoint: { + position: { + x: endPosition[0], + y: endPosition[1], + z: endPosition[2], + }, + rotation: { + x: endRotation[0], + y: endRotation[1], + z: endRotation[2], + }, + }, + }, + }, + }); + } + } + }; + + useEffect(() => { + const handleGlobalPointerUp = () => { + setIsDragging(null); + setIsRotating(null); + if (controls) controls.enabled = true; + handlePointerUp(); + }; + + if (isDragging || isRotating) { + window.addEventListener("pointerup", handleGlobalPointerUp); + } + + return () => { + window.removeEventListener("pointerup", handleGlobalPointerUp); + }; + }, [isDragging, isRotating, startPosition, startRotation, endPosition, endRotation]); + + return ( + startPosition.length > 0 && endPosition.length > 0 ? ( + + { + e.stopPropagation(); + handlePointerDown(e, "start", "start"); + }} + onPointerMissed={() => { + controls.enabled = true; + setIsDragging(null); + setIsRotating(null); + }} + /> + + { + e.stopPropagation(); + handlePointerDown(e, "end", "end"); + }} + onPointerMissed={() => { + controls.enabled = true; + setIsDragging(null); + setIsRotating(null); + }} + /> + + ) : null + ); +} +export default VehicleUI; + + diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index a8cfc39..2f0b235 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -1,9 +1,8 @@ import { useEffect, useRef, useState } from 'react' import { useFrame, useThree } from '@react-three/fiber'; -import { useFloorItems } from '../../../../../store/store'; import * as THREE from 'three'; import { Line } from '@react-three/drei'; -import { useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; +import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; interface VehicleAnimatorProps { @@ -16,27 +15,35 @@ interface VehicleAnimatorProps { } function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) { - const { decrementVehicleLoad, vehicles } = useVehicleStore(); + const { decrementVehicleLoad } = useVehicleStore(); const { isPaused } = usePauseButtonStore(); + const { isPlaying } = usePlayButtonStore(); const { speed } = useAnimationPlaySpeed(); - const { isReset } = useResetButtonStore(); - const [restRotation, setRestingRotation] = useState(true); - const [progress, setProgress] = useState(0); - const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); - const { scene } = useThree(); + const { isReset, setReset } = useResetButtonStore(); const progressRef = useRef(0); const movingForward = useRef(true); const completedRef = useRef(false); + const isPausedRef = useRef(false); + const pauseTimeRef = useRef(null); + const [restRotation, setRestingRotation] = useState(true); + const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); + const [progress, setProgress] = useState(0); + const { scene } = useThree(); let startTime: number; - let pausedTime: 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 }; + useEffect(() => { if (currentPhase === 'stationed-pickup' && path.length > 0) { setCurrentPath(path); + objectRotation = agvDetail.point.action?.pickUpPoint?.rotation } else if (currentPhase === 'pickup-drop' && path.length > 0) { + objectRotation = agvDetail.point.action?.unLoadPoint?.rotation setCurrentPath(path); } else if (currentPhase === 'drop-pickup' && path.length > 0) { + objectRotation = agvDetail.point.action?.pickUpPoint?.rotation setCurrentPath(path); } }, [currentPhase, path]); @@ -45,122 +52,42 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai setProgress(0); completedRef.current = false; }, [currentPath]); - // useEffect(() => { - // console.log('isReset: ', isReset); - // if (isReset) { - // reset(); - // setCurrentPath([]); - // setProgress(0); - // completedRef.current = false; - // decrementVehicleLoad(agvDetail.modelUuid, 0) - // } - // }, [isReset]) - // useFrame((_, delta) => { - // const object = scene.getObjectByProperty('uuid', agvUuid); - // if (!object || currentPath.length < 2) return; - // if (isPaused) return; - - // let totalDistance = 0; - // const distances = []; - - // for (let i = 0; i < currentPath.length - 1; i++) { - // const start = new THREE.Vector3(...currentPath[i]); - // const end = new THREE.Vector3(...currentPath[i + 1]); - // const segmentDistance = start.distanceTo(end); - // distances.push(segmentDistance); - // totalDistance += segmentDistance; - // } - - // let coveredDistance = progressRef.current; - // let accumulatedDistance = 0; - // let index = 0; - - // while ( - // index < distances.length && - // coveredDistance > accumulatedDistance + distances[index] - // ) { - // accumulatedDistance += distances[index]; - // index++; - // } - - // if (index < distances.length) { - // const start = new THREE.Vector3(...currentPath[index]); - // const end = new THREE.Vector3(...currentPath[index + 1]); - // const segmentDistance = distances[index]; - - // const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); - // const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); - // const rotationSpeed = 2.0; - // const currentAngle = object.rotation.y; - - // let angleDifference = targetAngle - currentAngle; - // if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; - // if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; - - // const maxRotationStep = rotationSpeed * delta; - // object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); - - // const isAligned = Math.abs(angleDifference) < 0.01; - - // if (isAligned) { - // progressRef.current += delta * (speed * agvDetail.speed); - // coveredDistance = progressRef.current; - - // const t = (coveredDistance - accumulatedDistance) / segmentDistance; - // const position = start.clone().lerp(end, t); - // object.position.copy(position); - // } - // } - - // if (progressRef.current >= totalDistance) { - // if (restRotation) { - // const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); - // object.quaternion.slerp(targetQuaternion, delta * 2); - // const angleDiff = object.quaternion.angleTo(targetQuaternion); - // if (angleDiff < 0.01) { - // let objectRotation = agvDetail.point.rotation - // object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); - // setRestingRotation(false); - // } - // return; - // } - // } - - // if (progressRef.current >= totalDistance) { - // setRestingRotation(true); - // progressRef.current = 0; - // movingForward.current = !movingForward.current; - // setCurrentPath([]); - // handleCallBack(); - // if (currentPhase === 'pickup-drop') { - // requestAnimationFrame(firstFrame); - // } - // } - // }); useEffect(() => { - if (isReset) { + if (isReset || !isPlaying) { reset(); setCurrentPath([]); setProgress(0); - progressRef.current = 0; completedRef.current = false; movingForward.current = true; - setRestingRotation(false); + progressRef.current = 0; + startTime = 0; + coveredDistance = 0; + setReset(false); + 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); + } } - }, [isReset]); + }, [isReset, isPlaying]) + + useEffect(() => { + isPausedRef.current = isPaused; + }, [isPaused]); useFrame((_, delta) => { - // If reset is active, don't run anything in frame - if (isReset) return; - const object = scene.getObjectByProperty('uuid', agvUuid); if (!object || currentPath.length < 2) return; if (isPaused) return; let totalDistance = 0; const distances = []; + let accumulatedDistance = 0; + let index = 0; for (let i = 0; i < currentPath.length - 1; i++) { const start = new THREE.Vector3(...currentPath[i]); @@ -170,10 +97,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai totalDistance += segmentDistance; } - let coveredDistance = progressRef.current; - let accumulatedDistance = 0; - let index = 0; - while (index < distances.length && coveredDistance > accumulatedDistance + distances[index]) { accumulatedDistance += distances[index]; index++; @@ -186,17 +109,16 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); + + const rotationSpeed = speed; const currentAngle = object.rotation.y; let angleDifference = targetAngle - currentAngle; if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; - const rotationSpeed = 2.0; const maxRotationStep = rotationSpeed * delta; - const rotationStep = Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); - object.rotation.y += rotationStep; - + object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); const isAligned = Math.abs(angleDifference) < 0.01; if (isAligned) { @@ -211,43 +133,63 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai if (progressRef.current >= totalDistance) { if (restRotation) { - const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); + 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); if (angleDiff < 0.01) { - const objectRotation = agvDetail.point.rotation; - object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + object.rotation.set(objectRotation.x, objectRotation.y, objectRotation.z); setRestingRotation(false); } - } else { - setRestingRotation(true); - progressRef.current = 0; - movingForward.current = !movingForward.current; - setCurrentPath([]); - handleCallBack(); - if (currentPhase === 'pickup-drop') { - requestAnimationFrame(firstFrame); - } + return; + } + } + + if (progressRef.current >= totalDistance) { + setRestingRotation(true); + progressRef.current = 0; + movingForward.current = !movingForward.current; + setCurrentPath([]); + handleCallBack(); + if (currentPhase === 'pickup-drop') { + requestAnimationFrame(firstFrame); } } }); function firstFrame() { - const unLoadDuration = agvDetail.point.action.unLoadDuration; const droppedMaterial = agvDetail.currentLoad; - fixedInterval = (unLoadDuration / droppedMaterial) * 1000; startTime = performance.now(); step(droppedMaterial); } function step(droppedMaterial: number) { - const elapsedTime = (performance.now() - startTime) * speed; + if (isPausedRef.current) { + if (!pauseTimeRef.current) { + pauseTimeRef.current = performance.now(); + } + requestAnimationFrame(() => step(droppedMaterial)); + return; + } + + if (pauseTimeRef.current) { + const pauseDuration = performance.now() - pauseTimeRef.current; + startTime += pauseDuration; + pauseTimeRef.current = null; + } + + const elapsedTime = performance.now() - startTime; + const unLoadDuration = agvDetail.point.action.unLoadDuration; + fixedInterval = ((unLoadDuration / agvDetail.currentLoad) * (1000 / speed)); + if (elapsedTime >= fixedInterval) { let droppedMat = droppedMaterial - 1; decrementVehicleLoad(agvDetail.modelUuid, 1); - if (droppedMat === 0) return; - startTime = performance.now(); - requestAnimationFrame(() => step(droppedMat)); + if (droppedMat > 0) { + startTime = performance.now(); + requestAnimationFrame(() => step(droppedMat)); + } else { + return; + } } else { requestAnimationFrame(() => step(droppedMaterial)); } diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index a7a41d3..6a81d3a 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -1,18 +1,18 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import VehicleAnimator from '../animator/vehicleAnimator'; import * as THREE from 'three'; import { NavMeshQuery } from '@recast-navigation/core'; import { useNavMesh } from '../../../../../store/store'; -import { usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; +import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; function VehicleInstance({ agvDetail }: any) { const { navMesh } = useNavMesh(); - const { isPlaying, setIsPlaying } = usePlayButtonStore(); - const { isReset } = useResetButtonStore(); + const { isPlaying } = usePlayButtonStore(); const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore(); const [currentPhase, setCurrentPhase] = useState('stationed'); const [path, setPath] = useState<[number, number, number][]>([]); + let isIncrememtable = useRef(true); const computePath = useCallback( (start: any, end: any) => { @@ -20,7 +20,7 @@ function VehicleInstance({ agvDetail }: any) { const navMeshQuery = new NavMeshQuery(navMesh); const { path: segmentPath } = navMeshQuery.computePath(start, end); return ( - segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || [] + segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [] ); } catch { return []; @@ -29,77 +29,92 @@ function VehicleInstance({ agvDetail }: any) { [navMesh] ); - function vehicleStatus(modelid: string, status: string) { - // console.log(`AGV ${modelid}: ${status}`); + function vehicleStatus(modelId: string, status: string) { + // console.log(`${modelId} , ${status}); } + + // Function to reset everything function reset() { + setCurrentPhase('stationed'); setVehicleActive(agvDetail.modelUuid, false); setVehicleState(agvDetail.modelUuid, 'idle'); setPath([]); - setCurrentPhase('stationed') + } + + const increment = () => { + if (isIncrememtable.current) { + + incrementVehicleLoad(agvDetail.modelUuid, 2); + isIncrememtable.current = false; + } } useEffect(() => { if (isPlaying) { + if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { const toPickupPath = computePath( - new THREE.Vector3(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]), - agvDetail.point.action.pickUpPoint + new THREE.Vector3(agvDetail?.position[0], agvDetail?.position[1], agvDetail?.position[2]), + agvDetail?.point?.action?.pickUpPoint?.position ); setPath(toPickupPath); - setVehicleActive(agvDetail.modelUuid, true); - setVehicleState(agvDetail.modelUuid, 'running'); setCurrentPhase('stationed-pickup'); + setVehicleState(agvDetail.modelUuid, 'running'); + setVehicleActive(agvDetail.modelUuid, true); vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup'); return; } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'picking') { setTimeout(() => { - incrementVehicleLoad(agvDetail.modelUuid, 2); + increment(); }, 5000); if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) { const toDrop = computePath( - agvDetail.point.action.pickUpPoint, - agvDetail.point.action.unLoadPoint + agvDetail.point.action.pickUpPoint.position, + agvDetail.point.action.unLoadPoint.position ); setPath(toDrop); - setVehicleActive(agvDetail.modelUuid, true); - setVehicleState(agvDetail.modelUuid, 'running'); setCurrentPhase('pickup-drop'); + setVehicleState(agvDetail.modelUuid, 'running'); + setVehicleActive(agvDetail.modelUuid, true); vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point'); } } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'dropping' && agvDetail.currentLoad === 0) { const dropToPickup = computePath( - agvDetail.point.action.unLoadPoint, - agvDetail.point.action.pickUpPoint + agvDetail.point.action.unLoadPoint.position, + agvDetail.point.action.pickUpPoint.position ); setPath(dropToPickup); - setVehicleActive(agvDetail.modelUuid, true); - setVehicleState(agvDetail.modelUuid, 'running'); setCurrentPhase('drop-pickup'); + setVehicleState(agvDetail.modelUuid, 'running'); + setVehicleActive(agvDetail.modelUuid, true); vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); + + isIncrememtable.current = true; } + } else { + reset() } - }, [vehicles, currentPhase, path, isPlaying, isReset]); + }, [vehicles, currentPhase, path, isPlaying]); function handleCallBack() { if (currentPhase === 'stationed-pickup') { - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); setCurrentPhase('picking'); + setVehicleState(agvDetail.modelUuid, 'idle'); + setVehicleActive(agvDetail.modelUuid, false); vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material'); setPath([]); } else if (currentPhase === 'pickup-drop') { - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); setCurrentPhase('dropping'); + setVehicleState(agvDetail.modelUuid, 'idle'); + setVehicleActive(agvDetail.modelUuid, false); vehicleStatus(agvDetail.modelUuid, 'Reached drop point'); setPath([]); } else if (currentPhase === 'drop-pickup') { - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); setCurrentPhase('picking'); + setVehicleState(agvDetail.modelUuid, 'idle'); + setVehicleActive(agvDetail.modelUuid, false); setPath([]); vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete'); } diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index 2a0070b..91111cf 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -3,12 +3,16 @@ import VehicleInstance from './instance/vehicleInstance' import { useVehicleStore } from '../../../../store/simulation/useVehicleStore' function VehicleInstances() { + const { vehicles } = useVehicleStore(); + return ( <> {vehicles.map((val: any, i: any) => + + )} diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index eaf12a3..7badec5 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -1,15 +1,21 @@ -import React, { useEffect } from 'react' -import VehicleInstances from './instances/vehicleInstances'; -import { useVehicleStore } from '../../../store/simulation/useVehicleStore'; -import { useFloorItems } from '../../../store/store'; - +import React, { useEffect, useState } 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 VehicleUI from "../ui/vehicle/vehicleUI"; +import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; function Vehicles() { const { vehicles, addVehicle } = useVehicleStore(); - + const { selectedEventSphere } = useSelectedEventSphere(); + const { selectedEventData } = useSelectedEventData(); const { floorItems } = useFloorItems(); + const { isPlaying } = usePlayButtonStore(); - const vehicleStatusSample: VehicleEventSchema[] = [ + const [vehicleStatusSample, setVehicleStatusSample] = useState< + VehicleEventSchema[] + >([ { modelUuid: "9356f710-4727-4b50-bdb2-9c1e747ecc74", modelName: "AGV", @@ -28,6 +34,7 @@ function Vehicles() { 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: [ @@ -71,8 +78,9 @@ function Vehicles() { actionType: "travel", unLoadDuration: 10, loadCapacity: 2, - pickUpPoint: { position: { x: 90, y: 0, z: 28 }, rotation: { x: 0, y: 0, z: 0 } }, - unLoadPoint: { position: { x: 20, y: 0, z: 10 }, rotation: { x: 0, y: 0, z: 0 } }, + steeringAngle:0, + pickUpPoint: null, + unLoadPoint: null, triggers: [ { triggerUuid: "trig-001", @@ -96,68 +104,117 @@ function Vehicles() { } } }, - { - 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, - pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, - unLoadPoint: { position: { x: 20, y: 0, z: 10 }, rotation: { x: 0, y: 0, z: 0 } }, - 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 - } - ] - } - } - } - ]; - - - useEffect(() => { - addVehicle('123', vehicleStatusSample[0]); - // addVehicle('123', vehicleStatusSample[1]); - // addVehicle('123', vehicleStatusSample[2]); - }, []) - + // { + // 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 + // } + // ] + // } + // } + // } + ]); 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; \ No newline at end of file +export default Vehicles; + + + diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index 05f7371..caf37a1 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"; @@ -69,13 +66,17 @@ const RealTimeVisulization: React.FC = () => { const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { setRightSelect } = useRightSelected(); - const { editWidgetOptions, setEditWidgetOptions } = useEditWidgetOptionsStore(); + const { editWidgetOptions, setEditWidgetOptions } = + useEditWidgetOptionsStore(); const { rightClickSelected, setRightClickSelected } = useRightClickSelected(); const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false); const { setFloatingWidget } = useFloatingWidget(); const { widgetSubOption } = useWidgetSubOption(); const { visualizationSocket } = useSocketStore(); const { setSelectedChartId } = useWidgetStore(); + const [waitingPanels, setWaitingPanels] = useState(null); + + console.log("waitingPanels: ", waitingPanels); OuterClick({ contextClassName: [ @@ -377,6 +378,8 @@ const RealTimeVisulization: React.FC = () => { setHiddenPanels={setHiddenPanels} selectedZone={selectedZone} setSelectedZone={setSelectedZone} + waitingPanels={waitingPanels} + setWaitingPanels={setWaitingPanels} /> )} @@ -385,6 +388,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 */} +