feat: Enhance InputWithDropDown to support disabled state

fix: Update Model component to manage animation states and transitions more effectively

feat: Implement worker action handling in useWorkerHandler for material management

feat: Add MaterialAnimator to HumanInstance for dynamic material loading

feat: Extend useTriggerHandler to support interactions between humans and various entities

feat: Create WorkerAction component for managing load capacity and actions

feat: Introduce MaterialAnimator for human instances to visualize material loads

refactor: Update asset store to manage animation completion state

fix: Ensure proper handling of human materials in useHumanStore
This commit is contained in:
2025-07-04 13:14:39 +05:30
parent 7cf82629e9
commit 02490214d9
17 changed files with 990 additions and 261 deletions

View File

@@ -35,7 +35,7 @@ const AssetProperties: React.FC = () => {
const handleAnimationClick = (animation: string) => {
if (selectedFloorItem) {
setCurrentAnimation(selectedFloorItem.uuid, animation, true, loopAnimation);
setCurrentAnimation(selectedFloorItem.uuid, animation, true, loopAnimation, true);
}
}

View File

@@ -1,95 +1,70 @@
import React from "react";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
interface TravelActionProps {
loadCapacity: {
value: string;
min: number;
max: number;
defaultValue: string;
onChange: (value: string) => void;
};
unloadDuration: {
value: string;
min: number;
max: number;
defaultValue: string;
onChange: (value: string) => void;
};
pickPoint?: {
value: string;
onChange: (value: string) => void;
};
unloadPoint?: {
value: string;
onChange: (value: string) => void;
};
clearPoints: () => void;
loadCapacity: {
value: string;
min: number;
max: number;
defaultValue: string;
onChange: (value: string) => void;
};
unloadDuration: {
value: string;
min: number;
max: number;
defaultValue: string;
onChange: (value: string) => void;
};
clearPoints: () => void;
}
const TravelAction: React.FC<TravelActionProps> = ({
loadCapacity,
unloadDuration,
pickPoint,
unloadPoint,
clearPoints,
loadCapacity,
unloadDuration,
clearPoints,
}) => {
return (
<>
<InputWithDropDown
label="Load Capacity"
value={loadCapacity.value}
min={loadCapacity.min}
max={loadCapacity.max}
defaultValue={loadCapacity.defaultValue}
step={1}
activeOption="s"
onClick={() => {}}
onChange={loadCapacity.onChange}
/>
<InputWithDropDown
label="Unload Duration"
value={unloadDuration.value}
min={unloadDuration.min}
max={unloadDuration.max}
defaultValue={unloadDuration.defaultValue}
step={0.1}
activeOption="s"
onClick={() => {}}
onChange={unloadDuration.onChange}
/>
<div className="selected-actions-list">
<div className="value-field-container">
<div className="label">Reset</div>
<button
id="rest-button"
type="button"
className="regularDropdown-container"
onClick={() => {
clearPoints();
}}
>
Clear
</button>
</div>
</div>
{pickPoint && (
<EyeDropInput
label="Pick Point"
value={pickPoint.value}
onChange={pickPoint.onChange}
/>
)}
{unloadPoint && (
<EyeDropInput
label="Unload Point"
value={unloadPoint.value}
onChange={unloadPoint.onChange}
/>
)}
</>
);
return (
<>
<InputWithDropDown
label="Load Capacity"
value={loadCapacity.value}
min={loadCapacity.min}
max={loadCapacity.max}
defaultValue={loadCapacity.defaultValue}
step={1}
activeOption="unit"
onClick={() => { }}
onChange={loadCapacity.onChange}
/>
<InputWithDropDown
label="Unload Duration"
value={unloadDuration.value}
min={unloadDuration.min}
max={unloadDuration.max}
defaultValue={unloadDuration.defaultValue}
step={0.1}
activeOption="s"
onClick={() => { }}
onChange={unloadDuration.onChange}
/>
<div className="selected-actions-list">
<div className="value-field-container">
<div className="label">Reset</div>
<button
id="rest-button"
type="button"
className="regularDropdown-container"
onClick={() => {
clearPoints();
}}
>
Clear
</button>
</div>
</div>
</>
);
};
export default TravelAction;

View File

@@ -0,0 +1,54 @@
import React from "react";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
interface WorkerActionProps {
loadCapacity: {
value: string;
min: number;
max: number;
step: number;
defaultValue: string;
disabled?: boolean,
onChange: (value: string) => void;
};
clearPoints: () => void;
}
const WorkerAction: React.FC<WorkerActionProps> = ({
loadCapacity,
clearPoints,
}) => {
return (
<>
<InputWithDropDown
label="Load Capacity"
value={loadCapacity.value}
min={loadCapacity.min}
max={loadCapacity.max}
disabled={loadCapacity.disabled}
defaultValue={loadCapacity.defaultValue}
step={loadCapacity.step}
activeOption="unit"
onClick={() => { }}
onChange={loadCapacity.onChange}
/>
<div className="selected-actions-list">
<div className="value-field-container">
<div className="label">Reset</div>
<button
id="rest-button"
type="button"
className="regularDropdown-container"
onClick={() => {
clearPoints();
}}
>
Clear
</button>
</div>
</div>
</>
);
};
export default WorkerAction;

View File

@@ -1,97 +0,0 @@
import React, { useRef } from "react";
import { AddIcon, RemoveIcon, ResizeHeightIcon } from "../../../../../icons/ExportCommonIcons";
import { handleResize } from "../../../../../../functions/handleResizePannel";
import { useSelectedAction, useSelectedAnimation } from "../../../../../../store/simulation/useSimulationStore";
import RenameInput from "../../../../../ui/inputs/RenameInput";
interface AnimationListProps {
animationOptions: string[];
animationSequences: {
animationUuid: string;
animationName: string;
animationType: "behaviour" | "animatedTravel";
animation: string | null;
travelPoints?: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null };
}[];
onAddAnimation: () => void;
onRemoveAnimation: (animationUuid: string) => void;
handleAnimationSelect: (animationUuid: string) => void;
handleRenameAnimation: (animationUuid: string, newName: string) => void;
}
const AnimationList: React.FC<AnimationListProps> = ({
animationSequences,
onAddAnimation,
onRemoveAnimation,
handleAnimationSelect,
handleRenameAnimation,
}) => {
const animationContainerRef = useRef<HTMLDivElement>(null);
const { selectedAction } = useSelectedAction();
const { selectedAnimation } = useSelectedAnimation();
return (
<div className="actions-list-container">
<div className="actions">
<div className="header">
<div className="header-value">Animation Sequences</div>
<button
id="add-action-button"
className="add-button"
onClick={onAddAnimation}
disabled={!selectedAction.actionId}
>
<AddIcon /> Add
</button>
</div>
<div
className="lists-main-container"
ref={animationContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{animationSequences.map((sequence) => (
<div
key={sequence.animationUuid}
className={`list-item ${selectedAnimation?.animationUuid === sequence.animationUuid ? "active" : ""}`}
>
<button
id="action-button"
className="value"
onClick={() =>
handleAnimationSelect(sequence.animationUuid)
}
>
<RenameInput
value={sequence.animationName}
onRename={(value) => handleRenameAnimation(sequence.animationUuid, value)}
/>
</button>
{animationSequences.length > 1 && (
<button
id="remove-action-button"
className="remove-button"
onClick={() => onRemoveAnimation(sequence.animationUuid)}
>
<RemoveIcon />
</button>
)}
</div>
))}
</div>
{animationSequences.length > 0 && (
<button
className="resize-icon"
id="action-resize"
onMouseDown={(e: any) => handleResize(e, animationContainerRef)}
>
<ResizeHeightIcon />
</button>
)}
</div>
</div>
</div>
);
};
export default AnimationList;

View File

@@ -4,30 +4,27 @@ import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from "../trigger/Trigger";
import PickAndPlaceAction from "../actions/PickAndPlaceAction";
import ActionsList from "../components/ActionsList";
import AnimationList from "../components/AnimationList";
import { useSelectedEventData, useSelectedAction, useSelectedAnimation } from "../../../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
import { useParams } from "react-router-dom";
import WorkerAction from "../actions/workerAction";
function HumanMechanics() {
const [activeOption, setActiveOption] = useState<"worker">("worker");
const [animationOptions, setAnimationOptions] = useState<string[]>([]);
const [speed, setSpeed] = useState("0.5");
const [loadCapacity, setLoadCapacity] = useState("1");
const [currentAction, setCurrentAction] = useState<HumanAction | undefined>();
const [selectedPointData, setSelectedPointData] = useState<HumanPointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { productStore, assetStore } = useSceneContext();
const { getAssetById } = assetStore();
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction, addAction, removeAction } = productStore();
const { productStore } = useSceneContext();
const { getPointByUuid, updateEvent, updateAction, addAction, removeAction, getEventByModelUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
const { selectedAnimation, setSelectedAnimation } = useSelectedAnimation();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
@@ -44,6 +41,13 @@ function HumanMechanics() {
setSelectedPointData(point);
setCurrentAction(point.action);
setSelectedAction(point.action.actionUuid, point.action.actionName);
setSpeed((
getEventByModelUuid(
selectedProduct.productUuid,
selectedEventData?.data.modelUuid || ""
) as HumanEventSchema | undefined
)?.speed?.toString() || "1");
setLoadCapacity(point.action.loadCapacity.toString());
}
} else {
clearSelectedAction();
@@ -68,6 +72,7 @@ function HumanMechanics() {
clearSelectedAction();
setCurrentAction(undefined);
setSpeed("0.5");
setLoadCapacity("1");
}
}, [selectedEventData, selectedProduct, selectedAction]);
@@ -130,6 +135,29 @@ function HumanMechanics() {
setSpeed(value);
};
const handleLoadCapacityChange = (value: string) => {
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
const updatedAction = { ...currentAction };
updatedAction.loadCapacity = parseInt(value)
const updatedPoint = { ...selectedPointData, action: updatedAction };
const event = updateAction(
selectedProduct.productUuid,
selectedAction.actionId,
updatedAction
);
if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
}
setCurrentAction(updatedAction);
setSelectedPointData(updatedPoint);
setLoadCapacity(value);
};
const handleClearPoints = () => {
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
@@ -239,7 +267,18 @@ function HumanMechanics() {
disabled={true}
/>
</div>
<PickAndPlaceAction clearPoints={handleClearPoints} />
<WorkerAction
loadCapacity={{
value: loadCapacity,
min: 1,
max: 5,
step: 1,
defaultValue: "1",
disabled: true,
onChange: handleLoadCapacityChange,
}}
clearPoints={handleClearPoints}
/>
<div className="tirgger">
<Trigger selectedPointData={selectedPointData as any} type="Human" />
</div>

View File

@@ -272,14 +272,6 @@ function VehicleMechanics() {
onChange: handleUnloadDurationChange,
}}
clearPoints={handleClearPoints}
// pickPoint={{
// value: currentPickPoint,
// onChange: handlePickPointChange,
// }}
// unloadPoint={{
// value: currentUnloadPoint,
// onChange: handleUnloadPointChange,
// }}
/>
)}
</div>

View File

@@ -8,6 +8,7 @@ type InputWithDropDownProps = {
max?: number;
step?: number;
defaultValue?: string;
disabled?: boolean;
options?: string[]; // Array of dropdown options
activeOption?: string; // The currently active dropdown option
onClick?: () => void;
@@ -23,6 +24,7 @@ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
max,
step,
defaultValue,
disabled = false,
options,
activeOption,
onClick,
@@ -54,6 +56,7 @@ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
type="number"
defaultValue={value}
// value={value}
disabled={disabled}
onChange={(e) => {
onChange(e.target.value);
}}