Refactor mechanics components to use ActionsList for action management

- Consolidated action handling logic into a new ActionsList component for better code organization and reusability.
- Updated RoboticArmMechanics, StorageMechanics, and VehicleMechanics to utilize the new ActionsList component.
- Improved state management and action updates within the mechanics components.
- Enhanced UI responsiveness and styling in sidebar and real-time visualization pages.
This commit is contained in:
Vishnu 2025-04-28 18:08:27 +05:30
parent 5b6badaa52
commit 897633d4cc
10 changed files with 1192 additions and 948 deletions

View File

@ -1,148 +1,161 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import Header from "./Header"; import Header from "./Header";
import useModuleStore, { import useModuleStore, {
useSubModuleStore, useSubModuleStore,
} from "../../../store/useModuleStore"; } from "../../../store/useModuleStore";
import { import {
AnalysisIcon, AnalysisIcon,
MechanicsIcon, MechanicsIcon,
PropertiesIcon, PropertiesIcon,
SimulationIcon, SimulationIcon,
} from "../../icons/SimulationIcons"; } from "../../icons/SimulationIcons";
import useToggleStore from "../../../store/useUIToggleStore"; import useToggleStore from "../../../store/useUIToggleStore";
import Visualization from "./visualization/Visualization"; import Visualization from "./visualization/Visualization";
import Analysis from "./analysis/Analysis"; import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations"; import Simulations from "./simulation/Simulations";
import { useSelectedFloorItem } from "../../../store/store"; import { useSelectedFloorItem } from "../../../store/store";
import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; import {
useSelectedEventData,
useSelectedEventSphere,
} from "../../../store/simulation/useSimulationStore";
import GlobalProperties from "./properties/GlobalProperties"; import GlobalProperties from "./properties/GlobalProperties";
import AsstePropertiies from "./properties/AssetProperties"; import AsstePropertiies from "./properties/AssetProperties";
import ZoneProperties from "./properties/ZoneProperties"; import ZoneProperties from "./properties/ZoneProperties";
import EventProperties from "./properties/eventProperties/EventProperties"; import EventProperties from "./properties/eventProperties/EventProperties";
const SideBarRight: React.FC = () => { const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const { toggleUI } = useToggleStore(); const { toggleUI } = useToggleStore();
const { subModule, setSubModule } = useSubModuleStore(); const { subModule, setSubModule } = useSubModuleStore();
const { selectedFloorItem } = useSelectedFloorItem(); const { selectedFloorItem } = useSelectedFloorItem();
const { selectedEventData } = useSelectedEventData(); const { selectedEventData } = useSelectedEventData();
const { selectedEventSphere } = useSelectedEventSphere(); const { selectedEventSphere } = useSelectedEventSphere();
// Reset activeList whenever activeModule changes // Reset activeList whenever activeModule changes
useEffect(() => { useEffect(() => {
if (activeModule !== "simulation") setSubModule("properties"); if (activeModule !== "simulation") setSubModule("properties");
if (activeModule === "simulation") setSubModule("simulations"); if (activeModule === "simulation") setSubModule("simulations");
}, [activeModule]); }, [activeModule, setSubModule]);
useEffect(() => { useEffect(() => {
if (activeModule !== "mechanics" && selectedEventData && selectedEventSphere) { if (
setSubModule("mechanics"); activeModule !== "mechanics" &&
} else if (!selectedEventData && !selectedEventSphere) { selectedEventData &&
if (activeModule === 'simulation') { selectedEventSphere
setSubModule("simulations"); ) {
} setSubModule("mechanics");
}; } else if (!selectedEventData && !selectedEventSphere) {
}, [activeModule, selectedEventData, selectedEventSphere]) if (activeModule === "simulation") {
setSubModule("simulations");
}
}
}, [activeModule, selectedEventData, selectedEventSphere, setSubModule]);
return ( return (
<div className="sidebar-right-wrapper"> <div className="sidebar-right-wrapper">
<Header /> <Header />
{toggleUI && ( {toggleUI && (
<div className="sidebar-actions-container"> <div className="sidebar-actions-container">
<div {activeModule !== "simulation" && (
className={`sidebar-action-list ${subModule === "properties" ? "active" : "" <button
}`} className={`sidebar-action-list ${
onClick={() => setSubModule("properties")} subModule === "properties" ? "active" : ""
> }`}
<PropertiesIcon isActive={subModule === "properties"} /> onClick={() => setSubModule("properties")}
</div> >
{activeModule === "simulation" && ( <PropertiesIcon isActive={subModule === "properties"} />
<> </button>
<div )}
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : "" {activeModule === "simulation" && (
}`} <>
onClick={() => setSubModule("mechanics")} <button
> className={`sidebar-action-list ${
<MechanicsIcon isActive={subModule === "mechanics"} /> subModule === "simulations" ? "active" : ""
</div> }`}
<div onClick={() => setSubModule("simulations")}
className={`sidebar-action-list ${subModule === "simulations" ? "active" : "" >
}`} <SimulationIcon isActive={subModule === "simulations"} />
onClick={() => setSubModule("simulations")} </button>
> <button
<SimulationIcon isActive={subModule === "simulations"} /> className={`sidebar-action-list ${
</div> subModule === "mechanics" ? "active" : ""
<div }`}
className={`sidebar-action-list ${subModule === "analysis" ? "active" : "" onClick={() => setSubModule("mechanics")}
}`} >
onClick={() => setSubModule("analysis")} <MechanicsIcon isActive={subModule === "mechanics"} />
> </button>
<AnalysisIcon isActive={subModule === "analysis"} /> <button
</div> className={`sidebar-action-list ${
</> subModule === "analysis" ? "active" : ""
)} }`}
</div> onClick={() => setSubModule("analysis")}
)} >
{/* process builder */} <AnalysisIcon isActive={subModule === "analysis"} />
{toggleUI && </button>
subModule === "properties" && </>
activeModule !== "visualization" && )}
!selectedFloorItem && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<GlobalProperties />
</div>
</div>
)}
{toggleUI &&
subModule === "properties" &&
activeModule !== "visualization" &&
selectedFloorItem && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<AsstePropertiies />
</div>
</div>
)}
{toggleUI &&
subModule === "zoneProperties" &&
(activeModule === "builder" || activeModule === "simulation") && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<ZoneProperties />
</div>
</div>
)}
{/* simulation */}
{toggleUI && activeModule === "simulation" && (
<>
{subModule === "simulations" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<Simulations />
</div>
</div>
)}
{subModule === "mechanics" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<EventProperties />
</div>
</div>
)}
{subModule === "analysis" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<Analysis />
</div>
</div>
)}
</>
)}
{/* realtime visualization */}
{toggleUI && activeModule === "visualization" && <Visualization />}
</div> </div>
); )}
{/* process builder */}
{toggleUI &&
subModule === "properties" &&
activeModule !== "visualization" &&
!selectedFloorItem && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<GlobalProperties />
</div>
</div>
)}
{toggleUI &&
subModule === "properties" &&
activeModule !== "visualization" &&
selectedFloorItem && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<AsstePropertiies />
</div>
</div>
)}
{toggleUI &&
subModule === "zoneProperties" &&
(activeModule === "builder" || activeModule === "simulation") && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<ZoneProperties />
</div>
</div>
)}
{/* simulation */}
{toggleUI && activeModule === "simulation" && (
<>
{subModule === "simulations" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<Simulations />
</div>
</div>
)}
{subModule === "mechanics" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<EventProperties />
</div>
</div>
)}
{subModule === "analysis" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<Analysis />
</div>
</div>
)}
</>
)}
{/* realtime visualization */}
{toggleUI && activeModule === "visualization" && <Visualization />}
</div>
);
}; };
export default SideBarRight; export default SideBarRight;

View File

@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { import {
useSelectedEventData, useSelectedEventData,
useSelectedEventSphere,
useSelectedProduct, useSelectedProduct,
} from "../../../../../store/simulation/useSimulationStore"; } from "../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../store/simulation/useProductStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore";
@ -9,6 +10,7 @@ import VehicleMechanics from "./mechanics/vehicleMechanics";
import RoboticArmMechanics from "./mechanics/roboticArmMechanics"; import RoboticArmMechanics from "./mechanics/roboticArmMechanics";
import MachineMechanics from "./mechanics/machineMechanics"; import MachineMechanics from "./mechanics/machineMechanics";
import StorageMechanics from "./mechanics/storageMechanics"; import StorageMechanics from "./mechanics/storageMechanics";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
const EventProperties: React.FC = () => { const EventProperties: React.FC = () => {
const { selectedEventData } = useSelectedEventData(); const { selectedEventData } = useSelectedEventData();
@ -18,13 +20,15 @@ const EventProperties: React.FC = () => {
null null
); );
const [assetType, setAssetType] = useState<string | null>(null); const [assetType, setAssetType] = useState<string | null>(null);
const { products } = useProductStore();
const { selectedEventSphere } = useSelectedEventSphere();
useEffect(() => { useEffect(() => {
const event = getCurrentEventData(); const event = getCurrentEventData();
setCurrentEventData(event); setCurrentEventData(event);
const type = determineAssetType(event); const type = determineAssetType(event);
setAssetType(type); setAssetType(type);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedEventData, selectedProduct]); }, [selectedEventData, selectedProduct]);
const getCurrentEventData = () => { const getCurrentEventData = () => {
@ -72,6 +76,39 @@ const EventProperties: React.FC = () => {
{assetType === "storageUnit" && <StorageMechanics />} {assetType === "storageUnit" && <StorageMechanics />}
</> </>
)} )}
{!currentEventData && selectedEventSphere && (
<div className="no-event-selected">
<p>
<strong>Oops!</strong> It looks like this object doesn't have an
event assigned yet. To continue, please link it to one of the
products below.
</p>
<div className="products-list">
<p>
<strong>Here are some products you can add it to:</strong>
</p>
<ul>
{products.map((product) => (
<li key={product.productId}>
<button>
<AddIcon />
{product.productName}
</button>
</li>
))}
</ul>
</div>
</div>
)}
{!selectedEventSphere && (
<div className="no-event-selected">
<p>
<strong>Oops!</strong> It looks like you haven't selected an event
point yet. Please select an event to view its properties.
</p>
</div>
)}
</div> </div>
); );
}; };

View File

@ -0,0 +1,197 @@
import React, { useRef } from "react";
import {
AddIcon,
RemoveIcon,
ResizeHeightIcon,
} from "../../../../../icons/ExportCommonIcons";
import RenameInput from "../../../../../ui/inputs/RenameInput";
import { handleResize } from "../../../../../../functions/handleResizePannel";
import {
useSelectedAction,
useSelectedEventData,
useSelectedProduct,
} from "../../../../../../store/simulation/useSimulationStore";
import { MathUtils } from "three";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
interface ActionsListProps {
setSelectedPointData: (data: any) => void; // You can replace `any` with a more specific type if you have one
selectedPointData: any; // You can replace `any` with a more specific type if you have one
// ui control props
multipleAction?: boolean;
}
const ActionsList: React.FC<ActionsListProps> = ({
setSelectedPointData,
selectedPointData,
multipleAction = false,
}) => {
const actionsContainerRef = useRef<HTMLDivElement>(null);
// store
const { selectedEventData } = useSelectedEventData();
const { updateAction, addAction, removeAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
const { selectedAction, setSelectedAction, clearSelectedAction } =
useSelectedAction();
const handleAddAction = () => {
if (!selectedEventData || !selectedPointData) return;
const newAction = {
actionUuid: MathUtils.generateUUID(),
actionName: `Action ${selectedPointData.actions.length + 1}`,
actionType: "pickAndPlace" as const,
process: {
startPoint: null,
endPoint: null,
},
triggers: [] as TriggerSchema[],
};
addAction(
selectedProduct.productId,
selectedEventData.data.modelUuid,
selectedEventData.selectedPoint,
newAction
);
const updatedPoint = {
...selectedPointData,
actions: [...selectedPointData.actions, newAction],
};
setSelectedPointData(updatedPoint);
setSelectedAction(newAction.actionUuid, newAction.actionName);
};
const handleDeleteAction = (actionUuid: string) => {
if (!selectedPointData) return;
removeAction(actionUuid);
const newActions = selectedPointData.actions.filter(
(a: any) => a.actionUuid !== actionUuid
);
const updatedPoint = {
...selectedPointData,
actions: newActions,
};
setSelectedPointData(updatedPoint);
if (selectedAction.actionId === actionUuid) {
if (newActions.length > 0) {
setSelectedAction(newActions[0].actionUuid, newActions[0].actionName);
} else {
clearSelectedAction();
}
}
};
const handleRenameAction = (newName: string) => {
if (!selectedAction.actionId) return;
updateAction(selectedAction.actionId, { actionName: newName });
if (selectedPointData?.actions) {
const updatedActions = selectedPointData.actions.map((action: any) =>
action.actionUuid === selectedAction.actionId
? { ...action, actionName: newName }
: action
);
setSelectedPointData({
...selectedPointData,
actions: updatedActions,
});
} else {
// write logic for single action
return;
}
};
const handleActionSelect = (actionUuid: string, actionName: string) => {
setSelectedAction(actionUuid, actionName);
};
return (
<div className="actions-list-container">
<div className="actions">
<div className="header">
<div className="header-value">Actions</div>
{multipleAction && (
<button className="add-button" onClick={() => handleAddAction()}>
<AddIcon /> Add
</button>
)}
</div>
<div
className="lists-main-container"
ref={actionsContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{multipleAction &&
selectedPointData.actions.map((action: any) => (
<div
key={action.actionUuid}
className={`list-item ${
selectedAction.actionId === action.actionUuid
? "active"
: ""
}`}
>
<button
className="value"
onClick={() =>
handleActionSelect(action.actionUuid, action.actionName)
}
>
<RenameInput
value={action.actionName}
onRename={handleRenameAction}
/>
</button>
{selectedPointData.actions.length > 1 && (
<button
className="remove-button"
onClick={() => handleDeleteAction(action.actionUuid)}
>
<RemoveIcon />
</button>
)}
</div>
))}
{!multipleAction && selectedPointData && (
<div
key={selectedPointData.action.actionUuid}
className={`list-item active`}
>
<button
className="value"
onClick={() =>
handleActionSelect(
selectedPointData.action.actionUuid,
selectedPointData.action.actionName
)
}
>
<RenameInput
value={selectedPointData.action.actionName}
onRename={handleRenameAction}
/>
</button>
</div>
)}
</div>
<button
className="resize-icon"
id="action-resize"
onMouseDown={(e: any) => handleResize(e, actionsContainerRef)}
>
<ResizeHeightIcon />
</button>
</div>
</div>
</div>
);
};
export default ActionsList;

View File

@ -1,212 +1,224 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from "react";
import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import DelayAction from '../actions/DelayAction' import DelayAction from "../actions/DelayAction";
import RenameInput from '../../../../../ui/inputs/RenameInput' import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import DespawnAction from '../actions/DespawnAction' import DespawnAction from "../actions/DespawnAction";
import SwapAction from '../actions/SwapAction' import SwapAction from "../actions/SwapAction";
import SpawnAction from '../actions/SpawnAction' import SpawnAction from "../actions/SpawnAction";
import DefaultAction from '../actions/DefaultAction' import DefaultAction from "../actions/DefaultAction";
import Trigger from '../trigger/Trigger' 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 { useProductStore } from "../../../../../../store/simulation/useProductStore";
import ActionsList from "../components/ActionsList";
function ConveyorMechanics() { function ConveyorMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default"); const [activeOption, setActiveOption] = useState<
const [selectedPointData, setSelectedPointData] = useState<ConveyorPointSchema | undefined>(); "default" | "spawn" | "swap" | "delay" | "despawn"
const { selectedEventData } = useSelectedEventData(); >("default");
const { getPointByUuid, updateEvent, updateAction } = useProductStore(); const [selectedPointData, setSelectedPointData] = useState<
const { selectedProduct } = useSelectedProduct(); ConveyorPointSchema | undefined
>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
useEffect(() => { useEffect(() => {
if (selectedEventData) { if (selectedEventData) {
const point = getPointByUuid( const point = getPointByUuid(
selectedProduct.productId, selectedProduct.productId,
selectedEventData?.data.modelUuid, selectedEventData?.data.modelUuid,
selectedEventData?.selectedPoint selectedEventData?.selectedPoint
) as ConveyorPointSchema | undefined; ) as ConveyorPointSchema | undefined;
if (point && 'action' in point) { if (point && "action" in point) {
setSelectedPointData(point); setSelectedPointData(point);
setActiveOption(point.action.actionType as "default" | "spawn" | "swap" | "delay" | "despawn"); setActiveOption(
} point.action.actionType as
} | "default"
}, [selectedProduct, selectedEventData]) | "spawn"
| "swap"
const handleSpeedChange = (value: string) => { | "delay"
if (!selectedEventData) return; | "despawn"
updateEvent(
selectedProduct.productId,
selectedEventData.data.modelUuid,
{ speed: parseFloat(value) }
); );
}; }
}
}, [selectedProduct, selectedEventData, getPointByUuid]);
const handleActionTypeChange = (option: string) => { const handleSpeedChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return; if (!selectedEventData) return;
const validOption = option as "default" | "spawn" | "swap" | "delay" | "despawn"; updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
setActiveOption(validOption); speed: parseFloat(value),
});
};
updateAction( const handleActionTypeChange = (option: string) => {
selectedPointData.action.actionUuid, if (!selectedEventData || !selectedPointData) return;
{ actionType: validOption } const validOption = option as
); | "default"
}; | "spawn"
| "swap"
| "delay"
| "despawn";
setActiveOption(validOption);
const handleRenameAction = (newName: string) => { updateAction(selectedPointData.action.actionUuid, {
if (!selectedPointData) return; actionType: validOption,
updateAction( });
selectedPointData.action.actionUuid, };
{ actionName: newName }
);
};
const handleSpawnCountChange = (value: string) => { const handleRenameAction = (newName: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
updateAction( updateAction(selectedPointData.action.actionUuid, { actionName: newName });
selectedPointData.action.actionUuid, };
{ spawnCount: value === "inherit" ? "inherit" : parseFloat(value) }
);
};
const handleSpawnIntervalChange = (value: string) => { const handleSpawnCountChange = (value: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
updateAction( updateAction(selectedPointData.action.actionUuid, {
selectedPointData.action.actionUuid, spawnCount: value === "inherit" ? "inherit" : parseFloat(value),
{ spawnInterval: value === "inherit" ? "inherit" : parseFloat(value) } });
); };
};
const handleMaterialSelect = (material: string) => { const handleSpawnIntervalChange = (value: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
updateAction( updateAction(selectedPointData.action.actionUuid, {
selectedPointData.action.actionUuid, spawnInterval: value === "inherit" ? "inherit" : parseFloat(value),
{ material } });
); };
};
const handleDelayChange = (value: string) => { const handleMaterialSelect = (material: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
updateAction( updateAction(selectedPointData.action.actionUuid, { material });
selectedPointData.action.actionUuid, };
{ delay: value === "inherit" ? "inherit" : parseFloat(value) }
);
};
const availableActions = { const handleDelayChange = (value: string) => {
defaultOption: "default", if (!selectedPointData) return;
options: ["default", "spawn", "swap", "delay", "despawn"], updateAction(selectedPointData.action.actionUuid, {
}; delay: value === "inherit" ? "inherit" : parseFloat(value),
});
};
// Get current values from store const availableActions = {
const currentSpeed = selectedEventData?.data.type === "transfer" defaultOption: "default",
? selectedEventData.data.speed.toString() options: ["default", "spawn", "swap", "delay", "despawn"],
: "0.5"; };
const currentActionName = selectedPointData // Get current values from store
? selectedPointData.action.actionName const currentSpeed =
: "Action Name"; selectedEventData?.data.type === "transfer"
? selectedEventData.data.speed.toString()
: "0.5";
const currentMaterial = selectedPointData const currentActionName = selectedPointData
? selectedPointData.action.material ? selectedPointData.action.actionName
: "Default material"; : "Action Name";
const currentSpawnCount = selectedPointData const currentMaterial = selectedPointData
? selectedPointData.action.spawnCount?.toString() || "1" ? selectedPointData.action.material
: "1"; : "Default material";
const currentSpawnInterval = selectedPointData const currentSpawnCount = selectedPointData
? selectedPointData.action.spawnInterval?.toString() || "1" ? selectedPointData.action.spawnCount?.toString() || "1"
: "1"; : "1";
const currentDelay = selectedPointData const currentSpawnInterval = selectedPointData
? selectedPointData.action.delay?.toString() || "0" ? selectedPointData.action.spawnInterval?.toString() || "1"
: "0"; : "1";
return ( const currentDelay = selectedPointData
? selectedPointData.action.delay?.toString() || "0"
: "0";
return (
<>
{selectedEventData && (
<> <>
{selectedEventData && <div key={selectedPointData?.uuid} className="global-props">
<> <div className="property-list-container">
<div key={selectedPointData?.uuid} className="global-props"> <div className="property-item">
<div className="property-list-container"> <InputWithDropDown
<div className="property-item"> label="Speed"
<InputWithDropDown value={currentSpeed}
label="Speed" min={0}
value={currentSpeed} step={0.1}
min={0} defaultValue={"0.5"}
step={0.1} max={10}
defaultValue={"0.5"} activeOption="m/s"
max={10} onClick={() => {}}
activeOption="m/s" onChange={handleSpeedChange}
onClick={() => { }} />
onChange={handleSpeedChange} </div>
/> </div>
</div> </div>
</div>
</div>
<div className="selected-actions-details"> <ActionsList
<div className="selected-actions-header"> setSelectedPointData={setSelectedPointData}
<RenameInput selectedPointData={selectedPointData}
value={currentActionName} />
onRename={handleRenameAction}
/> <div className="selected-actions-details">
</div> <div className="selected-actions-header">
<div className="selected-actions-list"> <RenameInput
<LabledDropdown value={currentActionName}
defaultOption={selectedPointData onRename={handleRenameAction}
? selectedPointData.action.actionType />
: "default"} </div>
options={availableActions.options} <div className="selected-actions-list">
onSelect={handleActionTypeChange} <LabledDropdown
/> defaultOption={
{activeOption === "default" && selectedPointData
<DefaultAction /> ? selectedPointData.action.actionType
} : "default"
{activeOption === "spawn" && }
<SpawnAction options={availableActions.options}
onChangeCount={handleSpawnCountChange} onSelect={handleActionTypeChange}
options={["Default material", "Material 1", "Material 2"]} />
defaultOption={currentMaterial} {activeOption === "default" && <DefaultAction />}
onSelect={handleMaterialSelect} {activeOption === "spawn" && (
onChangeInterval={handleSpawnIntervalChange} <SpawnAction
intervalValue={currentSpawnInterval} onChangeCount={handleSpawnCountChange}
countValue={currentSpawnCount} options={["Default material", "Material 1", "Material 2"]}
intervalMin={1} defaultOption={currentMaterial}
intervalMax={60} onSelect={handleMaterialSelect}
intervalDefaultValue="1" onChangeInterval={handleSpawnIntervalChange}
countMin={1} intervalValue={currentSpawnInterval}
countMax={100} countValue={currentSpawnCount}
countDefaultValue="1" intervalMin={1}
/> intervalMax={60}
} intervalDefaultValue="1"
{activeOption === "swap" && countMin={1}
<SwapAction countMax={100}
options={["Default material", "Material 1", "Material 2"]} countDefaultValue="1"
defaultOption={currentMaterial} />
onSelect={handleMaterialSelect} )}
/> {activeOption === "swap" && (
} <SwapAction
{activeOption === "despawn" && options={["Default material", "Material 1", "Material 2"]}
<DespawnAction /> defaultOption={currentMaterial}
} onSelect={handleMaterialSelect}
{activeOption === "delay" && />
<DelayAction )}
value={currentDelay} {activeOption === "despawn" && <DespawnAction />}
defaultValue="0" {activeOption === "delay" && (
min={0} <DelayAction
max={60} value={currentDelay}
onChange={handleDelayChange} defaultValue="0"
/> min={0}
} max={60}
</div> onChange={handleDelayChange}
</div> />
<div className="tirgger"> )}
<Trigger /> </div>
</div> </div>
</> <div className="tirgger">
} <Trigger />
</div>
</> </>
) )}
</>
);
} }
export default ConveyorMechanics export default ConveyorMechanics;

View File

@ -1,123 +1,129 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from "react";
import RenameInput from '../../../../../ui/inputs/RenameInput' import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from '../trigger/Trigger' 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 { useProductStore } from "../../../../../../store/simulation/useProductStore";
import ProcessAction from '../actions/ProcessAction' import ProcessAction from "../actions/ProcessAction";
import ActionsList from "../components/ActionsList";
function MachineMechanics() { function MachineMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "process">("default"); const [activeOption, setActiveOption] = useState<"default" | "process">(
const [selectedPointData, setSelectedPointData] = useState<MachinePointSchema | undefined>(); "default"
const { selectedEventData } = useSelectedEventData(); );
const { getPointByUuid, updateAction } = useProductStore(); const [selectedPointData, setSelectedPointData] = useState<
const { selectedProduct } = useSelectedProduct(); MachinePointSchema | undefined
>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
useEffect(() => { useEffect(() => {
if (selectedEventData) { if (selectedEventData) {
const point = getPointByUuid( const point = getPointByUuid(
selectedProduct.productId, selectedProduct.productId,
selectedEventData?.data.modelUuid, selectedEventData?.data.modelUuid,
selectedEventData?.selectedPoint selectedEventData?.selectedPoint
) as MachinePointSchema | undefined; ) as MachinePointSchema | undefined;
if (point && 'action' in point) { if (point && "action" in point) {
setSelectedPointData(point); setSelectedPointData(point);
setActiveOption(point.action.actionType as "process"); setActiveOption(point.action.actionType as "process");
} }
} }
}, [selectedProduct, selectedEventData]) }, [selectedProduct, selectedEventData, getPointByUuid]);
const handleActionTypeChange = (option: string) => { const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return; if (!selectedEventData || !selectedPointData) return;
const validOption = option as "process"; const validOption = option as "process";
setActiveOption(validOption); setActiveOption(validOption);
updateAction( updateAction(selectedPointData.action.actionUuid, {
selectedPointData.action.actionUuid, actionType: validOption,
{ actionType: validOption } });
); };
};
const handleRenameAction = (newName: string) => { const handleRenameAction = (newName: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
updateAction( updateAction(selectedPointData.action.actionUuid, { actionName: newName });
selectedPointData.action.actionUuid, };
{ actionName: newName }
);
};
const handleProcessTimeChange = (value: string) => { const handleProcessTimeChange = (value: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
updateAction( updateAction(selectedPointData.action.actionUuid, {
selectedPointData.action.actionUuid, processTime: parseFloat(value),
{ processTime: parseFloat(value) } });
); };
};
const handleMaterialSelect = (material: string) => { const handleMaterialSelect = (material: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
updateAction( updateAction(selectedPointData.action.actionUuid, {
selectedPointData.action.actionUuid, swapMaterial: material,
{ swapMaterial: material } });
); };
};
// Get current values from store // Get current values from store
const currentActionName = selectedPointData const currentActionName = selectedPointData
? selectedPointData.action.actionName ? selectedPointData.action.actionName
: "Action Name"; : "Action Name";
const currentProcessTime = selectedPointData const currentProcessTime = selectedPointData
? selectedPointData.action.processTime.toString() ? selectedPointData.action.processTime.toString()
: "1"; : "1";
const currentMaterial = selectedPointData const currentMaterial = selectedPointData
? selectedPointData.action.swapMaterial ? selectedPointData.action.swapMaterial
: "Default material"; : "Default material";
const availableActions = { const availableActions = {
defaultOption: "process", defaultOption: "process",
options: ["process"], options: ["process"],
}; };
return ( return (
<>
{selectedEventData && (
<> <>
{selectedEventData && <div className="selected-actions-details">
<> <div className="selected-actions-header">
<div className="selected-actions-details"> <RenameInput
<div className="selected-actions-header"> value={currentActionName}
<RenameInput onRename={handleRenameAction}
value={currentActionName} />
onRename={handleRenameAction} </div>
/> <ActionsList
</div> setSelectedPointData={setSelectedPointData}
<div className="selected-actions-list"> selectedPointData={selectedPointData}
<LabledDropdown />
defaultOption="process" <div className="selected-actions-list">
options={availableActions.options} <LabledDropdown
onSelect={handleActionTypeChange} defaultOption="process"
/> options={availableActions.options}
{activeOption === "process" && onSelect={handleActionTypeChange}
<ProcessAction />
value={currentProcessTime} {activeOption === "process" && (
min={0.1} <ProcessAction
max={60} value={currentProcessTime}
defaultValue="1" min={0.1}
onChange={handleProcessTimeChange} max={60}
swapOptions={["Default material", "Material 1", "Material 2"]} defaultValue="1"
swapDefaultOption={currentMaterial} onChange={handleProcessTimeChange}
onSwapSelect={handleMaterialSelect} swapOptions={["Default material", "Material 1", "Material 2"]}
/> swapDefaultOption={currentMaterial}
} onSwapSelect={handleMaterialSelect}
</div> />
</div> )}
<div className="tirgger"> </div>
<Trigger /> </div>
</div> <div className="tirgger">
</> <Trigger />
} </div>
</> </>
) )}
</>
);
} }
export default MachineMechanics export default MachineMechanics;

View File

@ -1,276 +1,194 @@
import { useEffect, useRef, useState } from 'react' import { useEffect, useState } from "react";
import * as THREE from 'three'; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' import RenameInput from "../../../../../ui/inputs/RenameInput";
import RenameInput from '../../../../../ui/inputs/RenameInput' import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' import Trigger from "../trigger/Trigger";
import Trigger from '../trigger/Trigger' import {
import { useSelectedEventData, useSelectedProduct, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore"; useSelectedEventData,
useSelectedProduct,
useSelectedAction,
} from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import { AddIcon, RemoveIcon, ResizeHeightIcon } from '../../../../../icons/ExportCommonIcons' import PickAndPlaceAction from "../actions/PickAndPlaceAction";
import { handleResize } from '../../../../../../functions/handleResizePannel' import ActionsList from "../components/ActionsList";
import PickAndPlaceAction from '../actions/PickAndPlaceAction'
function RoboticArmMechanics() { function RoboticArmMechanics() {
const actionsContainerRef = useRef<HTMLDivElement>(null); const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">(
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default"); "default"
const [selectedPointData, setSelectedPointData] = useState<RoboticArmPointSchema | undefined>(); );
const { selectedEventData } = useSelectedEventData(); const [selectedPointData, setSelectedPointData] = useState<
const { getPointByUuid, updateEvent, updateAction, addAction, removeAction } = useProductStore(); RoboticArmPointSchema | undefined
const { selectedProduct } = useSelectedProduct(); >();
const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction(); const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
const { selectedAction, setSelectedAction, clearSelectedAction } =
useSelectedAction();
useEffect(() => { useEffect(() => {
if (selectedEventData) { if (selectedEventData) {
const point = getPointByUuid( const point = getPointByUuid(
selectedProduct.productId, selectedProduct.productId,
selectedEventData.data.modelUuid, selectedEventData.data.modelUuid,
selectedEventData.selectedPoint selectedEventData.selectedPoint
) as RoboticArmPointSchema | undefined; ) as RoboticArmPointSchema | undefined;
if (point) { if (point) {
setSelectedPointData(point); setSelectedPointData(point);
setActiveOption(point.actions[0].actionType as "default" | "pickAndPlace"); setActiveOption(
if (point.actions.length > 0 && !selectedAction.actionId) { point.actions[0].actionType as "default" | "pickAndPlace"
setSelectedAction(point.actions[0].actionUuid, point.actions[0].actionName); );
} if (point.actions.length > 0 && !selectedAction.actionId) {
} setSelectedAction(
} else { point.actions[0].actionUuid,
clearSelectedAction(); point.actions[0].actionName
);
} }
}, [selectedEventData, selectedProduct]); }
} else {
clearSelectedAction();
}
}, [
clearSelectedAction,
getPointByUuid,
selectedAction.actionId,
selectedEventData,
selectedProduct,
setSelectedAction,
]);
const handleActionSelect = (actionUuid: string, actionName: string) => { const handleRenameAction = (newName: string) => {
setSelectedAction(actionUuid, actionName); if (!selectedAction.actionId) return;
}; updateAction(selectedAction.actionId, { actionName: newName });
const handleAddAction = () => { if (selectedPointData) {
if (!selectedEventData || !selectedPointData) return; const updatedActions = selectedPointData.actions.map((action) =>
action.actionUuid === selectedAction.actionId
? { ...action, actionName: newName }
: action
);
setSelectedPointData({
...selectedPointData,
actions: updatedActions,
});
}
};
const newAction = { const handleSpeedChange = (value: string) => {
actionUuid: THREE.MathUtils.generateUUID(), if (!selectedEventData) return;
actionName: `Action ${selectedPointData.actions.length + 1}`, updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
actionType: "pickAndPlace" as "pickAndPlace", speed: parseFloat(value),
process: { });
startPoint: null, };
endPoint: null
},
triggers: [] as TriggerSchema[]
};
addAction( const handlePickPointChange = (value: string) => {
selectedProduct.productId, if (!selectedAction.actionId || !selectedPointData) return;
selectedEventData.data.modelUuid, const [x, y, z] = value.split(",").map(Number);
selectedEventData.selectedPoint,
newAction
);
const updatedPoint = { updateAction(selectedAction.actionId, {
...selectedPointData, process: {
actions: [...selectedPointData.actions, newAction] startPoint: [x, y, z] as [number, number, number],
}; endPoint:
setSelectedPointData(updatedPoint); selectedPointData.actions.find(
setSelectedAction(newAction.actionUuid, newAction.actionName); (a) => a.actionUuid === selectedAction.actionId
}; )?.process.endPoint || null,
},
});
};
const handleDeleteAction = (actionUuid: string) => { const handlePlacePointChange = (value: string) => {
if (!selectedPointData) return; if (!selectedAction.actionId || !selectedPointData) return;
const [x, y, z] = value.split(",").map(Number);
removeAction(actionUuid); updateAction(selectedAction.actionId, {
const newActions = selectedPointData.actions.filter(a => a.actionUuid !== actionUuid); process: {
startPoint:
selectedPointData.actions.find(
(a) => a.actionUuid === selectedAction.actionId
)?.process.startPoint || null,
endPoint: [x, y, z] as [number, number, number],
},
});
};
const updatedPoint = { const availableActions = {
...selectedPointData, defaultOption: "pickAndPlace",
actions: newActions options: ["pickAndPlace"],
}; };
setSelectedPointData(updatedPoint);
if (selectedAction.actionId === actionUuid) { const currentSpeed =
if (newActions.length > 0) { selectedEventData?.data.type === "roboticArm"
setSelectedAction(newActions[0].actionUuid, newActions[0].actionName); ? selectedEventData.data.speed.toString()
} else { : "0.5";
clearSelectedAction();
}
}
};
const handleRenameAction = (newName: string) => { const currentAction = selectedPointData?.actions.find(
if (!selectedAction.actionId) return; (a) => a.actionUuid === selectedAction.actionId
updateAction( );
selectedAction.actionId, const currentPickPoint = currentAction?.process.startPoint
{ actionName: newName } ? `${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]}`
: "";
if (selectedPointData) { return (
const updatedActions = selectedPointData.actions.map(action => <>
action.actionUuid === selectedAction.actionId {selectedEventData && selectedPointData && (
? { ...action, actionName: newName }
: action
);
setSelectedPointData({
...selectedPointData,
actions: updatedActions
});
}
};
const handleSpeedChange = (value: string) => {
if (!selectedEventData) return;
updateEvent(
selectedProduct.productId,
selectedEventData.data.modelUuid,
{ speed: parseFloat(value) }
);
};
const handlePickPointChange = (value: string) => {
if (!selectedAction.actionId || !selectedPointData) return;
const [x, y, z] = value.split(',').map(Number);
updateAction(
selectedAction.actionId,
{
process: {
startPoint: [x, y, z] as [number, number, number],
endPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.endPoint || null
}
}
);
};
const handlePlacePointChange = (value: string) => {
if (!selectedAction.actionId || !selectedPointData) return;
const [x, y, z] = value.split(',').map(Number);
updateAction(
selectedAction.actionId,
{
process: {
startPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.startPoint || null,
endPoint: [x, y, z] as [number, number, number]
}
}
);
};
const availableActions = {
defaultOption: "pickAndPlace",
options: ["pickAndPlace"],
};
const currentSpeed = selectedEventData?.data.type === "roboticArm"
? selectedEventData.data.speed.toString()
: "0.5";
const currentAction = selectedPointData?.actions.find(a => a.actionUuid === selectedAction.actionId);
const currentPickPoint = currentAction?.process.startPoint
? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}`
: "";
const currentPlacePoint = currentAction?.process.endPoint
? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}`
: "";
return (
<> <>
{selectedEventData && selectedPointData && ( <div className="global-props">
<> <div className="property-list-container">
<div className="global-props"> <div className="property-item">
<div className="property-list-container"> <InputWithDropDown
<div className="property-item"> label="Speed"
<InputWithDropDown value={currentSpeed}
label="Speed" min={0}
value={currentSpeed} step={0.1}
min={0} defaultValue={"0.5"}
step={0.1} max={10}
defaultValue={"0.5"} activeOption="m/s"
max={10} onClick={() => {}}
activeOption="m/s" onChange={handleSpeedChange}
onClick={() => { }} />
onChange={handleSpeedChange} </div>
/> </div>
</div> </div>
</div>
</div>
<div className="actions-list-container"> <ActionsList
<div className="actions"> setSelectedPointData={setSelectedPointData}
<div className="header"> selectedPointData={selectedPointData}
<div className="header-value">Actions</div> multipleAction
<div className="add-button" onClick={handleAddAction}> />
<AddIcon /> Add
</div>
</div>
<div
className="lists-main-container"
ref={actionsContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{selectedPointData.actions.map((action) => (
<div
key={action.actionUuid}
className={`list-item ${selectedAction.actionId === action.actionUuid ? "active" : ""}`}
>
<div
className="value"
onClick={() => handleActionSelect(action.actionUuid, action.actionName)}
>
<RenameInput
value={action.actionName}
onRename={handleRenameAction}
/>
</div>
{selectedPointData.actions.length > 1 && (
<div
className="remove-button"
onClick={() => handleDeleteAction(action.actionUuid)}
>
<RemoveIcon />
</div>
)}
</div>
))}
</div>
<div
className="resize-icon"
id="action-resize"
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
>
<ResizeHeightIcon />
</div>
</div>
</div>
</div>
{selectedAction.actionId && currentAction && ( {selectedAction.actionId && currentAction && (
<div className="selected-actions-details"> <div className="selected-actions-details">
<div className="selected-actions-header"> <div className="selected-actions-header">
<RenameInput <RenameInput
value={selectedAction.actionName} value={selectedAction.actionName}
onRename={handleRenameAction} onRename={handleRenameAction}
/> />
</div> </div>
<div className="selected-actions-list"> <div className="selected-actions-list">
<LabledDropdown <LabledDropdown
defaultOption={activeOption} defaultOption={activeOption}
options={availableActions.options} options={availableActions.options}
onSelect={() => { }} onSelect={() => {}}
disabled={true} disabled={true}
/> />
<PickAndPlaceAction <PickAndPlaceAction
pickPointValue={currentPickPoint} pickPointValue={currentPickPoint}
pickPointOnChange={handlePickPointChange} pickPointOnChange={handlePickPointChange}
placePointValue={currentPlacePoint} placePointValue={currentPlacePoint}
placePointOnChange={handlePlacePointChange} placePointOnChange={handlePlacePointChange}
/> />
</div> </div>
<div className="tirgger"> <div className="tirgger">
<Trigger /> <Trigger />
</div> </div>
</div> </div>
)} )}
</>
)}
</> </>
) )}
</>
);
} }
export default RoboticArmMechanics export default RoboticArmMechanics;

View File

@ -1,113 +1,120 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from "react";
import RenameInput from '../../../../../ui/inputs/RenameInput' import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from '../trigger/Trigger' 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 { useProductStore } from "../../../../../../store/simulation/useProductStore";
import StorageAction from '../actions/StorageAction'; import StorageAction from "../actions/StorageAction";
import ActionsList from "../components/ActionsList";
function StorageMechanics() { function StorageMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default"); const [activeOption, setActiveOption] = useState<
const [selectedPointData, setSelectedPointData] = useState<StoragePointSchema | undefined>(); "default" | "store" | "spawn"
const { selectedEventData } = useSelectedEventData(); >("default");
const { getPointByUuid, updateAction } = useProductStore(); const [selectedPointData, setSelectedPointData] = useState<
const { selectedProduct } = useSelectedProduct(); StoragePointSchema | undefined
>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
useEffect(() => { useEffect(() => {
if (selectedEventData) { if (selectedEventData) {
const point = getPointByUuid( const point = getPointByUuid(
selectedProduct.productId, selectedProduct.productId,
selectedEventData?.data.modelUuid, selectedEventData?.data.modelUuid,
selectedEventData?.selectedPoint selectedEventData?.selectedPoint
) as StoragePointSchema | undefined; ) as StoragePointSchema | undefined;
if (point && 'action' in point) { if (point && "action" in point) {
setSelectedPointData(point); setSelectedPointData(point);
setActiveOption(point.action.actionType as "store" | "spawn"); setActiveOption(point.action.actionType as "store" | "spawn");
} }
} }
}, [selectedProduct, selectedEventData]) }, [selectedProduct, selectedEventData, getPointByUuid]);
const handleActionTypeChange = (option: string) => { const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return; if (!selectedEventData || !selectedPointData) return;
const validOption = option as "store" | "spawn"; const validOption = option as "store" | "spawn";
setActiveOption(validOption); setActiveOption(validOption);
updateAction( updateAction(selectedPointData.action.actionUuid, {
selectedPointData.action.actionUuid, actionType: validOption,
{ actionType: validOption } });
); };
};
const handleRenameAction = (newName: string) => { const handleRenameAction = (newName: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
updateAction( updateAction(selectedPointData.action.actionUuid, { actionName: newName });
selectedPointData.action.actionUuid, };
{ actionName: newName }
);
};
const handleCapacityChange = (value: string) => { const handleCapacityChange = (value: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
updateAction( updateAction(selectedPointData.action.actionUuid, {
selectedPointData.action.actionUuid, storageCapacity: parseInt(value),
{ storageCapacity: parseInt(value) } });
); };
};
// Get current values from store // Get current values from store
const currentActionName = selectedPointData const currentActionName = selectedPointData
? selectedPointData.action.actionName ? selectedPointData.action.actionName
: "Action Name"; : "Action Name";
const currentCapacity = selectedPointData const currentCapacity = selectedPointData
? selectedPointData.action.storageCapacity.toString() ? selectedPointData.action.storageCapacity.toString()
: "0"; : "0";
const availableActions = { const availableActions = {
defaultOption: "store", defaultOption: "store",
options: ["store", "spawn"], options: ["store", "spawn"],
}; };
return ( return (
<>
{selectedEventData && (
<> <>
{selectedEventData && <ActionsList
<> setSelectedPointData={setSelectedPointData}
<div className="selected-actions-details"> selectedPointData={selectedPointData}
<div className="selected-actions-header"> />
<RenameInput <div className="selected-actions-details">
value={currentActionName} <div className="selected-actions-header">
onRename={handleRenameAction} <RenameInput
/> value={currentActionName}
</div> onRename={handleRenameAction}
<div className="selected-actions-list"> />
<LabledDropdown </div>
defaultOption={activeOption} <div className="selected-actions-list">
options={availableActions.options} <LabledDropdown
onSelect={handleActionTypeChange} defaultOption={activeOption}
/> options={availableActions.options}
{activeOption === "store" && onSelect={handleActionTypeChange}
<StorageAction />
value={currentCapacity} {activeOption === "store" && (
defaultValue="0" <StorageAction
min={0} value={currentCapacity}
max={20} defaultValue="0"
onChange={handleCapacityChange} min={0}
/> max={20}
} onChange={handleCapacityChange}
{activeOption === "spawn" && ( />
<div className="spawn-options"> )}
<p>Spawn configuration options would go here</p> {activeOption === "spawn" && (
</div> <div className="spawn-options">
)} <p>Spawn configuration options would go here</p>
</div> </div>
</div> )}
<div className="tirgger"> </div>
<Trigger /> </div>
</div> <div className="tirgger">
</> <Trigger />
} </div>
</> </>
) )}
</>
);
} }
export default StorageMechanics export default StorageMechanics;

View File

@ -1,197 +1,199 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from "react";
import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import RenameInput from '../../../../../ui/inputs/RenameInput' import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from '../trigger/Trigger' 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 { useProductStore } from "../../../../../../store/simulation/useProductStore";
import TravelAction from '../actions/TravelAction' import TravelAction from "../actions/TravelAction";
import ActionsList from "../components/ActionsList";
function VehicleMechanics() { function VehicleMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "travel">("default"); const [activeOption, setActiveOption] = useState<"default" | "travel">(
const [selectedPointData, setSelectedPointData] = useState<VehiclePointSchema | undefined>(); "default"
const { selectedEventData } = useSelectedEventData(); );
const { getPointByUuid, updateEvent, updateAction } = useProductStore(); const [selectedPointData, setSelectedPointData] = useState<
const { selectedProduct } = useSelectedProduct(); VehiclePointSchema | undefined
>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
const { selectedProduct } = useSelectedProduct();
useEffect(() => { useEffect(() => {
if (selectedEventData) { if (selectedEventData) {
const point = getPointByUuid( const point = getPointByUuid(
selectedProduct.productId, selectedProduct.productId,
selectedEventData.data.modelUuid, selectedEventData.data.modelUuid,
selectedEventData.selectedPoint selectedEventData.selectedPoint
) as VehiclePointSchema | undefined; ) as VehiclePointSchema | undefined;
if (point) { if (point) {
setSelectedPointData(point); setSelectedPointData(point);
setActiveOption(point.action.actionType as "travel"); setActiveOption(point.action.actionType as "travel");
} }
} }
}, [selectedProduct, selectedEventData]) }, [selectedProduct, selectedEventData, getPointByUuid]);
const handleSpeedChange = (value: string) => { const handleSpeedChange = (value: string) => {
if (!selectedEventData) return; if (!selectedEventData) return;
updateEvent( updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
selectedProduct.productId, speed: parseFloat(value),
selectedEventData.data.modelUuid, });
{ speed: parseFloat(value) } };
);
};
const handleActionTypeChange = (option: string) => { const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return; if (!selectedEventData || !selectedPointData) return;
const validOption = option as "travel"; const validOption = option as "travel";
setActiveOption(validOption); setActiveOption(validOption);
updateAction( updateAction(selectedPointData.action.actionUuid, {
selectedPointData.action.actionUuid, actionType: validOption,
{ actionType: validOption } });
); };
};
const handleRenameAction = (newName: string) => { const handleRenameAction = (newName: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
updateAction( updateAction(selectedPointData.action.actionUuid, { actionName: newName });
selectedPointData.action.actionUuid, };
{ actionName: newName }
);
};
const handleLoadCapacityChange = (value: string) => { const handleLoadCapacityChange = (value: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
updateAction( updateAction(selectedPointData.action.actionUuid, {
selectedPointData.action.actionUuid, loadCapacity: parseFloat(value),
{ loadCapacity: parseFloat(value) } });
); };
};
const handleUnloadDurationChange = (value: string) => { const handleUnloadDurationChange = (value: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
updateAction( updateAction(selectedPointData.action.actionUuid, {
selectedPointData.action.actionUuid, unLoadDuration: parseFloat(value),
{ unLoadDuration: parseFloat(value) } });
); };
};
const handlePickPointChange = (value: string) => { const handlePickPointChange = (value: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
const [x, y, z] = value.split(',').map(Number); const [x, y, z] = value.split(",").map(Number);
updateAction( updateAction(selectedPointData.action.actionUuid, {
selectedPointData.action.actionUuid, pickUpPoint: { x, y, z },
{ pickUpPoint: { x, y, z } } });
); };
};
const handleUnloadPointChange = (value: string) => { const handleUnloadPointChange = (value: string) => {
if (!selectedPointData) return; if (!selectedPointData) return;
const [x, y, z] = value.split(',').map(Number); const [x, y, z] = value.split(",").map(Number);
updateAction( updateAction(selectedPointData.action.actionUuid, {
selectedPointData.action.actionUuid, unLoadPoint: { x, y, z },
{ unLoadPoint: { x, y, z } } });
); };
};
// Get current values from store // Get current values from store
const currentSpeed = selectedEventData?.data.type === "vehicle" const currentSpeed =
? selectedEventData.data.speed.toString() selectedEventData?.data.type === "vehicle"
: "0.5"; ? selectedEventData.data.speed.toString()
: "0.5";
const currentActionName = selectedPointData const currentActionName = selectedPointData
? selectedPointData.action.actionName ? selectedPointData.action.actionName
: "Action Name"; : "Action Name";
const currentLoadCapacity = selectedPointData const currentLoadCapacity = selectedPointData
? selectedPointData.action.loadCapacity.toString() ? selectedPointData.action.loadCapacity.toString()
: "1"; : "1";
const currentUnloadDuration = selectedPointData const currentUnloadDuration = selectedPointData
? selectedPointData.action.unLoadDuration.toString() ? selectedPointData.action.unLoadDuration.toString()
: "1"; : "1";
const currentPickPoint = selectedPointData?.action.pickUpPoint const currentPickPoint = selectedPointData?.action.pickUpPoint
? `${selectedPointData.action.pickUpPoint.x},${selectedPointData.action.pickUpPoint.y},${selectedPointData.action.pickUpPoint.z}` ? `${selectedPointData.action.pickUpPoint.x},${selectedPointData.action.pickUpPoint.y},${selectedPointData.action.pickUpPoint.z}`
: ""; : "";
const currentUnloadPoint = selectedPointData?.action.unLoadPoint const currentUnloadPoint = selectedPointData?.action.unLoadPoint
? `${selectedPointData.action.unLoadPoint.x},${selectedPointData.action.unLoadPoint.y},${selectedPointData.action.unLoadPoint.z}` ? `${selectedPointData.action.unLoadPoint.x},${selectedPointData.action.unLoadPoint.y},${selectedPointData.action.unLoadPoint.z}`
: ""; : "";
const availableActions = { const availableActions = {
defaultOption: "travel", defaultOption: "travel",
options: ["travel"], options: ["travel"],
}; };
return ( return (
<>
{selectedEventData && (
<> <>
{selectedEventData && <div className="global-props">
<> <div className="property-list-container">
<div className="global-props"> <div className="property-item">
<div className="property-list-container"> <InputWithDropDown
<div className="property-item"> label="Speed"
<InputWithDropDown value={currentSpeed}
label="Speed" min={0}
value={currentSpeed} step={0.1}
min={0} defaultValue={"0.5"}
step={0.1} max={10}
defaultValue={"0.5"} activeOption="m/s"
max={10} onClick={() => {}}
activeOption="m/s" onChange={handleSpeedChange}
onClick={() => { }} />
onChange={handleSpeedChange} </div>
/> </div>
</div> </div>
</div> <ActionsList
</div> setSelectedPointData={setSelectedPointData}
selectedPointData={selectedPointData}
/>
<div className="selected-actions-details">
<div className="selected-actions-header">
<RenameInput
value={currentActionName}
onRename={handleRenameAction}
/>
</div>
<div className="selected-actions-list">
<LabledDropdown
defaultOption="travel"
options={availableActions.options}
onSelect={handleActionTypeChange}
/>
<div className="selected-actions-details"> {activeOption === "travel" && (
<div className="selected-actions-header"> <TravelAction
<RenameInput loadCapacity={{
value={currentActionName} value: currentLoadCapacity,
onRename={handleRenameAction} min: 1,
/> max: 100,
</div> defaultValue: "1",
<div className="selected-actions-list"> onChange: handleLoadCapacityChange,
<LabledDropdown }}
defaultOption="travel" unloadDuration={{
options={availableActions.options} value: currentUnloadDuration,
onSelect={handleActionTypeChange} min: 1,
/> max: 60,
defaultValue: "1",
{activeOption === 'travel' && onChange: handleUnloadDurationChange,
<TravelAction }}
loadCapacity={{ // pickPoint={{
value: currentLoadCapacity, // value: currentPickPoint,
min: 1, // onChange: handlePickPointChange,
max: 100, // }}
defaultValue: "1", // unloadPoint={{
onChange: handleLoadCapacityChange, // value: currentUnloadPoint,
}} // onChange: handleUnloadPointChange,
unloadDuration={{ // }}
value: currentUnloadDuration, />
min: 1, )}
max: 60, </div>
defaultValue: "1", </div>
onChange: handleUnloadDurationChange, <div className="tirgger">
}} <Trigger />
// pickPoint={{ </div>
// value: currentPickPoint,
// onChange: handlePickPointChange,
// }}
// unloadPoint={{
// value: currentUnloadPoint,
// onChange: handleUnloadPointChange,
// }}
/>
}
</div>
</div>
<div className="tirgger">
<Trigger />
</div>
</>
}
</> </>
) )}
</>
);
} }
export default VehicleMechanics export default VehicleMechanics;

View File

@ -366,15 +366,66 @@
min-height: 50vh; min-height: 50vh;
padding-bottom: 12px; padding-bottom: 12px;
position: relative; position: relative;
display: flex; overflow: auto;
flex-direction: column;
.sidebar-right-content-container { .sidebar-right-content-container {
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
// flex: 1;
height: calc(100% - 36px); height: calc(100% - 36px);
position: relative; position: relative;
overflow: auto; width: 320px;
.no-event-selected {
color: #666;
padding: 1.8rem 1rem;
grid-column: 1 / -1;
.products-list {
padding-top: 1rem;
.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);
stroke-width: 1.5px;
}
color: var(--accent-color);
&:before {
width: 100%;
}
}
}
}
}
}
}
} }
} }
@ -707,7 +758,7 @@
} }
.selected-actions-list { .selected-actions-list {
margin-bottom: 8px; margin-bottom: 8px;
.eye-dropper-input-container{ .eye-dropper-input-container {
padding: 6px 12px; padding: 6px 12px;
.regularDropdown-container { .regularDropdown-container {
padding: 5px 8px; padding: 5px 8px;
@ -798,6 +849,7 @@
@include flex-center; @include flex-center;
padding: 4px; padding: 4px;
cursor: grab; cursor: grab;
width: 100%;
&:active { &:active {
cursor: grabbing; cursor: grabbing;

View File

@ -776,13 +776,13 @@
border-radius: 6px; border-radius: 6px;
overflow: hidden; overflow: hidden;
padding: 4px; padding: 4px;
min-width: 150px; min-width: 150px;
.option { .option {
padding: 4px 10px; padding: 4px 10px;
border-radius: #{$border-radius-small}; border-radius: #{$border-radius-small};
color: var(--text-color); color: var(--text-color);
text-wrap: nowrap;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
@ -794,8 +794,8 @@
color: #f65648; color: #f65648;
&:hover { &:hover {
background-color: #f65648; background-color: #f657484d;
color: white; color: #f65648;
} }
} }
} }