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 757bf54..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 = () => { > diff --git a/app/src/components/icons/ExportModuleIcons.tsx b/app/src/components/icons/ExportModuleIcons.tsx index 1dda323..c1a8432 100644 --- a/app/src/components/icons/ExportModuleIcons.tsx +++ b/app/src/components/icons/ExportModuleIcons.tsx @@ -10,7 +10,7 @@ export function BuilderIcon({ isActive }: { isActive: boolean }) { > @@ -29,41 +29,41 @@ export function SimulationIcon({ isActive }: { isActive: boolean }) { > @@ -81,19 +81,19 @@ export function VisualizationIcon({ isActive }: { isActive: boolean }) { > @@ -112,20 +112,20 @@ export function CartIcon({ isActive }: { isActive: boolean }) { > diff --git a/app/src/components/icons/HeaderIcons.tsx b/app/src/components/icons/HeaderIcons.tsx index ef02f02..c2a0f62 100644 --- a/app/src/components/icons/HeaderIcons.tsx +++ b/app/src/components/icons/HeaderIcons.tsx @@ -9,7 +9,7 @@ export function ProjectIcon() { > @@ -31,26 +31,26 @@ export function ToggleSidebarIcon() { width="17" height="13.7273" rx="3.59091" - stroke="var(--accent-color)" + stroke="var(--text-color)" /> ); diff --git a/app/src/components/icons/RealTimeVisulationIcons.tsx b/app/src/components/icons/RealTimeVisulationIcons.tsx index d418247..84d8cca 100644 --- a/app/src/components/icons/RealTimeVisulationIcons.tsx +++ b/app/src/components/icons/RealTimeVisulationIcons.tsx @@ -10,43 +10,43 @@ export function CleanPannel() { diff --git a/app/src/components/icons/SimulationIcons.tsx b/app/src/components/icons/SimulationIcons.tsx index b4aa881..ef23c8f 100644 --- a/app/src/components/icons/SimulationIcons.tsx +++ b/app/src/components/icons/SimulationIcons.tsx @@ -9,13 +9,17 @@ export function AnalysisIcon({ isActive }: { isActive: boolean }) { > @@ -34,11 +38,15 @@ export function MechanicsIcon({ isActive }: { isActive: boolean }) { > ); @@ -55,15 +63,21 @@ export function PropertiesIcon({ isActive }: { isActive: boolean }) { > ); @@ -82,13 +96,17 @@ export function SimulationIcon({ isActive }: { isActive: boolean }) { fillRule="evenodd" clipRule="evenodd" d="M6.44104 7.04762C6.57815 6.98413 6.73614 6.98413 6.87325 7.04762L12.0161 9.42958C12.198 9.51377 12.3143 9.69589 12.3143 9.89624V15.8512C12.3143 16.0347 12.2165 16.2043 12.0577 16.2962L6.9148 19.2736C6.75547 19.3659 6.55881 19.3659 6.39949 19.2736L1.25661 16.2962C1.09779 16.2043 1 16.0347 1 15.8512V9.89624C1 9.69589 1.11635 9.51377 1.29815 9.42958L6.44104 7.04762ZM2.02857 10.7297L6.14286 12.794V17.9366L2.02857 15.5546V10.7297ZM7.17143 17.9366L11.2857 15.5546V10.7297L7.17143 12.794V17.9366ZM6.65714 11.9013L10.6163 9.91477L6.65714 8.08106L2.69798 9.91477L6.65714 11.9013Z" - fill={"var(--icon-default-color-active)"} + fill={ + isActive ? "var(--icon-default-color-active)" : "var(--text-color)" + } /> ); diff --git a/app/src/components/icons/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/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 = () => { 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/widgets/panel/AddButtons.tsx b/app/src/modules/visualization/widgets/panel/AddButtons.tsx index 778ded1..6968c2e 100644 --- a/app/src/modules/visualization/widgets/panel/AddButtons.tsx +++ b/app/src/modules/visualization/widgets/panel/AddButtons.tsx @@ -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"; @@ -315,7 +313,7 @@ const AddButtons: React.FC = ({ fill={ hiddenPanels[selectedZone.zoneId]?.includes(side) ? "var(--icon-default-color-active)" - : "var(--icon-default-color)" + : "var(--text-color)" } />
    @@ -352,7 +350,7 @@ const AddButtons: React.FC = ({ fill={ selectedZone.lockedPanels.includes(side) ? "var(--icon-default-color-active)" - : "var(--icon-default-color)" + : "var(--text-color)" } />
    diff --git a/app/src/services/factoryBuilder/assest/floorAsset/deleteFloorItemApi.ts b/app/src/services/factoryBuilder/assest/floorAsset/deleteFloorItemApi.ts index fbbb042..908319b 100644 --- a/app/src/services/factoryBuilder/assest/floorAsset/deleteFloorItemApi.ts +++ b/app/src/services/factoryBuilder/assest/floorAsset/deleteFloorItemApi.ts @@ -1,13 +1,13 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -export const deleteFloorItem = async (organization: string, modeluuid: string, modelname: string) => { +export const deleteFloorItem = async (organization: string, modelUuid: string, modelName: string) => { try { const response = await fetch(`${url_Backend_dwinzo}/api/v1/deletefloorItem`, { method: "DELETE", headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ organization, modeluuid, modelname }), + body: JSON.stringify({ organization, modelUuid, modelName }), }); if (!response.ok) { diff --git a/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts b/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts index d587f06..3d7c921 100644 --- a/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts +++ b/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts @@ -1,8 +1,8 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; export const setFloorItemApi = async ( organization: string, - modeluuid?: string, - modelname?: string, + modelUuid?: string, + modelName?: string, modelfileID?: string, position?: Object, rotation?: Object, @@ -10,7 +10,7 @@ export const setFloorItemApi = async ( isVisible?: boolean, ) => { try { - const body: any = { organization, modeluuid, modelname, position, rotation, modelfileID, isLocked, isVisible }; + const body: any = { organization, modelUuid, modelName, position, rotation, modelfileID, isLocked, isVisible }; const response = await fetch(`${url_Backend_dwinzo}/api/v2/setasset`, { method: "POST", diff --git a/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts b/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts index 58f179d..da50167 100644 --- a/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts +++ b/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts @@ -1,13 +1,13 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -export const deleteWallItem = async (organization: string, modeluuid: string, modelname: string) => { +export const deleteWallItem = async (organization: string, modelUuid: string, modelName: string) => { try { const response = await fetch(`${url_Backend_dwinzo}/api/v1/deleteWallItem`, { method: "DELETE", headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ organization, modeluuid, modelname }), + body: JSON.stringify({ organization, modelUuid, modelName }), }); if (!response.ok) { diff --git a/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts b/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts index 79bed55..984adf5 100644 --- a/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts +++ b/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts @@ -2,8 +2,8 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR export const setWallItem = async ( organization: string, - modeluuid: string, - modelname: string, + modelUuid: string, + modelName: string, type: string, csgposition: Object, csgscale: Object, @@ -17,7 +17,7 @@ export const setWallItem = async ( headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ organization, modeluuid, modelname, position, type, csgposition, csgscale, quaternion, scale }), + body: JSON.stringify({ organization, modelUuid, modelName, position, type, csgposition, csgscale, quaternion, scale }), }); if (!response.ok) { diff --git a/app/src/services/factoryBuilder/webWorkers/assetManagerWorker.js b/app/src/services/factoryBuilder/webWorkers/assetManagerWorker.js index 4ccdbf5..50dac3f 100644 --- a/app/src/services/factoryBuilder/webWorkers/assetManagerWorker.js +++ b/app/src/services/factoryBuilder/webWorkers/assetManagerWorker.js @@ -21,7 +21,7 @@ onmessage = (event) => { const itemPosition = new THREE.Vector3(...item.position); const distance = cameraPos.distanceTo(itemPosition); - if (distance <= renderDistance && !uuids.includes(item.modeluuid)) { + if (distance <= renderDistance && !uuids.includes(item.modelUuid)) { toAdd.push(item); } }); @@ -35,7 +35,7 @@ onmessage = (event) => { // Check for items to be removed uuids.forEach((uuid) => { - const floorItem = floorItems.find((item) => item.modeluuid === uuid); + const floorItem = floorItems.find((item) => item.modelUuid === uuid); if (floorItem) { const itemPosition = new THREE.Vector3(...floorItem.position); const distance = cameraPos.distanceTo(itemPosition); diff --git a/app/src/services/simulation/deleteProductDataApi.ts b/app/src/services/simulation/deleteProductApi.ts similarity index 89% rename from app/src/services/simulation/deleteProductDataApi.ts rename to app/src/services/simulation/deleteProductApi.ts index 06718f8..2987a53 100644 --- a/app/src/services/simulation/deleteProductDataApi.ts +++ b/app/src/services/simulation/deleteProductApi.ts @@ -1,6 +1,6 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -export const deleteProductDataApi = async (productId: string, organization: string) => { +export const deleteProductApi = async (productId: string, organization: string) => { try { const response = await fetch(`${url_Backend_dwinzo}/api/v2/productDataDelete?productId=${productId}&organization=${organization}`, { method: "PATCH", diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index 8ec74cf..4f2b546 100644 --- a/app/src/store/simulation/useProductStore.ts +++ b/app/src/store/simulation/useProductStore.ts @@ -6,13 +6,15 @@ type ProductsStore = { // Product-level actions addProduct: (productName: string, productId: string) => void; + setProducts: (products: productsSchema) => void; removeProduct: (productId: string) => void; updateProduct: (productId: string, updates: Partial<{ productName: string; eventDatas: EventsSchema[] }>) => void; // Event-level actions addEvent: (productId: string, event: EventsSchema) => void; removeEvent: (productId: string, modelUuid: string) => void; - updateEvent: (productId: string, modelUuid: string, updates: Partial) => void; + deleteEvent: (modelUuid: string) => void; + updateEvent: (productId: string, modelUuid: string, updates: Partial) => EventsSchema | undefined; // Point-level actions addPoint: (productId: string, modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void; @@ -30,12 +32,12 @@ type ProductsStore = { modelUuid: string, pointUuid: string, action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] - ) => void; - removeAction: (actionUuid: string) => void; + ) => EventsSchema | undefined; + removeAction: (actionUuid: string) => EventsSchema | undefined; updateAction: ( actionUuid: string, updates: Partial - ) => void; + ) => EventsSchema | undefined; // Trigger-level actions addTrigger: ( @@ -50,7 +52,7 @@ type ProductsStore = { // Renaming functions renameProduct: (productId: string, newName: string) => void; - renameAction: (actionUuid: string, newName: string) => void; + renameAction: (actionUuid: string, newName: string) => EventsSchema | undefined; renameTrigger: (triggerUuid: string, newName: string) => void; // Helper functions @@ -78,6 +80,12 @@ export const useProductStore = create()( }); }, + setProducts: (products) => { + set((state) => { + state.products = products; + }); + }, + removeProduct: (productId) => { set((state) => { state.products = state.products.filter(p => p.productId !== productId); @@ -112,16 +120,27 @@ export const useProductStore = create()( }); }, + deleteEvent: (modelUuid: string) => { + set((state) => { + for (const product of state.products) { + product.eventDatas = product.eventDatas.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid); + } + }); + }, + updateEvent: (productId, modelUuid, updates) => { + let updatedEvent: EventsSchema | undefined; set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event) { Object.assign(event, updates); + updatedEvent = JSON.parse(JSON.stringify(event)); } } }); + return updatedEvent; }, // Point-level actions @@ -172,6 +191,7 @@ export const useProductStore = create()( // Action-level actions addAction: (productId, modelUuid, pointUuid, action) => { + let updatedEvent: EventsSchema | undefined; set((state) => { const product = state.products.find(p => p.productId === productId); if (product) { @@ -180,19 +200,24 @@ export const useProductStore = create()( const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); if (point) { point.action = action as any; + updatedEvent = JSON.parse(JSON.stringify(event)); } } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { if ('action' in (event as any).point) { (event as any).point.action = action; + updatedEvent = JSON.parse(JSON.stringify(event)); } else if ('actions' in (event as any).point) { (event as any).point.actions.push(action); + updatedEvent = JSON.parse(JSON.stringify(event)); } } } }); + return updatedEvent; }, removeAction: (actionUuid: string) => { + let updatedEvent: EventsSchema | undefined; set((state) => { for (const product of state.products) { for (const event of product.eventDatas) { @@ -203,20 +228,28 @@ export const useProductStore = create()( } else if ('point' in event) { const point = (event as any).point; if (event.type === "roboticArm") { - // Handle RoboticArmEventSchema if ('actions' in point) { - point.actions = point.actions.filter((a: any) => a.actionUuid !== actionUuid); + const index = point.actions.findIndex((a: any) => a.actionUuid === actionUuid); + if (index !== -1) { + point.actions.splice(index, 1); + updatedEvent = JSON.parse(JSON.stringify(event)); + return; + } } } else if ('action' in point && point.action?.actionUuid === actionUuid) { - // For other schemas with a single 'action' + point.action = undefined; + updatedEvent = JSON.parse(JSON.stringify(event)); + return; } } } } }); + return updatedEvent; }, updateAction: (actionUuid, updates) => { + let updatedEvent: EventsSchema | undefined; set((state) => { for (const product of state.products) { for (const event of product.eventDatas) { @@ -224,6 +257,7 @@ export const useProductStore = create()( for (const point of (event as ConveyorEventSchema).points) { if (point.action && point.action.actionUuid === actionUuid) { Object.assign(point.action, updates); + updatedEvent = JSON.parse(JSON.stringify(event)); return; } } @@ -231,11 +265,13 @@ export const useProductStore = create()( const point = (event as any).point; if ('action' in point && point.action.actionUuid === actionUuid) { Object.assign(point.action, updates); + updatedEvent = JSON.parse(JSON.stringify(event)); return; } else if ('actions' in point) { const action = point.actions.find((a: any) => a.actionUuid === actionUuid); if (action) { Object.assign(action, updates); + updatedEvent = JSON.parse(JSON.stringify(event)); return; } } @@ -243,6 +279,7 @@ export const useProductStore = create()( } } }); + return updatedEvent; }, // Trigger-level actions @@ -352,6 +389,7 @@ export const useProductStore = create()( }, renameAction: (actionUuid, newName) => { + let updatedEvent: EventsSchema | undefined; set((state) => { for (const product of state.products) { for (const event of product.eventDatas) { @@ -359,6 +397,7 @@ export const useProductStore = create()( for (const point of (event as ConveyorEventSchema).points) { if (point.action && point.action.actionUuid === actionUuid) { point.action.actionName = newName; + updatedEvent = JSON.parse(JSON.stringify(event)); return; } } @@ -366,11 +405,13 @@ export const useProductStore = create()( const point = (event as any).point; if ('action' in point && point.action.actionUuid === actionUuid) { point.action.actionName = newName; + updatedEvent = JSON.parse(JSON.stringify(event)); return; } else if ('actions' in point) { const action = point.actions.find((a: any) => a.actionUuid === actionUuid); if (action) { action.actionName = newName; + updatedEvent = JSON.parse(JSON.stringify(event)); return; } } @@ -378,6 +419,7 @@ export const useProductStore = create()( } } }); + return updatedEvent; }, renameTrigger: (triggerUuid, newName) => { @@ -433,7 +475,7 @@ export const useProductStore = create()( getPointByUuid: (productId, modelUuid, pointUuid) => { const event = get().getEventByModelUuid(productId, modelUuid); if (!event) return undefined; - + if ('points' in event) { return (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); } else if ('point' in event && (event as any).point.uuid === pointUuid) { diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts index 449ceb7..a5ea3be 100644 --- a/app/src/store/simulation/useVehicleStore.ts +++ b/app/src/store/simulation/useVehicleStore.ts @@ -22,6 +22,7 @@ interface VehiclesStore { ) => void; setVehicleActive: (modelUuid: string, isActive: boolean) => void; + updateSteeringAngle: (modelUuid: string, steeringAngle: number) => void; incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void; decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void; setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void; @@ -76,6 +77,15 @@ export const useVehicleStore = create()( }); }, + updateSteeringAngle: (modelUuid, steeringAngle) => { + set((state) => { + const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.point.action.steeringAngle = steeringAngle; + } + }); + }, + incrementVehicleLoad: (modelUuid, incrementBy) => { set((state) => { const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); diff --git a/app/src/styles/abstracts/variables.scss b/app/src/styles/abstracts/variables.scss index 2913425..f4a6495 100644 --- a/app/src/styles/abstracts/variables.scss +++ b/app/src/styles/abstracts/variables.scss @@ -16,12 +16,13 @@ $text-button-color: #f3f3fd; $text-color-dark: #f3f3fd; $text-disabled-dark: #6f6f7a; $input-text-color-dark: #b5b5c8; -$highlight-text-color-dark: #b392f0; +$highlight-text-color-dark: #d2baff; $text-button-color-dark: #f3f3fd; // background colors // ---------- light mode ---------- -$background-color: linear-gradient(-45deg, #fcfdfdcc 0%, #fcfdfd99 100%); +$background-color: linear-gradient(-45deg, #fcfdfd71 0%, #fcfdfd79 100%); +$background-color-solid-gradient: linear-gradient(-45deg, #fcfdfd 0%, #fcfdfd 100%); $background-color-solid: #fcfdfd; $background-color-secondary: #fcfdfd4d; $background-color-accent: #6f42c1; @@ -44,6 +45,7 @@ $background-radial-gray-gradient: radial-gradient( // ---------- dark mode ---------- $background-color-dark: linear-gradient(-45deg, #333333b3 0%, #2d2437b3 100%); +$background-color-solid-gradient-dark: linear-gradient(-45deg, #333333 0%, #2d2437 100%); $background-color-solid-dark: #19191d; $background-color-secondary-dark: #19191d99; $background-color-accent-dark: #6f42c1; @@ -105,19 +107,10 @@ $color5: #c7a8ff; // old variables $accent-color: #6f42c1; $accent-color-dark: #c4abf1; -$highlight-accent-color: #e0dfff; -$highlight-accent-color-dark: #403e6a; -// $background-color: #fcfdfd; -// $background-color-dark: #19191d; -// $background-color-secondary: #e1e0ff80; -// $background-color-secondary-dark: #39394f99; $background-color-gray: #f3f3f3; $background-color-gray-dark: #232323; -// $border-color: #e0dfff; -// $border-color-dark: #403e6a; - $shadow-color: #3c3c431a; $shadow-color-dark: #8f8f8f1a; diff --git a/app/src/styles/base/base.scss b/app/src/styles/base/base.scss index 10fb87c..bf53164 100644 --- a/app/src/styles/base/base.scss +++ b/app/src/styles/base/base.scss @@ -11,6 +11,7 @@ // background colors --background-color: #{$background-color}; --background-color-solid: #{$background-color-solid}; + --background-color-solid-gradient: #{$background-color-solid-gradient}; --background-color-secondary: #{$background-color-secondary}; --background-color-accent: #{$background-color-accent}; --background-color-button: #{$background-color-button}; @@ -61,6 +62,7 @@ // background colors --background-color: #{$background-color-dark}; + --background-color-solid-gradient: #{$background-color-solid-gradient-dark}; --background-color-solid: #{$background-color-solid-dark}; --background-color-secondary: #{$background-color-secondary-dark}; --background-color-accent: #{$background-color-accent-dark}; diff --git a/app/src/styles/components/input.scss b/app/src/styles/components/input.scss index b4e7651..e3b9585 100644 --- a/app/src/styles/components/input.scss +++ b/app/src/styles/components/input.scss @@ -51,9 +51,6 @@ input[type="number"] { -webkit-appearance: none; margin: 0; } - - // Firefox - -moz-appearance: textfield; } .input-value { @@ -105,7 +102,7 @@ input[type="number"] { .search-wrapper { position: sticky; top: 0; - padding: 8px 10px; + padding: 0px 10px; width: 100%; z-index: 1; @@ -140,15 +137,16 @@ input[type="number"] { .clear-button { @include flex-center; position: absolute; + top: 4px; right: 4px; - width: 24px; - height: 24px; + width: 21px; + height: 21px; border: none; + border-radius: #{$border-radius-large}; cursor: pointer; background: transparent; - &:hover { - background: var(--highlight-accent-color); + background: var(--background-color-secondary); } } } @@ -219,9 +217,9 @@ input[type="number"] { .regularDropdown-container { width: 100%; min-width: 80px; - padding: 2px 4px; + padding: 4px 8px; border: 1px solid var(--border-color); - border-radius: 6px; + border-radius: #{$border-radius-large}; position: relative; cursor: pointer; @@ -230,7 +228,7 @@ input[type="number"] { display: flex; justify-content: space-between; cursor: pointer; - border-radius: 6px; + border-radius: #{$border-radius-large}; } .dropdown-options { @@ -238,7 +236,7 @@ input[type="number"] { width: 100%; background: var(--background-color); border: 1px solid var(--border-color); - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-large}; z-index: 10; max-height: 200px; overflow-y: auto; @@ -255,7 +253,7 @@ input[type="number"] { padding: 2px 4px; cursor: pointer; flex-direction: row !important; - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-medium}; &:hover { color: var(--highlight-text-color); @@ -272,17 +270,19 @@ input[type="number"] { .input.default { width: 100%; position: relative; + @include flex-center; + gap: 6px; .dropdown { - top: 2px; - right: 2px; - position: absolute; - background: var(--highlight-accent-color); - border-radius: #{$border-radius-small}; - padding: 1px 4px; + height: 100%; + background: var(--background-color-drop-down-gradient); + border-radius: #{$border-radius-extra-large}; + padding: 1px 8px; + outline: 1px solid var(--border-color); .active-option { - color: var(--accent-color); + line-height: 22px; + color: var(--text-color); font-size: var(--font-size-small); } } @@ -304,10 +304,10 @@ input[type="number"] { .eye-picker-button { height: 24px; - min-width: 24px; + min-width: 36px; @include flex-center; - border-radius: #{$border-radius-small}; - background: var(--background-color-secondary); + border-radius: #{$border-radius-large}; + background: var(--background-color-drop-down-gradient); cursor: pointer; } @@ -326,6 +326,9 @@ input[type="number"] { background: var(--background-color) !important; border: 1px solid var(--border-color) !important; padding: 5px 10px; + cursor: pointer; + border-radius: #{$border-radius-extra-large}; + transition: background-color 0.3s ease; .label { white-space: nowrap; @@ -333,12 +336,6 @@ input[type="number"] { max-width: 80%; text-overflow: ellipsis; } - - // font-size: 12px; - cursor: pointer; - border-radius: 5px; - transition: background-color 0.3s ease; - &:hover { background: #333333; } @@ -354,7 +351,8 @@ input[type="number"] { right: -16px; background: var(--background-color); border: 1px solid var(--border-color); - border-radius: 5px; + border-radius: #{$border-radius-large}; + backdrop-filter: blur(18px); box-shadow: #{$box-shadow-medium}; z-index: 1000; min-width: 200px; @@ -364,13 +362,11 @@ input[type="number"] { .dropdown-content { display: flex; flex-direction: column; - gap: 6px; + padding: 2px; .nested-dropdown { margin-left: 0; } - - padding: 10px; } .loading { @@ -409,15 +405,16 @@ input[type="number"] { .dropdown-item { display: block; - padding: 5px 10px; + padding: 4px 10px; text-decoration: none; color: var(--text-color); font-size: var(--font-size-regular); cursor: pointer; transition: background-color 0.3s ease; - + border-radius: #{$border-radius-large}; &:hover { - background: var(--background-color); + color: var(--accent-color); + background: var(--highlight-accent-color); } } @@ -428,24 +425,25 @@ input[type="number"] { display: flex; align-items: center; justify-content: space-between; - padding: 5px 10px; + padding: 4px 10px; cursor: pointer; font-size: var(--font-size-regular); color: var(--text-color); transition: background-color 0.3s ease; - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-large}; .arrow-container { @include flex-center; } &:hover { - background: var(--background-color); + color: var(--accent-color); + background: var(--highlight-accent-color); } &.open { - color: var(--accent-color); - background: var(--highlight-accent-color); + color: var(--text-button-color); + background: var(--background-color-accent); } .icon { @@ -649,7 +647,7 @@ input[type="number"] { padding: 2px 32px; border: none; border-radius: #{$border-radius-large}; - color: var(--text-color); + color: var(--text-button-color); background: var(--background-color-button); transition: all 0.2s; cursor: pointer; diff --git a/app/src/styles/components/lists.scss b/app/src/styles/components/lists.scss index 3b52e69..894eac1 100644 --- a/app/src/styles/components/lists.scss +++ b/app/src/styles/components/lists.scss @@ -34,9 +34,8 @@ padding: 12px; } - .list-container { + li.list-container { padding: 2px; - // margin-left: 10px; overflow: hidden; .list-item { @@ -45,11 +44,13 @@ text-align: center; padding: 4px 8px; border-radius: #{$border-radius-large}; - - .value { - width: 100%; - text-align: start; - max-width: 180px; + .zone-header{ + @include flex-center; + .value { + width: 100%; + text-align: start; + max-width: 180px; + } } .options-container { @@ -61,11 +62,18 @@ cursor: pointer; } } + &:first-child{ + background: var(--highlight-accent-color); + .input-value{ + color: var(--highlight-text-color); + } + } } - .active { background: var(--highlight-accent-color); - color: var(--primary-color); + .input-value{ + color: var(--highlight-text-color); + } } } diff --git a/app/src/styles/components/marketPlace/marketPlace.scss b/app/src/styles/components/marketPlace/marketPlace.scss index b84a252..23b14b7 100644 --- a/app/src/styles/components/marketPlace/marketPlace.scss +++ b/app/src/styles/components/marketPlace/marketPlace.scss @@ -9,8 +9,8 @@ position: absolute; left: 0; top: 0; - padding: 100px 50px; - padding-bottom: 32px; + padding: 10px; + padding-top: 100px; .marketplace-container { position: relative; @@ -59,8 +59,9 @@ .regularDropdown-container { max-width: 159px; height: 100%; - border-radius: #{$border-radius-large}; + border-radius: #{$border-radius-extra-large}; border: 1px solid var(--border-color); + padding: 0 10px; .dropdown-header { align-items: center; } @@ -68,8 +69,9 @@ .button { padding: 5px 20px; - border: 1px solid var(--accent-color); border-radius: 14px; + background: var(--background-color-button); + color: var(--text-button-color); } .rating-container { @@ -106,14 +108,14 @@ .cards-wrapper-container { display: flex; flex-wrap: wrap; - gap: 28px; + gap: 18px; .card-container { - width: calc(25% - 23px); + width: calc(25% - 14px); border-radius: 18px; padding: 12px; box-shadow: 0px 2px 10.5px 0px #0000000d; - background: var(--background-color); + background: var(--background-color-solid-gradient); border: 1px solid var(--border-color); position: relative; display: flex; diff --git a/app/src/styles/components/menu/menu.scss b/app/src/styles/components/menu/menu.scss index be9e17f..dffc6a4 100644 --- a/app/src/styles/components/menu/menu.scss +++ b/app/src/styles/components/menu/menu.scss @@ -7,7 +7,7 @@ gap: 2px; position: relative; border-radius: #{$border-radius-extra-large}; - background: var(--background-color-drop-down); + background: var(--background-color-drop-down-gradient); padding: 3px 8px; width: fit-content; max-width: 100%; @@ -25,11 +25,12 @@ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + color: var(--text-color); } } .more-options-button { @include flex-center; - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-medium}; height: 22px; position: relative; &:hover { @@ -52,7 +53,7 @@ top: 32px; left: 0; z-index: 5; - background: var(--background-color); + background: var(--background-color-solid); color: var(--text-color); box-shadow: var(--box-shadow-light); border-radius: 8px; @@ -69,7 +70,7 @@ position: relative; height: 100%; padding: 4px 8px 4px 12px; - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-medium}; .menu-button { width: 100%; cursor: pointer; @@ -89,19 +90,21 @@ .dropdown-menu { position: absolute; top: 0; - left: 100%; - background: var(--background-color); + left: 103%; + background: var(--background-color-solid); min-width: 220px; - border-radius: 4px; + border-radius: #{$border-radius-medium}; box-shadow: var(--box-shadow-light); - border: 1px solid var(--background-color); + outline: 1px solid var(--border-color); + backdrop-filter: blur(20px); + outline-offset: -1px; z-index: 100; padding: 4px; .menu-item-container { position: relative; .menu-item { padding: 4px 8px 4px 12px; - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-medium}; display: flex; justify-content: space-between; align-items: center; @@ -138,18 +141,19 @@ .submenu { position: absolute; - left: 100%; + left: 102%; top: 0; - background: var(--background-color); + background: var(--background-color-solid); min-width: 200px; - border-radius: 0 4px 4px 4px; + border-radius: #{$border-radius-medium}; box-shadow: var(--box-shadow-light); - border: 1px solid var(--background-color); + outline: 1px solid var(--border-color); + outline-offset: -1px; z-index: 101; padding: 4px; .submenu-item { padding: 4px 8px 4px 12px; - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-medium}; display: flex; justify-content: space-between; align-items: center; diff --git a/app/src/styles/components/moduleToggle.scss b/app/src/styles/components/moduleToggle.scss index c864cbf..7e5b727 100644 --- a/app/src/styles/components/moduleToggle.scss +++ b/app/src/styles/components/moduleToggle.scss @@ -38,7 +38,7 @@ left: 0; width: 0%; height: 100%; - background: var(--highlight-accent-color); + background: var(--background-color-solid-gradient); transition: width 0.2s; border-radius: #{$border-radius-extra-large}; } diff --git a/app/src/styles/components/tools.scss b/app/src/styles/components/tools.scss index abea736..5984dab 100644 --- a/app/src/styles/components/tools.scss +++ b/app/src/styles/components/tools.scss @@ -16,6 +16,8 @@ background: var(--background-color); backdrop-filter: blur(8px); z-index: #{$z-index-default}; + outline: 1px solid var(--border-color); + outline-offset: -1px; .split { height: 20px; @@ -28,7 +30,7 @@ .general-options, .activeDropicon { @include flex-center; - gap: 8px; + gap: 2px; interpolate-size: allow-keywords; width: 0; opacity: 0; @@ -39,7 +41,7 @@ height: 28px; width: 28px; cursor: pointer; - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-medium}; &:hover { background: color-mix(in srgb, @@ -77,19 +79,20 @@ position: absolute; bottom: 40px; left: 0; - box-shadow: #{$box-shadow-medium}; - padding: 8px; - border-radius: #{$border-radius-large}; + padding: 2px 4px; + border-radius: #{$border-radius-medium}; background: var(--background-color); + backdrop-filter: blur(8px); .option-list { - margin: 4px 0; display: flex; align-items: center; white-space: nowrap; border-radius: #{$border-radius-medium}; gap: 6px; - padding: 4px; + padding: 2px; + padding-right: 12px; + margin: 2px 0; &:hover { background: var(--highlight-accent-color); @@ -116,10 +119,10 @@ .toggle-threed-button { @include flex-center; - padding: 3px; - border-radius: #{$border-radius-small}; - background: var(--highlight-accent-color); - gap: 2px; + padding: 4px; + border-radius: #{$border-radius-medium}; + background: var(--background-color); + gap: 5px; position: relative; .toggle-option { @@ -132,30 +135,25 @@ &::after { content: ""; position: absolute; - background: var(--accent-color); - left: 3px; - top: 3px; - height: 18px; - width: 18px; - border-radius: #{$border-radius-small}; + background: var(--background-color-accent); + left: 2px; + top: 2px; + height: 23px; + width: 23px; + border-radius: #{$border-radius-medium}; transition: all 0.2s; } .active { - color: var(--highlight-accent-color); + color: var(--text-button-color); } } .toggled { &::after { - left: 24px; + left: 25px; } } - - - - - } .exitPlay { diff --git a/app/src/styles/components/visualization/floating/common.scss b/app/src/styles/components/visualization/floating/common.scss index 0084e7a..0bbbdc9 100644 --- a/app/src/styles/components/visualization/floating/common.scss +++ b/app/src/styles/components/visualization/floating/common.scss @@ -182,7 +182,6 @@ background: var(--background-color-secondary); border-radius: 20px; color: var(--text-color); - background: #252525cc; .header-wrapper { width: 100%; @@ -276,7 +275,7 @@ .icon { width: 45px; height: 45px; - background: var(--accent-color); + background: var(--background-color-accent); display: flex; justify-content: center; align-items: center; diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 01715ec..c7f1694 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -7,7 +7,7 @@ top: 32px; left: 8px; background: var(--background-color); - backdrop-filter: blur(150px); + backdrop-filter: blur(15px); border-radius: #{$border-radius-extra-large}; outline: 1px solid var(--border-color); box-shadow: #{$box-shadow-medium}; @@ -30,10 +30,6 @@ padding: 0 8px; width: 100%; max-width: calc(100% - 32px); - - .input-value { - color: var(--accent-color); - } } } @@ -55,8 +51,6 @@ .active { background: var(--background-color-accent); - outline: 1px solid var(--border-color); - outline-offset: -1px; rect { stroke: var(--icon-default-color-active); } @@ -64,7 +58,12 @@ fill: var(--icon-default-color-active); } &:hover { - background: var(--background-color-secondary); + rect { + stroke: var(--icon-default-color); + } + circle { + fill: var(--icon-default-color); + } } } } @@ -235,7 +234,6 @@ .outline-container { height: 100%; - .outline-content-container { position: relative; height: 100%; @@ -256,7 +254,7 @@ top: 32px; right: 8px; background: var(--background-color); - backdrop-filter: blur(150px); + backdrop-filter: blur(15px); border-radius: #{$border-radius-extra-large}; outline: 1px solid var(--border-color); box-shadow: #{$box-shadow-medium}; @@ -276,7 +274,7 @@ .share-button { padding: 4px 12px; - color: var(--text-color); + color: var(--text-button-color); background: var(--background-color-button); font-weight: var(--font-weight-regular); border-radius: #{$border-radius-large}; @@ -370,14 +368,14 @@ width: 34px; border-radius: #{$border-radius-circle}; background: var(--background-color-secondary); - backdrop-filter: blur(8px); - box-shadow: #{$box-shadow-medium}; + backdrop-filter: blur(12px); outline: 1px solid var(--border-color); outline-offset: -1px; } .active { background: var(--background-color-accent); + outline: none; } } @@ -395,55 +393,43 @@ .no-event-selected { color: #666; - padding: 1.8rem 1rem; + padding: 16px; grid-column: 1 / -1; .products-list { padding-top: 1rem; + .product-item { + text-align: start; + margin-top: 8px; + padding: 2px 0; + text-decoration: none; + display: flex; + flex-wrap: wrap; + gap: 6px; + button { + width: fit-content; + position: relative; + @include flex-center; + gap: 4px; + background: var(--background-color); + padding: 8px 12px; + border-radius: #{$border-radius-extra-large}; + outline: 1px solid var(--border-color); + &:hover { + background: var(--background-color-accent); + color: var(--text-button-color); + outline: none; + path { + stroke: var(--text-button-color); + stroke-width: 1.3; + } + } + } + } .products-list-title { text-align: start; color: var(--accent-color); font-size: var(--font-size-regular); } - ul { - li { - text-align: start; - margin: 8px 0; - padding: 2px 0; - text-decoration: none; - &::marker { - content: ""; - } - button { - width: fit-content; - position: relative; - transition: all 0.2s ease; - @include flex-center; - gap: 4px; - &:before { - content: ""; - position: absolute; - left: 0; - bottom: -4px; - background: var(--accent-color); - height: 1px; - width: 0%; - transition: all 0.3s ease; - } - } - &:hover { - button { - path { - stroke: var(--accent-color); - strokeWidth: 1.5px; - } - color: var(--accent-color); - &:before { - width: 100%; - } - } - } - } - } } } } @@ -456,6 +442,9 @@ .sidebar-right-content-container { .dataSideBar { .inputs-wrapper { + display: flex; + flex-direction: column; + gap: 6px; .datas { .input-value { padding: 5px 10px; @@ -487,6 +476,7 @@ .datas__class { display: flex; align-items: center; + gap: 12px; .multi-level-dropdown { width: 170px; @@ -496,22 +486,13 @@ justify-content: space-between; gap: 6px; } - } - } - - .datas__class { - display: flex; - gap: 12px; - - // .datas__separator { - // } - - .disable { - cursor: not-allowed; - pointer-events: none; - /* Disables all mouse interactions */ - opacity: 0.5; - /* Optional: Makes the button look visually disabled */ + .disable { + cursor: not-allowed; + pointer-events: none; + /* Disables all mouse interactions */ + opacity: 0.5; + /* Optional: Makes the button look visually disabled */ + } } } } @@ -522,12 +503,6 @@ padding-bottom: 6px; } - .inputs-wrapper { - display: flex; - flex-direction: column; - gap: 6px; - } - .selectedMain-container { display: flex; flex-direction: column; @@ -627,10 +602,8 @@ width: 100%; height: 150px; background: #f0f0f0; - // border-radius: 8px; display: flex; align-items: center; - // justify-content: center; } .optionsContainer { @@ -713,7 +686,7 @@ path { stroke: var(--accent-color); - strokeWidth: 1.5px; + stroke-width: 1.5px; } &:hover { @@ -742,14 +715,14 @@ .add-button { @include flex-center; padding: 2px 4px; - background: var(--accent-color); - color: var(--primary-color); + background: var(--background-color-button); + color: var(--text-button-color); border-radius: #{$border-radius-small}; cursor: pointer; outline: none; border: none; path { - stroke: var(--primary-color); + stroke: var(--text-button-color); } &:disabled { background: var(--text-disabled); @@ -763,7 +736,7 @@ .value-field-container { margin: 0; input { - padding: 5px 4px; + padding: 5px 10px; } .dropdown { top: 4px; @@ -785,8 +758,8 @@ padding: 6px 12px; .regularDropdown-container { padding: 5px 8px; - outline: 2px solid var(--border-color); - outline-offset: -2px; + outline: 1px solid var(--border-color); + outline-offset: -1px; border: none; } } @@ -804,11 +777,10 @@ } .lists-main-container { - margin: 2px 8px; - width: calc(100% - 12px); - margin-right: 4px; + margin: 2px; + width: calc(100% - 4px); background: var(--background-color-gray); - border-radius: #{$border-radius-small}; + border-radius: 8px; min-height: 120px; .list-container { @@ -818,10 +790,9 @@ .list-item { @include flex-space-between; - padding: 2px 12px; + padding: 4px 12px; width: 100%; - margin: 2px 0; - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-medium}; .value { display: flex; justify-content: flex-start; @@ -953,6 +924,18 @@ } } + .trigger-wrapper { + .trigger-item { + .trigger-name { + padding: 8px; + margin-top: 4px; + } + .value-field-container { + margin: 0; + } + } + } + .footer { @include flex-center; justify-content: flex-start; @@ -962,10 +945,9 @@ } .compare-simulations-container { - margin: 6px; background: var(--background-color-gray); padding: 12px; - border-radius: #{$border-radius-medium}; + border-radius: #{$border-radius-large}; .compare-simulations-header { font-weight: var(--font-weight-medium); @@ -987,10 +969,12 @@ input { width: fit-content; - background: var(--accent-color); - color: var(--highlight-accent-color); - padding: 2px 8px; + background: var(--background-color-button); + color: var(--text-button-color); + padding: 3px 10px; cursor: pointer; + border: none; + outline: none; } } } @@ -1098,24 +1082,24 @@ input { border: none; + outline: none; cursor: pointer; - transition: all 0.2s; &:hover { - transform: translateY(-2px); box-shadow: #{$box-shadow-medium}; - outline: 1px solid var(--accent-color); + outline: 1px solid var(--input-border-color); } } .cancel { background: transparent; - color: var(--accent-color); + background: var(--background-color-secondary); + color: var(--text-color); } .submit { - background: var(--accent-color); - color: var(--highlight-accent-color); + background: var(--background-color-button); + color: var(--text-button-color); } } @@ -1123,7 +1107,7 @@ margin: 6px; background: var(--background-color-gray); padding: 12px; - border-radius: #{$border-radius-medium}; + border-radius: #{$border-radius-large}; .custom-analysis-header { font-weight: var(--font-weight-medium); @@ -1145,28 +1129,53 @@ input { width: fit-content; - background: var(--accent-color); - color: var(--highlight-accent-color); - padding: 2px 8px; + background: var(--background-color-button); + color: var(--text-button-color); + padding: 3px 10px; cursor: pointer; + border: none; + outline: none; } } } } } -.assets-container { - padding: 0 6px; +.assets-container-main { + width: 100%; + display: flex; + flex-direction: row; + flex-wrap: wrap; + height: 100%; + max-height: 50vh; + gap: 3px; + overflow: auto; + + .assets-result { + width: 100%; + .assets-wrapper { + margin: 0; + } + } + .assets-list-section { + width: 100%; + padding: 4px; + } .assets-wrapper { width: 100%; position: relative; - margin: 8px 10px; - h2 { + h2, + .searched-content { color: var(--text-color); font-family: $large; font-weight: $bold-weight; + padding: 8px; + @include flex-space-between; + .back-button { + cursor: pointer; + } } .categories-container { @@ -1175,14 +1184,16 @@ flex-direction: row; flex-wrap: wrap; height: 100%; - gap: 8px; - padding: 10px 0; + gap: 4px; + padding: 2px; .category { - width: 121px; + width: 123px; height: 95px; - border-radius: 3.59px; - background: var(--background-color-gray); + border-radius: #{$border-radius-large}; + background: var(--background-color); + outline: 1px solid var(--border-color); + outline-offset: -1px; padding: 8px; padding-top: 12px; font-weight: $bold-weight; @@ -1193,8 +1204,6 @@ position: relative; z-index: 3; font-size: var(--font-size-regular); - // -webkit-text-fill-color: transparent; - // -webkit-text-stroke: 1px black; } &::after { @@ -1260,7 +1269,6 @@ .category-image { position: absolute; - // top: 50%; bottom: 0; right: -10px; transform: translate(0, 0%) scale(0.8); @@ -1276,14 +1284,15 @@ flex-direction: row; flex-wrap: wrap; height: 100%; - gap: 3px; - padding: 10px 0; + gap: 6px; + padding: 2px; .assets { - width: 117px; + width: 122px; height: 95px; - border-radius: #{$border-radius-small}; - background: var(--background-color-gray); + border-radius: #{$border-radius-large}; + background: var(--background-color); + outline: 1px solid var(--border-color); font-weight: $medium-weight; position: relative; overflow: hidden; @@ -1301,18 +1310,20 @@ z-index: 3; padding: 8px; width: 100%; - max-height: 38px; + height: 100%; font-size: var(--font-size-regular); - background: color-mix( - in srgb, - var(--background-color) 40%, - transparent + background: linear-gradient( + 0deg, + rgba(37, 24, 51, 0) 0%, + rgba(78, 22, 128, 0.4) 100% ); - backdrop-filter: blur(5px); + pointer-events: none; + backdrop-filter: blur(8px); opacity: 0; transition: opacity 0.3s ease; display: -webkit-box; - -webkit-line-clamp: 2; + -webkit-line-clamp: 3; + line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis; @@ -1326,63 +1337,5 @@ } } } - - .back-button { - position: absolute; - top: 0; - right: 0; - @include flex-center; - cursor: pointer; - } - } -} - -.assets-container { - width: 100%; - display: flex; - flex-direction: row; - flex-wrap: wrap; - height: 100%; - gap: 3px; - padding: 10px 0; - - .assets { - width: 117px; - height: 95px; - border-radius: 3.59px; - background: var(--background-color-gray); - padding: 8px; - padding-top: 12px; - font-weight: $medium-weight; - position: relative; - overflow: hidden; - - .asset-name { - position: relative; - z-index: 3; - font-size: var(--font-size-regular); - } - - .asset-image { - height: 100%; - width: 100%; - position: absolute; - // top: 50%; - // right: 5px; - // transform: translate(0, -50%); - top: 0; - left: 0; - z-index: 2; - } - } -} - -.assets-result { - width: 100%; - height: 100%; - margin: 8px 10px; - - .assets-wrapper { - margin: 0; } } diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index e89b9a7..7348eff 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -4,7 +4,6 @@ // Main Container .realTime-viz { background: #131313; - border-radius: 20px; box-shadow: $box-shadow-medium; width: calc(100% - (320px + 270px + 90px)); height: calc(100% - (250px)); @@ -24,19 +23,15 @@ } .floating { - - width: calc(var(--realTimeViz-container-width) * 0.2); height: calc(var(--realTimeViz-container-width) * 0.05); min-width: 250px; max-width: 300px; - // min-height: 83px !important; - // max-height: 100px !important; - background: var(--background-color); - border: 1.23px solid var(--border-color); + backdrop-filter: blur(10px); + border: 1px solid var(--border-color); box-shadow: 0px 4.91px 4.91px 0px #0000001c; border-radius: $border-radius-medium; padding: 18px; @@ -67,12 +62,12 @@ .zone-wrapper { display: flex; background: var(--background-color); + backdrop-filter: blur(10px); position: absolute; bottom: 0px; left: 50%; gap: 6px; border-radius: 8px; - max-width: 80%; overflow: auto; max-width: calc(100% - 500px); min-width: 150px; @@ -117,15 +112,15 @@ } .active { - background: var(--accent-color); - color: var(--background-color); - // color: #FCFDFD !important; + background: var(--background-color-accent); + color: var(--text-button-color); + border: none; + outline: none; } } .zone-wrapper.bottom { bottom: var(--bottomWidth); - // bottom: 200px; } .content-container { @@ -146,7 +141,6 @@ display: flex; background: rgba(224, 223, 255, 0.5); position: absolute; - // bottom: 10px; left: 50%; transform: translate(-50%, 0); gap: 6px; @@ -189,7 +183,6 @@ border-radius: 6px; overflow: auto; z-index: $z-index-tools; - overflow: auto; &::-webkit-scrollbar { display: none; @@ -203,7 +196,8 @@ display: flex; flex-direction: column; gap: 6px; - // background: var(--background-color); + background: var(--background-color); + backdrop-filter: blur(10px); &::-webkit-scrollbar { display: none; @@ -211,12 +205,10 @@ .chart-container { width: 100%; - max-height: 100%; border: 1px dashed var(--background-color-gray); border-radius: 8px; box-shadow: var(--box-shadow-medium); - padding: 6px 0; background: var(--background-color); position: relative; padding: 0 10px; @@ -255,14 +247,11 @@ color: var(--text-color); &:hover { + background: var(--highlight-accent-color); + width: 100%; .label { color: var(--accent-color); } - } - - &:hover { - background: var(--highlight-accent-color); - width: 100%; svg { &:first-child { @@ -285,7 +274,6 @@ } } - .close-btn { position: absolute; top: 5px; @@ -369,7 +357,6 @@ .playingFlase { .zone-wrapper.bottom { bottom: var(--bottomWidth); - // bottom: 210px; } } @@ -402,7 +389,7 @@ } .active { - background: var(--accent-color); + background: var(--background-color-accent); } &:hover { @@ -417,8 +404,7 @@ height: 18px; display: flex; justify-content: center; - // align-items: center; - background: var(--accent-color); + background: var(--background-color-accent); border: none; color: var(--background-color); border-radius: 4px; @@ -426,24 +412,23 @@ .add-icon { @include flex-center; transition: rotate 0.2s; - } path { - stroke: var(--primary-color); + stroke: var(--text-color); stroke-width: 2; } } .active { - background: #ffe3e0; + background: #f657482f; .add-icon { rotate: 45deg; path { stroke: #f65648; - stroke-width: 2; + stroke-width: 1.3; } @@ -596,12 +581,6 @@ } .floating-wrapper { - .icon { - // width: 25px !important; - // height: 25px !important; - // background: transparent; - } - .kebab { width: 25px; height: 25px; @@ -647,9 +626,6 @@ .label { color: var(--accent-color); } - } - - &:hover { background: var(--highlight-accent-color); width: 100%; @@ -669,22 +645,19 @@ } .distance-line { - position: absolute; border-style: dashed; - border-color: var(--accent-color); - /* Green color for visibility */ + border-color: var(--background-color-accent); border-width: 1px; pointer-events: none; - /* Ensure lins don't interfere with dragging */ z-index: 10000; } /* Label styles for displaying distance values */ .distance-label { position: absolute; - background: var(--accent-color); - color: white; + background: var(--background-color-accent); + color: var(--text-button-color); font-size: 12px; padding: 2px 6px; border-radius: 3px; @@ -756,15 +729,12 @@ } .activeChart { - outline: 2px solid var(--accent-color); + outline: 1px solid var(--highlight-secondary-color); z-index: 2 !important; } .chart-container.notLinked { - outline: 1px solid red; - - } .connectionSuccess { @@ -983,4 +953,4 @@ opacity: 0; transform: scaleY(0); } -} \ No newline at end of file +} diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 811812d..cb71864 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -14,7 +14,7 @@ interface TriggerSchema { triggeredAsset: { triggeredModel: { modelName: string, modelUuid: string }; triggeredPoint: { pointName: string, pointUuid: string }; - triggeredAction: { actionName: string, actionUuid: string }; + triggeredAction: { actionName: string, actionUuid: string } | null; } | null; } @@ -44,6 +44,7 @@ interface VehiclePointSchema { actionType: "travel"; unLoadDuration: number; loadCapacity: number; + steeringAngle: number; pickUpPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null; unLoadPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null; triggers: TriggerSchema[]; diff --git a/app/src/types/world/worldTypes.d.ts b/app/src/types/world/worldTypes.d.ts index fa6c129..c148038 100644 --- a/app/src/types/world/worldTypes.d.ts +++ b/app/src/types/world/worldTypes.d.ts @@ -189,13 +189,26 @@ export type RefTubeGeometry = React.MutableRefObject; // Type for individual items placed on the floor, with positioning and rotation metadata export type FloorItemType = { - modeluuid: string; - modelname: string; + modelUuid: string; + modelName: string; position: [number, number, number]; rotation: { x: number; y: number; z: number }; modelfileID: string; isLocked: boolean; isVisible: boolean; + eventData?: { + type: string; + point?: { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; + } + points?: { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; + }[]; + } }; // Array of floor items for managing multiple objects on the floor @@ -225,8 +238,8 @@ export type AssetConfigurations = { [key: string]: AssetConfiguration; }; interface WallItem { type: "Fixed-Move" | "Free-Move" | undefined; model?: THREE.Group; - modeluuid?: string; - modelname?: string; + modelUuid?: string; + modelName?: string; scale?: [number, number, number]; csgscale?: [number, number, number]; csgposition?: [number, number, number]; diff --git a/app/src/utils/indexDB/idbUtils.ts b/app/src/utils/indexDB/idbUtils.ts index c9228d3..24b1448 100644 --- a/app/src/utils/indexDB/idbUtils.ts +++ b/app/src/utils/indexDB/idbUtils.ts @@ -3,43 +3,43 @@ const STORE_NAME = 'models'; const DB_VERSION = 1; export function initializeDB(): Promise { - return new Promise((resolve, reject) => { - const request = indexedDB.open(DB_NAME, DB_VERSION); + return new Promise((resolve, reject) => { + const request = indexedDB.open(DB_NAME, DB_VERSION); - request.onupgradeneeded = () => { - const db = request.result; - if (!db.objectStoreNames.contains(STORE_NAME)) { - db.createObjectStore(STORE_NAME); - } - }; + request.onupgradeneeded = () => { + const db = request.result; + if (!db.objectStoreNames.contains(STORE_NAME)) { + db.createObjectStore(STORE_NAME); + } + }; - request.onsuccess = () => resolve(request.result); - request.onerror = () => reject(request.error); - }); + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }); } export async function storeGLTF(key: string, file: Blob): Promise { - const db = await initializeDB(); + const db = await initializeDB(); - return new Promise((resolve, reject) => { - const transaction = db.transaction(STORE_NAME, 'readwrite'); - const store = transaction.objectStore(STORE_NAME); - const request = store.put(file, key); + return new Promise((resolve, reject) => { + const transaction = db.transaction(STORE_NAME, 'readwrite'); + const store = transaction.objectStore(STORE_NAME); + const request = store.put(file, key); - request.onsuccess = () => resolve(); - request.onerror = () => reject(request.error); - }); + request.onsuccess = () => resolve(); + request.onerror = () => reject(request.error); + }); } export async function retrieveGLTF(key: string): Promise { - const db = await initializeDB(); + const db = await initializeDB(); - return new Promise((resolve, reject) => { - const transaction = db.transaction(STORE_NAME, 'readonly'); - const store = transaction.objectStore(STORE_NAME); - const request = store.get(key); + return new Promise((resolve, reject) => { + const transaction = db.transaction(STORE_NAME, 'readonly'); + const store = transaction.objectStore(STORE_NAME); + const request = store.get(key); - request.onsuccess = () => resolve(request.result as Blob | undefined); - request.onerror = () => reject(request.error); - }); + request.onsuccess = () => resolve(request.result as Blob | undefined); + request.onerror = () => reject(request.error); + }); } \ No newline at end of file