first commit

This commit is contained in:
2025-06-10 15:28:23 +05:30
commit e22a2dc275
699 changed files with 100382 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
import React, { useState } from "react";
import orgImg from "../../../assets/image/orgTemp.png";
import { useActiveUsers, useCamMode } from "../../../store/builder/store";
import { ActiveUser } from "../../../types/users";
import CollaborationPopup from "../../templates/CollaborationPopup";
import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor";
import { useSelectedUserStore } from "../../../store/collaboration/useCollabStore";
import { useToggleStore } from "../../../store/useUIToggleStore";
import { ToggleSidebarIcon } from "../../icons/HeaderIcons";
import useModuleStore from "../../../store/useModuleStore";
const Header: React.FC = () => {
const { activeUsers } = useActiveUsers();
const userName = localStorage.getItem("userName") ?? "Anonymous";
const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
const { activeModule } = useModuleStore();
const guestUsers: ActiveUser[] = activeUsers.filter(
(user: ActiveUser) => user.userName !== userName
);
const [userManagement, setUserManagement] = useState(false);
const { setSelectedUser } = useSelectedUserStore();
const { setCamMode } = useCamMode();
function handleUserFollow(user: any, index: number) {
const position = {
x: user.position?.x!,
y: user.position?.y!,
z: user.position?.z!,
};
const target = {
x: user.target?.x!,
y: user.target?.y!,
z: user.target?.z!,
};
const rotation = {
x: user.rotation?.x!,
y: user.rotation?.y!,
z: user.rotation?.z!,
};
// retun on no data
if (!position || !target || !rotation) return;
// Set the selected user in the store
setSelectedUser({
color: getAvatarColor(index, user.userName),
name: user.userName,
id: user.id,
location: { position, rotation, target },
});
setCamMode("FollowPerson");
}
return (
<>
{userManagement && (
<CollaborationPopup setUserManagement={setUserManagement} />
)}
<div className="header-container">
<div className="options-container">
<button
id="toggle-rightSidebar-ui-button"
className={`toggle-sidebar-ui-button ${!toggleUIRight ? "active" : ""
}`}
onClick={() => {
if (activeModule !== "market") {
setToggleUI(toggleUILeft, !toggleUIRight);
localStorage.setItem(
"navBarUiRight",
JSON.stringify(!toggleUIRight)
);
}
}}
>
<div className="tooltip">
{toggleUIRight ? "Hide" : "Show"} sidebar (ctrl + ])
</div>
<ToggleSidebarIcon />
</button>
<button
id="share-button"
className="share-button"
onClick={() => {
setUserManagement(true);
}}
>
Share
</button>
{/* <div className="app-docker-button">
<AppDockIcon />
</div> */}
</div>
<div className="split"></div>
<div className="users-container">
<div className="guest-users-container">
{guestUsers.length > 3 && (
<div className="other-guest">+{guestUsers.length - 3}</div>
)}
{guestUsers.slice(0, 3).map((user, index) => (
<button
id="user-profile-button"
key={`${index}-${user.userName}`}
className="user-profile"
style={{ background: getAvatarColor(index, user.userName) }}
onClick={() => {
handleUserFollow(user, index);
}}
>
{user.userName[0]}
</button>
))}
</div>
<div className="user-profile-container">
<div className="user-profile">{userName[0]}</div>
<div className="user-organization">
<img src={orgImg} alt="" />
</div>
</div>
</div>
</div>
</>
);
};
export default Header;

View File

@@ -0,0 +1,217 @@
import React, { useEffect } from "react";
import Header from "./Header";
import useModuleStore, {
useSubModuleStore,
} from "../../../store/useModuleStore";
import {
AnalysisIcon,
MechanicsIcon,
PropertiesIcon,
SimulationIcon,
} from "../../icons/SimulationIcons";
import { useToggleStore } from "../../../store/useUIToggleStore";
import Visualization from "./visualization/Visualization";
import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations";
import useVersionHistoryStore, {
useSaveVersion,
useSelectedFloorItem,
useToolMode,
} from "../../../store/builder/store";
import {
useSelectedEventData,
useSelectedEventSphere,
} from "../../../store/simulation/useSimulationStore";
import GlobalProperties from "./properties/GlobalProperties";
import AsstePropertiies from "./properties/AssetProperties";
import ZoneProperties from "./properties/ZoneProperties";
import EventProperties from "./properties/eventProperties/EventProperties";
import VersionHistory from "./versionHisory/VersionHistory";
import AisleProperties from "./properties/AisleProperties";
import WallProperties from "./properties/eventProperties/WallProperties";
const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore();
const { toggleUIRight } = useToggleStore();
const { toolMode } = useToolMode();
const { subModule, setSubModule } = useSubModuleStore();
const { selectedFloorItem } = useSelectedFloorItem();
const { selectedEventData } = useSelectedEventData();
const { selectedEventSphere } = useSelectedEventSphere();
const { viewVersionHistory, setVersionHistory } = useVersionHistoryStore();
const { isVersionSaved } = useSaveVersion();
// Reset activeList whenever activeModule changes
useEffect(() => {
if (activeModule !== "simulation") setSubModule("properties");
if (activeModule === "simulation") setSubModule("simulations");
}, [activeModule, setSubModule]);
useEffect(() => {
if (
activeModule !== "mechanics" &&
selectedEventData &&
selectedEventSphere
) {
setSubModule("mechanics");
} else if (!selectedEventData && !selectedEventSphere) {
if (activeModule === "simulation") {
setSubModule("simulations");
}
}
if (activeModule !== "simulation") {
setSubModule("properties");
}
}, [activeModule, selectedEventData, selectedEventSphere, setSubModule]);
return (
<div
className={`sidebar-right-wrapper ${toggleUIRight && (!isVersionSaved || activeModule !== "simulation") ? "open" : "closed"
}`}
>
<Header />
{toggleUIRight && (
<>
{!isVersionSaved && (
<div className="sidebar-actions-container">
{activeModule !== "simulation" && (
<button
id="sidebar-action-list-properties"
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
}`}
onClick={() => {
setSubModule("properties");
setVersionHistory(false);
}}
>
<div className="tooltip">properties</div>
<PropertiesIcon isActive={subModule === "properties"} />
</button>
)}
{activeModule === "simulation" && (
<>
<button
id="sidebar-action-list-simulation"
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
}`}
onClick={() => {
setSubModule("simulations");
setVersionHistory(false);
}}
>
<div className="tooltip">simulations</div>
<SimulationIcon isActive={subModule === "simulations"} />
</button>
<button
id="sidebar-action-list-mechanics"
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
}`}
onClick={() => {
setSubModule("mechanics");
setVersionHistory(false);
}}
>
<div className="tooltip">mechanics</div>
<MechanicsIcon isActive={subModule === "mechanics"} />
</button>
<button
id="sidebar-action-list-analysis"
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
}`}
onClick={() => {
setSubModule("analysis");
setVersionHistory(false);
}}
>
<div className="tooltip">analysis</div>
<AnalysisIcon isActive={subModule === "analysis"} />
</button>
</>
)}
</div>
)}
{viewVersionHistory && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<VersionHistory />
</div>
</div>
)}
{/* process builder */}
{!viewVersionHistory &&
subModule === "properties" &&
activeModule !== "visualization" &&
!selectedFloorItem && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
{(() => {
if (toolMode === "Aisle") {
return <AisleProperties />;
} else if (toolMode === "Wall") {
return <WallProperties />;
} else {
return <GlobalProperties />;
}
})()}
</div>
</div>
)}
{!viewVersionHistory &&
subModule === "properties" &&
activeModule !== "visualization" &&
selectedFloorItem && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<AsstePropertiies />
</div>
</div>
)}
{!viewVersionHistory &&
subModule === "zoneProperties" &&
(activeModule === "builder" || activeModule === "simulation") && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<ZoneProperties />
</div>
</div>
)}
{/* simulation */}
{!isVersionSaved &&
!viewVersionHistory &&
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 */}
{activeModule === "visualization" && <Visualization />}
</>
)}
</div>
);
};
export default SideBarRight;

View File

@@ -0,0 +1,124 @@
import React, { useState } from "react";
import { AIIcon } from "../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
import { AnalysisPresetsType } from "../../../../types/analysis";
import RenderAnalysisInputs from "./RenderAnalysisInputs";
import { useInputValues } from "../../../../store/builder/store";
const Analysis: React.FC = () => {
const [selectedOption, setSelectedOption] = useState("Throughput time");
const handleSelect = (option: string) => {
setSelectedOption(option); // Normalize for key matching
};
const AnalysisPresets: AnalysisPresetsType = {
"Throughput time": [
// { type: "default", inputs: { label: "Cycle time", activeOption: "s" } },
// { type: "default", inputs: { label: "machines / lines", activeOption: "item" } },
// { type: "default", inputs: { label: "Machine uptime", activeOption: "%" } },
],
"Production capacity": [
{ type: "range", inputs: { label: "Shift length", activeOption: "hr" } },
{ type: "default", inputs: { label: "Shifts / day", activeOption: "unit" } },
{ type: "default", inputs: { label: "Working days / year", activeOption: "days" } },
{ type: "default", inputs: { label: "Yield rate", activeOption: "%" } },
],
ROI: [
{
type: "default",
inputs: { label: "Selling price", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Material cost", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Labor Cost", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Maintenance cost", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Electricity cost", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Fixed costs", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Initial Investment", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Salvage value", activeOption: "Hrs" },
},
{
type: "default",
inputs: { label: "Production period", activeOption: "yrs" },
},
{
type: "default",
inputs: { label: "Tax rate", activeOption: "%" },
},
],
};
const { inputValues, setInputValues, updateInputValue } = useInputValues();
return (
<div className="analysis-main-wrapper">
<div className="analysis-main-container">
<div className="header">Object</div>
<div className="generate-report-button">
<AIIcon /> Generate Report
</div>
<div className="analysis-content-container section">
<div className="dropdown-header-container">
<div className="value">Create Analysis</div>
</div>
<div className="dropdown-content-container">
<RegularDropDown
header={selectedOption}
options={["Throughput time", "Production capacity", "ROI"]}
onSelect={handleSelect}
search={false}
/>
</div>
{/* Render only the selected option */}
<RenderAnalysisInputs
keyName={selectedOption}
presets={
AnalysisPresets[selectedOption as keyof AnalysisPresetsType]
}
inputValues={inputValues}
onInputChange={(label, value) => {
updateInputValue(label, value);
}}
/>
<div className="buttons-container">
<input type="button" value={"Clear"} className="cancel" onClick={() => setInputValues({})} />
<input type="button" value={"Update"} className="submit" onClick={() => setInputValues(inputValues)} />
</div>
<div className="create-custom-analysis-container">
<div className="custom-analysis-header">Create Custom Analysis</div>
<div className="content">
Click <span>'Create'</span> to enhances decision-making by
providing actionable insights, optimizing operations that adapts
to the unique challenges.
</div>
<div className="input">
<input type="button" value={"Create"} className="submit" />
</div>
</div>
</div>
</div>
</div>
);
};
export default Analysis;

View File

@@ -0,0 +1,45 @@
import React from "react";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import InputRange from "../../../ui/inputs/InputRange";
import { AnalysisPresetsType } from "../../../../types/analysis";
interface InputRendererProps {
keyName: string;
presets: AnalysisPresetsType[keyof AnalysisPresetsType];
inputValues: Record<string, string>; // <-- Add this line
onInputChange: (label: string, value: string) => void;
}
const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets,inputValues, onInputChange }) => {
return (
<div key={`main-${keyName}`} className="analysis-inputs">
{presets.map((preset, index) => {
if (preset.type === "default") {
return (
<InputWithDropDown
key={index}
label={preset.inputs.label}
value={inputValues[preset.inputs.label] || ""}
activeOption={preset.inputs.activeOption}
onChange={(newValue) => onInputChange(preset.inputs.label, newValue)}
/>
);
}
if (preset.type === "range") {
return (
<InputRange
key={index}
label={preset.inputs.label}
min={0}
max={8}
value={5}
/>
);
}
return null;
})}
</div>
);
};
export default RenderAnalysisInputs;

View File

@@ -0,0 +1,64 @@
import React from "react";
import { EyeDroperIcon } from "../../../icons/ExportCommonIcons";
interface PositionInputProps {
label?: string; // Optional label for the input
onChange: (value: string) => void; // Callback for value change
placeholder?: string; // Optional placeholder
type?: string; // Input type (e.g., text, number, email)
value1?: number;
value2?: number;
disabled?: boolean; // Optional disabled property
isEyedrop?: boolean; // Optional eyedrop property
handleEyeDropClick?: () => void; // Optional function for eye drop click
}
const PositionInput: React.FC<PositionInputProps> = ({
onChange,
label = "Position", // Default label
placeholder = "Enter value", // Default placeholder
type = "number", // Default type
value1 = "number",
value2 = "number",
disabled = false, // Default disabled value
isEyedrop = false, // Default isEyedrop value
handleEyeDropClick = () => {}, // Default function for eye drop click
}) => {
return (
<div className="custom-input-container">
<div className="header">{label}</div>
<div className="inputs-container">
<div className="input-container">
<div className="custom-input-label">X : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
value={value1}
disabled={disabled} // Apply disabled prop
/>
</div>
<div className="split"></div>
<div className="input-container">
<div className="custom-input-label">Y : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
value={value2}
disabled={disabled} // Apply disabled prop
/>
</div>
</div>
{isEyedrop && (
<div className="eye-picker-button" onClick={handleEyeDropClick}>
<EyeDroperIcon isActive={false} />
</div>
)}
</div>
);
};
export default PositionInput;

View File

@@ -0,0 +1,35 @@
import React from "react";
interface RotationInputProps {
onChange: (value: string) => void; // Callback for value change
placeholder?: string; // Optional placeholder
type?: string; // Input type (e.g., text, number, email)
value?: number;
}
const RotationInput: React.FC<RotationInputProps> = ({
onChange,
placeholder = "Enter value", // Default placeholder
type = "number", // Default type
value = "number",
}) => {
return (
<div className="custom-input-container">
<div className="header">Rotation</div>
<div className="inputs-container" style={{ display: "block" }}>
<div className="input-container">
<div className="custom-input-label">Rotate : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
value={value}
/>
</div>
</div>
</div>
);
};
export default RotationInput;

View File

@@ -0,0 +1,57 @@
import React from "react";
import { EyeDroperIcon } from "../../../icons/ExportCommonIcons";
// import { useThree } from "@react-three/fiber";
interface PositionInputProps {
onChange: (value: [number, number, number]) => void; // Callback for value change
header: string;
placeholder?: string; // Optional placeholder
type?: string; // Input type (e.g., text, number, email)
value: [number, number, number] | null;
disabled?: boolean; // To enable/disable editing
}
const Vector3Input: React.FC<PositionInputProps> = ({
onChange,
header,
placeholder = "Enter value", // Default placeholder
type = "string", // Default type
value,
disabled = false, // Default to disabled
}) => {
const handleChange = (index: number, newValue: string) => {
if (!value) return;
const updatedValue = [...value] as [number, number, number];
updatedValue[index] = parseFloat(newValue) || 0;
console.log('updatedValue: ', updatedValue);
onChange(updatedValue);
};
return (
<div className="custom-input-container">
<div className="header">
{header}
</div>
<div className="inputs-container">
{["X", "Y", "Z"].map((axis, i) => (
<div className="input-container" key={axis}>
<div className="custom-input-label">{axis}:</div>
<input
className="custom-input-field"
type={type}
value={value?.[i] !== undefined ? value[i].toFixed(2) : ""}
// onChange={(e) => handleChange(i, e.target.value)}
placeholder={placeholder}
disabled={disabled}
/>
</div>
))}
</div>
</div>
);
};
export default Vector3Input;

View File

@@ -0,0 +1,300 @@
import React, { useMemo, useState } from "react";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import { ArrowIcon } from "../../../icons/ExportCommonIcons";
// image imports
import Arc from "../../../../assets/image/aisleTypes/Arc.png";
import Arrow from "../../../../assets/image/aisleTypes/Arrow.png";
import Arrows from "../../../../assets/image/aisleTypes/Arrows.png";
import Circle from "../../../../assets/image/aisleTypes/Circle.png";
import Dashed from "../../../../assets/image/aisleTypes/Dashed.png";
import Directional from "../../../../assets/image/aisleTypes/Directional.png";
import Dotted from "../../../../assets/image/aisleTypes/Dotted.png";
import Solid from "../../../../assets/image/aisleTypes/Solid.png";
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
import InputToggle from "../../../ui/inputs/InputToggle";
interface TextureItem {
color: string;
id: AisleColors;
brief: string;
texture: string;
}
const AisleProperties: React.FC = () => {
const [collapsePresets, setCollapsePresets] = useState(false);
const [collapseTexture, setCollapseTexture] = useState(true);
const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, isFlipped, setAisleType, setAisleColor, setAisleWidth, setDashLength, setGapLength, setDotRadius, setAisleLength, setIsFlipped } = useBuilderStore();
const aisleTextureList: TextureItem[] = [
{ color: "yellow", id: "yellow", brief: "pedestrian walkways", texture: "" },
{ color: "gray", id: "gray", brief: "basic", texture: "" },
{ color: "green", id: "green", brief: "pedestrian walkways", texture: "" },
{ color: "orange", id: "orange", brief: "material flow", texture: "" },
{ color: "blue", id: "blue", brief: "vehicle paths", texture: "" },
{ color: "purple", id: "purple", brief: "material flow", texture: "" },
{ color: "red", id: "red", brief: "safety zone", texture: "" },
{ color: "bright green", id: "#66FF00", brief: "safety zone", texture: "" },
{ color: "yellow-black", id: "yellow-black", brief: "utility aisles", texture: "" },
{ color: "white-black", id: "white-black", brief: "utility aisles", texture: "" },
];
const aisleTypes: {
name: string;
type: AisleTypes;
id: string;
thumbnail: string;
}[] = [
{ name: "Solid", type: "solid-aisle", id: "1", thumbnail: Solid },
{ name: "Dotted", type: "dotted-aisle", id: "2", thumbnail: Dotted },
{ name: "Dashed", type: "dashed-aisle", id: "3", thumbnail: Dashed },
{ name: "Arrow", type: "arrow-aisle", id: "4", thumbnail: Arrow },
{ name: "Continuous Arrows", type: "arrows-aisle", id: "5", thumbnail: Arrows },
{ name: "Directional", type: "junction-aisle", id: "6", thumbnail: Directional },
{ name: "Arc", type: "arc-aisle", id: "7", thumbnail: Arc },
{ name: "Circle", type: "circle-aisle", id: "8", thumbnail: Circle },
];
const handleAisleWidthChange = (value: string) => {
const width = parseFloat(value);
if (!isNaN(width)) {
setAisleWidth(width);
}
};
const handleDashLengthChange = (value: string) => {
const length = parseFloat(value);
if (!isNaN(length)) {
setDashLength(length);
}
};
const handleGapLengthChange = (value: string) => {
const length = parseFloat(value);
if (!isNaN(length)) {
setGapLength(length);
}
};
const handleDotRadiusChange = (value: string) => {
const radius = parseFloat(value);
if (!isNaN(radius)) {
setDotRadius(radius);
}
};
const handleAisleLengthChange = (value: string) => {
const length = parseFloat(value);
if (!isNaN(length)) {
setAisleLength(length);
}
};
const handleIsFlippedChange = () => {
setIsFlipped(!aisleIsFlipped)
};
const dashLengthValue = useMemo(() => {
return dashLength.toString();
}, [aisleType, dashLength]);
const dotRadiusValue = useMemo(() => {
return dotRadius.toString();
}, [aisleType, dotRadius]);
const gapLengthValue = useMemo(() => {
return gapLength.toString();
}, [aisleType, gapLength]);
const aisleWidthValue = useMemo(() => {
return aisleWidth.toString();
}, [aisleType, aisleWidth]);
const aisleLengthValue = useMemo(() => {
return aisleLength.toString();
}, [aisleType, aisleLength]);
const aisleIsFlipped = useMemo(() => {
return isFlipped;
}, [aisleType, isFlipped]);
const renderAdvancedProperties = () => {
switch (aisleType) {
case 'dashed-aisle':
return (
<>
{aisleType &&
<>
<InputWithDropDown
label="Dash Length"
value={`${dashLengthValue}`}
min={0.1}
step={0.1}
max={2}
onChange={handleDashLengthChange}
/>
<InputWithDropDown
label="Gap Length"
value={`${gapLengthValue}`}
min={0.1}
step={0.1}
max={2}
onChange={handleGapLengthChange}
/>
</>
}
</>
);
case 'dotted-aisle':
return (
<>
{aisleType &&
<>
<InputWithDropDown
label="Dot Radius"
value={`${dotRadiusValue}`}
min={0.1}
step={0.1}
max={2}
onChange={handleDotRadiusChange}
/>
<InputWithDropDown
label="Gap Length"
value={`${gapLengthValue}`}
min={0.1}
step={0.1}
max={2}
onChange={handleGapLengthChange}
/>
</>
}
</>
);
case 'arrows-aisle':
return (
<>
{aisleType &&
<>
<InputWithDropDown
label="Arrow Length"
value={`${aisleLengthValue}`}
min={0.1}
step={0.1}
max={2}
onChange={handleAisleLengthChange}
/>
<InputWithDropDown
label="Gap Length"
value={`${gapLengthValue}`}
min={0.1}
step={0.1}
max={2}
onChange={handleGapLengthChange}
/>
</>
}
</>
);
case 'junction-aisle': case 'arc-aisle':
return (
<>
{aisleType &&
<InputToggle
inputKey="Flip Ailse"
label="Flip Aisle"
value={aisleIsFlipped}
onClick={handleIsFlippedChange}
/>
}
</>
);
default:
return null;
}
};
return (
<div className="aisle-properties-container">
<div className="header">Properties</div>
{/* Basic Properties */}
<section>
{aisleType !== 'dotted-aisle' &&
<InputWithDropDown
label="Aisle Width"
value={`${aisleWidthValue}`}
min={0.1}
step={0.1}
max={2}
onChange={handleAisleWidthChange}
/>
}
{renderAdvancedProperties()}
</section>
{/* Presets */}
<section>
<button
className="header"
onClick={() => setCollapsePresets(!collapsePresets)}
aria-expanded={!collapsePresets}
>
<div className="value">Presets</div>
<div className="icon">
<ArrowIcon />
</div>
</button>
{!collapsePresets && (
<div className="presets-list-container">
{aisleTypes.map((val) => (
<div className="preset-list" key={val.id}>
<button
className={`thumbnail ${aisleType === val.type ? "selected" : ""}`}
title={val.name}
onClick={() => setAisleType(val.type)}
>
<img src={val.thumbnail} alt="" />
</button>
</div>
))}
</div>
)}
</section>
{/* Texture */}
<section>
<button
className="header"
onClick={() => setCollapseTexture(!collapseTexture)}
aria-expanded={!collapseTexture}
>
<div className="value">Aisle Texture</div>
<div className="icon" style={{ rotate: collapseTexture ? "" : "-90deg" }}>
<ArrowIcon />
</div>
</button>
{collapseTexture && (
<div className="aisle-texture-container">
{aisleTextureList.map((val) => (
<button
key={val.id}
title={val.brief || val.id}
className={`aisle-list ${aisleColor === val.color ? "selected" : ""}`}
onClick={() => setAisleColor(val.id)}
aria-pressed={aisleColor === val.id}
>
<div className="texture-display">{val.texture}</div>
<div className="aisle-color">{val.color}</div>
<div className="aisle-brief">{`( ${val.brief} )`}</div>
</button>
))}
</div>
)}
</section>
</div>
);
};
export default AisleProperties;

View File

@@ -0,0 +1,103 @@
import React, { useState } from "react";
import InputToggle from "../../../ui/inputs/InputToggle";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import { RemoveIcon } from "../../../icons/ExportCommonIcons";
import PositionInput from "../customInput/PositionInputs";
import RotationInput from "../customInput/RotationInput";
import { useSelectedFloorItem, useObjectPosition, useObjectRotation } from "../../../../store/builder/store";
interface UserData {
id: number; // Unique identifier for the user data
label: string; // Label of the user data field
value: string; // Value of the user data field
}
const AssetProperties: React.FC = () => {
const [userData, setUserData] = useState<UserData[]>([]); // State to track user data
const [nextId, setNextId] = useState(1); // Unique ID for new entries
const { selectedFloorItem } = useSelectedFloorItem();
const { objectPosition } = useObjectPosition();
const { objectRotation } = useObjectRotation();
// Function to handle adding new user data
const handleAddUserData = () => {
const newUserData: UserData = {
id: nextId,
label: `Property ${nextId}`,
value: "",
};
setUserData([...userData, newUserData]);
setNextId(nextId + 1); // Increment the ID for the next entry
};
// Function to update the value of a user data entry
const handleUserDataChange = (id: number, newValue: string) => {
setUserData((prevUserData) =>
prevUserData.map((data) =>
data.id === id ? { ...data, value: newValue } : data
)
);
};
// Remove user data
const handleRemoveUserData = (id: number) => {
setUserData((prevUserData) =>
prevUserData.filter((data) => data.id !== id)
);
};
return (
<div className="asset-properties-container">
{/* Name */}
<div className="header">{selectedFloorItem.userData.modelName}</div>
<section>
{objectPosition.x && objectPosition.z &&
<PositionInput
onChange={() => { }}
value1={parseFloat(objectPosition.x.toFixed(5))}
value2={parseFloat(objectPosition.z.toFixed(5))}
/>
}
{objectRotation.y &&
<RotationInput
onChange={() => { }}
value={parseFloat(objectRotation.y.toFixed(5))}
/>
}
</section>
<section>
<div className="header">Render settings</div>
<InputToggle inputKey="visible" label="Visible" />
<InputToggle inputKey="frustumCull" label="Frustum cull" />
</section>
<section>
<div className="header">User Data</div>
{userData.map((data) => (
<div className="input-container">
<InputWithDropDown
key={data.id}
label={data.label}
value={data.value}
editableLabel
onChange={(newValue) => handleUserDataChange(data.id, newValue)} // Pass the change handler
/>
<div
className="remove-button"
onClick={() => handleRemoveUserData(data.id)}
>
<RemoveIcon />
</div>
</div>
))}
{/* Add new user data */}
<div className="optimize-button" onClick={handleAddUserData}>
+ Add
</div>
</section>
</div>
);
};
export default AssetProperties;

View File

@@ -0,0 +1,314 @@
import React, { useEffect, useState } from "react";
import InputRange from "../../../ui/inputs/InputRange";
import InputToggle from "../../../ui/inputs/InputToggle";
import { AIIcon } from "../../../icons/ExportCommonIcons";
import LabeledButton from "../../../ui/inputs/LabledButton";
import {
useAzimuth,
useElevation,
useLimitDistance,
useRenderDistance,
useResetCamera,
useRoofVisibility,
useSelectedWallItem,
useShadows,
useSocketStore,
useTileDistance,
useToggleView,
useWallVisibility,
} from "../../../../store/builder/store";
import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment";
import * as CONSTANTS from "../../../../types/world/worldConstants";
import { useParams } from "react-router-dom";
const GlobalProperties: React.FC = () => {
const { toggleView, setToggleView } = useToggleView();
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
const { wallVisibility, setWallVisibility } = useWallVisibility();
const { shadows, setShadows } = useShadows();
const { resetCamera, setResetCamera } = useResetCamera();
const { elevation, setElevation } = useElevation();
const { azimuth, setAzimuth } = useAzimuth();
const { renderDistance, setRenderDistance } = useRenderDistance();
const { setPlaneValue, setGridValue, planeValue, gridValue } = useTileDistance();
const { socket } = useSocketStore();
const { limitDistance, setLimitDistance } = useLimitDistance();
const [distance, setDistance] = useState<number>(40);
const [limitGridDistance, setLimitGridDistance] = useState(false);
const [gridDistance, setGridDistance] = useState<number>(3);
const { projectId } = useParams();
const optimizeScene = async (value: any) => {
const email = localStorage.getItem("email");
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
setEnvironment(
organization,
localStorage.getItem("userId")!,
wallVisibility,
roofVisibility,
shadows,
30,
true,
projectId
);
setRenderDistance(30);
setLimitDistance(true);
};
const limitRenderDistance = async () => {
const email = localStorage.getItem("email");
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
if (limitDistance) {
setEnvironment(
organization,
localStorage.getItem("userId")!,
wallVisibility,
roofVisibility,
shadows,
75,
!limitDistance,
projectId
);
setRenderDistance(75);
} else {
setEnvironment(
organization,
localStorage.getItem("userId")!,
wallVisibility,
roofVisibility,
shadows,
renderDistance,
!limitDistance,
projectId
);
}
setLimitDistance(!limitDistance);
};
function updateDistance(value: number) {
setDistance(value);
setRenderDistance(value);
}
function updateGridDistance(value: number) {
setGridDistance(value);
// setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
// setPlaneValue({ height: value * 100, width: value * 100 });
}
function updatedGrid(value: number) {
// console.log(" (value * 100) / 4 : ", (value * 100) / 4);
setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
setPlaneValue({ height: value * 100, width: value * 100 });
}
const updatedDist = async (value: number) => {
const email = localStorage.getItem("email");
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
setRenderDistance(value);
// setDistance(value);
const data = await setEnvironment(
organization,
localStorage.getItem("userId")!,
wallVisibility,
roofVisibility,
shadows,
value,
limitDistance,
projectId
);
};
// Function to toggle roof visibility
const changeRoofVisibility = async () => {
const email = localStorage.getItem("email");
const organization = email!.split("@")[1].split(".")[0];
//using REST
const data = await setEnvironment(
organization,
localStorage.getItem("userId")!,
wallVisibility,
!roofVisibility,
shadows,
renderDistance,
limitDistance,
projectId
);
//
//using Socket
// const visData = {
// organization: organization,
// userId: localStorage.getItem('userId')!,
// wallVisibility: wallVisibility,
// roofVisibility: !roofVisibility,
// shadowVisibility: shadows,
// socketId: socket.id
// };
// socket.emit('v1:Environment:set', visData)
setRoofVisibility(!roofVisibility); // Toggle roof visibility
};
// Function to toggle wall visibility
const changeWallVisibility = async () => {
const email = localStorage.getItem("email");
const organization = email!.split("@")[1].split(".")[0];
//using REST
const data = await setEnvironment(
organization,
localStorage.getItem("userId")!,
!wallVisibility,
roofVisibility,
shadows,
renderDistance,
limitDistance, projectId
);
//
//using Socket
// const visData = {
// organization: organization,
// userId: localStorage.getItem('userId')!,
// wallVisibility: !wallVisibility,
// roofVisibility: roofVisibility,
// shadowVisibility: shadows,
// socketId: socket.id
// };
// socket.emit('v1:Environment:set', visData)
setWallVisibility(!wallVisibility); // Toggle wall visibility
};
const shadowVisibility = async () => {
const email = localStorage.getItem("email");
const organization = email!.split("@")[1].split(".")[0];
//using REST
const data = await setEnvironment(
organization,
localStorage.getItem("userId")!,
wallVisibility,
roofVisibility,
!shadows,
renderDistance,
limitDistance,
projectId
);
//
//using Socket
// const visData = {
// organization: organization,
// userId: localStorage.getItem('userId')!,
// wallVisibility: wallVisibility,
// roofVisibility: roofVisibility,
// shadowVisibility: !shadows,
// socketId: socket.id
// };
// socket.emit('v1:Environment:set', visData)
setShadows(!shadows);
};
const toggleResetCamera = () => {
if (!toggleView) {
setResetCamera(true); // Trigger reset camera action
}
};
// function changeRenderDistance(e: any) {
// if (parseInt(e.target.value) < 20) {
// setRenderDistance(20);
// } else if (parseInt(e.target.value) > 75) {
// setRenderDistance(75);
// } else {
// setRenderDistance(parseInt(e.target.value));
// }
// }
return (
<div className="global-properties-container">
<section>
<div className="header">Environment</div>
<div className="optimize-button" onClick={optimizeScene}>
<AIIcon />
Optimize
</div>
<div className="split"></div>
<InputToggle
value={roofVisibility}
inputKey="1"
label="Roof Visibility"
onClick={changeRoofVisibility}
/>
<InputToggle
value={wallVisibility}
inputKey="2"
label="Wall Visibility"
onClick={changeWallVisibility}
/>
{/* <InputToggle
value={shadows}
inputKey="3"
label="Shadows Visibility"
onClick={shadowVisibility}
/> */}
<LabeledButton
label="Reset Camera"
onClick={toggleResetCamera}
value="Reset"
/>
<div className="split"></div>
{/* //visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor} */}
<InputToggle
inputKey="4"
label="Limit Render Distance"
value={limitDistance}
// onClick={() => {
// setLimitDistance(!limitDistance);
// // setDistance(75);
// // setRenderDistance(75);
// }}
onClick={async () => {
await limitRenderDistance(); // Call the function here
}}
/>
<InputRange
label="Distance"
disabled={!limitDistance}
value={renderDistance}
min={CONSTANTS.distanceConfig.minDistance}
max={CONSTANTS.distanceConfig.maxDistance}
onChange={(value: number) => updateDistance(value)}
onPointerUp={updatedDist}
key={"6"}
/>
{/* <div className="split"></div>
<InputToggle
inputKey="6"
label="Display Grid"
value={limitGridDistance}
onClick={() => {
setLimitGridDistance(!limitGridDistance);
}}
/>
<InputRange
label="Tile Distance"
disabled={!limitGridDistance}
value={gridDistance}
key={"7"}
min={1}
max={5}
onChange={(value: number) => updateGridDistance(value)}
onPointerUp={updatedGrid}
/> */}
</section>
</div>
);
};
export default GlobalProperties;

View File

@@ -0,0 +1,128 @@
import React, { useEffect, useState } from "react";
import RenameInput from "../../../ui/inputs/RenameInput";
import Vector3Input from "../customInput/Vector3Input";
import { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore";
import {
useEditPosition,
usezonePosition,
useZones,
usezoneTarget,
} from "../../../../store/builder/store";
import { zoneCameraUpdate } from "../../../../services/visulization/zone/zoneCameraUpdation";
import { useParams } from "react-router-dom";
const ZoneProperties: React.FC = () => {
const { Edit, setEdit } = useEditPosition();
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const { zonePosition, setZonePosition } = usezonePosition();
const { zoneTarget, setZoneTarget } = usezoneTarget();
const { zones, setZones } = useZones();
const { projectId } = useParams()
useEffect(() => {
setZonePosition(selectedZone.zoneViewPortPosition);
setZoneTarget(selectedZone.zoneViewPortTarget);
}, [selectedZone?.zoneViewPortPosition, selectedZone?.zoneViewPortTarget]);
async function handleSetView() {
try {
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
let zonesdata = {
zoneUuid: selectedZone.zoneUuid,
viewPortposition: zonePosition,
viewPortCenter: zoneTarget,
};
let response = await zoneCameraUpdate(zonesdata, organization, projectId);
console.log('response: ', response);
if (response.message === "zone updated") {
setEdit(false);
} else {
// console.log(response);
}
} catch (error) {
echo.error("Failed to set zone view");
}
}
function handleEditView() {
setEdit(!Edit); // This will toggle the `Edit` state correctly
}
async function handleZoneNameChange(newName: string) {
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const zonesdata = {
zoneUuid: selectedZone.zoneUuid,
zoneName: newName,
};
// Call your API to update the zone
let response = await zoneCameraUpdate(zonesdata, organization, projectId);
if (response.message === "zone updated") {
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
setZones((prevZones: any[]) =>
prevZones.map((zone) =>
zone.zoneUuid === selectedZone.zoneUuid
? { ...zone, zoneName: newName }
: zone
)
);
} else {
// console.log(response?.message);
}
}
function handleVectorChange(
key: "zoneViewPortTarget" | "zoneViewPortPosition",
newValue: [number, number, number]
) {
setSelectedZone((prev) => ({ ...prev, [key]: newValue }));
}
const checkZoneNameDuplicate = (name: string) => {
return zones.some(
(zone: any) =>
zone.zoneName?.trim().toLowerCase() === name?.trim().toLowerCase() &&
zone.zoneUuid !== selectedZone.zoneUuid
);
};
return (
<div className="zone-properties-container">
<section>
<div className="header">
<RenameInput
value={selectedZone.zoneName}
onRename={handleZoneNameChange}
checkDuplicate={checkZoneNameDuplicate}
/>
<div className="button" onClick={handleEditView}>
{Edit ? "Cancel" : "Edit"}
</div>
</div>
<Vector3Input
onChange={(value) => handleVectorChange("zoneViewPortTarget", value)}
header="Viewport Target"
value={zoneTarget as [number, number, number]}
disabled={!Edit}
/>
<Vector3Input
onChange={(value) =>
handleVectorChange("zoneViewPortPosition", value)
}
header="Viewport Position"
value={zonePosition as [number, number, number]}
disabled={!Edit}
/>
{Edit && (
<div className="button-save" onClick={handleSetView}>
Set View
</div>
)}
</section>
</div>
);
};
export default ZoneProperties;

View File

@@ -0,0 +1,137 @@
import React, { useEffect, useState } from "react";
import {
useSelectedEventData,
useSelectedEventSphere,
} from "../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../store/simulation/useProductStore";
import ConveyorMechanics from "./mechanics/conveyorMechanics";
import VehicleMechanics from "./mechanics/vehicleMechanics";
import RoboticArmMechanics from "./mechanics/roboticArmMechanics";
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";
import { useProductContext } from "../../../../../modules/simulation/products/productContext";
import { useParams } from "react-router-dom";
const EventProperties: React.FC = () => {
const { selectedEventData } = useSelectedEventData();
const { getEventByModelUuid } = useProductStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const [currentEventData, setCurrentEventData] = useState<EventsSchema | null>(
null
);
const [assetType, setAssetType] = useState<string | null>(null);
const { products, addEvent } = useProductStore();
const { selectedEventSphere } = useSelectedEventSphere();
const { projectId } = useParams();
useEffect(() => {
const event = getCurrentEventData();
setCurrentEventData(event);
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.productUuid,
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;
}
};
return (
<div className="event-proprties-wrapper">
{currentEventData && (
<>
<div className="header">
<div className="header-value">
{selectedEventData?.data.modelName}
</div>
</div>
{assetType === "conveyor" && <ConveyorMechanics />}
{assetType === "vehicle" && <VehicleMechanics />}
{assetType === "roboticArm" && <RoboticArmMechanics />}
{assetType === "machine" && <MachineMechanics />}
{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>
<div className="product-item">
{products.map((product) => (
<button
id="add-event-to-product-button"
key={product.productUuid}
onClick={() => {
if (selectedEventData) {
handleAddEventToProduct({
event: useEventsStore
.getState()
.getEventByModelUuid(
selectedEventData?.data.modelUuid
),
addEvent,
selectedProduct,
projectId: projectId || ''
});
}
}}
>
<AddIcon />
{product.productName}
</button>
))}
</div>
</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>
);
};
export default EventProperties;

View File

@@ -0,0 +1,201 @@
import { useEffect, useState } from "react";
import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown";
import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons";
// Texture Imports
import wallTexture1 from "../../../../../assets/image/wallTextures/wallTexture.png";
import defaultTexture from "../../../../../assets/image/wallTextures/defaultTexture.jpg";
import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
// Define Material type
type Material = {
texture: string;
textureName: string;
};
// Initial and default material
const initialMaterial: Material = {
texture: wallTexture1,
textureName: "Grunge Concrete Wall",
};
const defaultMaterial: Material = {
texture: defaultTexture,
textureName: "Default Material",
};
const WallProperties = () => {
const { wallHeight, wallThickness, setWallHeight, setWallThickness } = useBuilderStore();
const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1");
const [materials, setMaterials] = useState<Material[]>([initialMaterial]);
const [selectedMaterials, setSelectedMaterials] = useState<{
side1: Material | null;
side2: Material | null;
}>({
side1: null,
side2: null,
});
// Select initial material for both sides on mount
useEffect(() => {
setSelectedMaterials({
side1: initialMaterial,
side2: initialMaterial,
});
}, []);
const handleHeightChange = (newValue: string) => {
setWallHeight(parseFloat(newValue));
};
const handleThicknessChange = (newValue: string) => {
setWallThickness(parseFloat(newValue));
};
const handleAddMaterial = () => {
const newMaterial: Material = {
texture: defaultMaterial.texture,
textureName: `Material ${materials.length + 1}`,
};
setMaterials([...materials, newMaterial]);
};
const handleSelectMaterial = (material: Material) => {
setSelectedMaterials((prev) => ({
...prev,
[activeSide]: material,
}));
};
const handleRemoveMaterial = (index: number) => {
const updatedMaterials = materials.filter((_, i) => i !== index);
// Ensure there's always at least one material
const newMaterials =
updatedMaterials.length === 0 ? [defaultMaterial] : updatedMaterials;
setMaterials(newMaterials);
// Deselect the material if it's the one removed
setSelectedMaterials((prev) => {
const updated = { ...prev };
["side1", "side2"].forEach((side) => {
if (
updated[side as "side1" | "side2"]?.texture ===
materials[index].texture
) {
updated[side as "side1" | "side2"] = defaultMaterial;
}
});
return updated;
});
};
return (
<div className="wall-properties-container">
<div className="header">Wall</div>
<div className="wall-properties">
<InputWithDropDown
label="Height"
value={`${wallHeight}`}
onChange={(val) => handleHeightChange(val)}
/>
<InputWithDropDown
label="Thickness"
value={`${wallThickness}`}
onChange={(val) => handleThicknessChange(val)}
/>
</div>
<section>
<div className="header-wrapper">
<div className="header">Materials</div>
<button className="addMaterial" onClick={handleAddMaterial}>
<AddIcon />
</button>
</div>
<div className="material-preview">
<div className="sides-wrapper">
<div
className={`side-wrapper ${activeSide === "side1" ? "active" : ""
}`}
onClick={() => setActiveSide("side1")}
>
<div className="label">Side 1</div>
<div className="texture-image">
{selectedMaterials.side1 && (
<img
src={selectedMaterials.side1.texture}
alt={selectedMaterials.side1.textureName}
/>
)}
</div>
</div>
<div
className={`side-wrapper ${activeSide === "side2" ? "active" : ""
}`}
onClick={() => setActiveSide("side2")}
>
<div className="label">Side 2</div>
<div className="texture-image">
{selectedMaterials.side2 && (
<img
src={selectedMaterials.side2.texture}
alt={selectedMaterials.side2.textureName}
/>
)}
</div>
</div>
</div>
<div className="preview">
{selectedMaterials[activeSide] && (
<img
src={selectedMaterials[activeSide]!.texture}
alt={selectedMaterials[activeSide]!.textureName}
/>
)}
</div>
</div>
<div className="materials">
{materials.length === 0 ? (
<div className="no-materials">No materials added yet.</div>
) : (
<div className="material-container">
{materials.map((material, index) => (
<div
className="material-wrapper"
key={`${material.textureName}_${index}`}
onClick={() => handleSelectMaterial(material)}
>
<div className="material-property">
<div className="material-image">
<img src={material.texture} alt={material.textureName} />
</div>
<div className="material-name">{material.textureName}</div>
</div>
<div
className="delete-material"
onClick={(e) => {
e.stopPropagation();
handleRemoveMaterial(index);
}}
>
<RemoveIcon />
</div>
</div>
))}
</div>
)}
</div>
</section>
</div>
);
};
export default WallProperties;

View File

@@ -0,0 +1,7 @@
import React from "react";
const DefaultAction:React.FC = () => {
return <></>;
};
export default DefaultAction;

View File

@@ -0,0 +1,34 @@
import React from "react";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
interface DelayActionProps {
value: string;
defaultValue: string;
min: number;
max: number;
onChange: (value: string) => void;
}
const DelayAction: React.FC<DelayActionProps> = ({
value,
defaultValue,
min,
max,
onChange,
}) => {
return (
<InputWithDropDown
label="Delay"
value={value}
min={min}
step={0.1}
defaultValue={defaultValue}
max={max}
activeOption="s"
onClick={() => {}}
onChange={onChange}
/>
);
};
export default DelayAction;

View File

@@ -0,0 +1,10 @@
import React from "react";
const DespawnAction: React.FC = () => {
return (
<>
</>
);
};
export default DespawnAction;

View File

@@ -0,0 +1,29 @@
import React from "react";
interface PickAndPlaceActionProps {
clearPoints: () => void;
}
const PickAndPlaceAction: React.FC<PickAndPlaceActionProps> = ({
clearPoints,
}) => {
return (
<div className="selected-actions-list">
<div className="value-field-container">
<div className="label">Reset</div>
<button
id="pick-and-place-action-clear-button"
type="button"
className="regularDropdown-container"
onClick={() => {
clearPoints();
}}
>
Clear
</button>
</div>
</div>
);
};
export default PickAndPlaceAction;

View File

@@ -0,0 +1,48 @@
import React from "react";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import SwapAction from "./SwapAction";
interface ProcessActionProps {
value: string;
min: number;
max: number;
defaultValue: string;
onChange: (value: string) => void;
swapOptions: string[];
swapDefaultOption: string;
onSwapSelect: (value: string) => void;
}
const ProcessAction: React.FC<ProcessActionProps> = ({
value,
min,
max,
defaultValue,
onChange,
swapOptions,
swapDefaultOption,
onSwapSelect,
}) => {
return (
<>
<InputWithDropDown
label="Process Time"
value={value}
min={min}
step={1}
max={max}
defaultValue={defaultValue}
activeOption="s"
onClick={() => { }}
onChange={onChange}
/>
<SwapAction
options={swapOptions}
defaultOption={swapDefaultOption}
onSelect={onSwapSelect}
/>
</>
);
};
export default ProcessAction;

View File

@@ -0,0 +1,72 @@
import React from "react";
import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
interface SpawnActionProps {
onChangeInterval: (value: string) => void;
onChangeCount: (value: string) => void;
defaultOption: string;
options: string[];
onSelect: (option: string) => void;
intervalValue: string;
countValue: string;
intervalMin: number;
intervalMax: number;
intervalDefaultValue: string;
countMin: number;
countMax: number;
countDefaultValue: string;
}
const SpawnAction: React.FC<SpawnActionProps> = ({
onChangeInterval,
onChangeCount,
defaultOption,
options,
onSelect,
intervalValue,
countValue,
intervalMin,
intervalMax,
intervalDefaultValue,
countMin,
countMax,
countDefaultValue,
}) => {
return (
<>
<InputWithDropDown
label="Spawn interval"
value={intervalValue}
min={intervalMin}
step={1}
defaultValue={intervalDefaultValue}
max={intervalMax}
activeOption="s"
onClick={() => { }}
onChange={onChangeInterval}
/>
<InputWithDropDown
label="Spawn count"
value={countValue}
min={countMin}
step={1}
defaultValue={countDefaultValue}
max={countMax}
activeOption="s"
onClick={() => { }}
onChange={onChangeCount}
/>
{/* <PreviewSelectionWithUpload /> */}
<LabledDropdown
label="Presets"
defaultOption={defaultOption}
options={options}
onSelect={onSelect}
/>
</>
);
};
export default SpawnAction;

View File

@@ -0,0 +1,57 @@
import React from "react";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
interface StorageActionProps {
type: "store" | "spawn" | "default";
value: string;
min: number;
max?: number;
defaultValue: string;
currentMaterialType: string;
handleCapacityChange: (value: string) => void;
handleMaterialTypeChange: (value: string) => void;
}
const StorageAction: React.FC<StorageActionProps> = ({ type, value, min, max, defaultValue, currentMaterialType, handleCapacityChange, handleMaterialTypeChange }) => {
return (
<>
{type === 'store' &&
<InputWithDropDown
label="Storage Capacity"
value={value}
min={min}
step={1}
max={max}
defaultValue={defaultValue}
activeOption="unit"
onClick={() => { }}
onChange={handleCapacityChange}
/>
}
{type === 'spawn' &&
<>
<InputWithDropDown
label="Spawn Capacity"
value={value}
min={min}
step={1}
max={max}
defaultValue={defaultValue}
activeOption="unit"
onClick={() => { }}
onChange={handleCapacityChange}
/>
<LabledDropdown
label={"Material Type"}
defaultOption={currentMaterialType}
options={["Default material", "Material 1", "Material 2", "Material 3"]}
onSelect={handleMaterialTypeChange}
/>
</>
}
</>
);
};
export default StorageAction;

View File

@@ -0,0 +1,25 @@
import React from "react";
import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
interface SwapActionProps {
onSelect: (option: string) => void;
defaultOption: string;
options: string[];
}
const SwapAction: React.FC<SwapActionProps> = ({
onSelect,
defaultOption,
options,
}) => {
return (
<PreviewSelectionWithUpload
label="Presets"
defaultOption={defaultOption}
options={options}
onSelect={onSelect}
/>
);
};
export default SwapAction;

View File

@@ -0,0 +1,95 @@
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;
}
const TravelAction: React.FC<TravelActionProps> = ({
loadCapacity,
unloadDuration,
pickPoint,
unloadPoint,
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}
/>
)}
</>
);
};
export default TravelAction;

View File

@@ -0,0 +1,160 @@
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,
} from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
import { useParams } from "react-router-dom";
interface ActionsListProps {
selectedPointData: any;
multipleAction?: boolean;
handleAddAction?: () => void;
handleDeleteAction?: (actionUuid: string) => void;
}
const ActionsList: React.FC<ActionsListProps> = ({
selectedPointData,
multipleAction = false,
handleAddAction,
handleDeleteAction,
}) => {
const actionsContainerRef = useRef<HTMLDivElement>(null);
// store
const { renameAction } = useProductStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { selectedAction, setSelectedAction } = useSelectedAction();
const { projectId } = useParams();
const handleRenameAction = (newName: string) => {
if (!selectedAction.actionId) return;
const event = renameAction(
selectedProduct.productUuid,
selectedAction.actionId,
newName
);
setSelectedAction(selectedAction.actionId, newName);
if (event) {
upsertProductOrEventApi({
productName: selectedProduct.productName,
productUuid: selectedProduct.productUuid,
projectId,
eventDatas: event,
});
}
};
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>
<button
id="add-action-button"
className="add-button"
onClick={() => {
if (handleAddAction) {
handleAddAction();
}
}}
disabled={!multipleAction}
>
<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
id="action-button"
className="value"
onClick={() =>
handleActionSelect(action.actionUuid, action.actionName)
}
>
<RenameInput
value={action.actionName}
onRename={(value) => handleRenameAction(value)}
/>
</button>
{selectedPointData?.actions?.length > 1 && (
<button
id="remove-action-button"
className="remove-button"
onClick={() => {
if (handleDeleteAction) {
handleDeleteAction(action.actionUuid);
}
}}
>
<RemoveIcon />
</button>
)}
</div>
))}
{!multipleAction && selectedPointData?.action && (
<div
key={selectedPointData.action.actionUuid}
className={`list-item active`}
>
<button
id="action-button"
className="value"
onClick={() =>
handleActionSelect(
selectedPointData.action.actionUuid,
selectedPointData.action.actionName
)
}
>
<RenameInput
value={selectedPointData.action.actionName}
onRename={handleRenameAction}
/>
</button>
</div>
)}
</div>
{multipleAction && (
<button
className="resize-icon"
id="action-resize"
onMouseDown={(e: any) => handleResize(e, actionsContainerRef)}
>
<ResizeHeightIcon />
</button>
)}
</div>
</div>
</div>
);
};
export default ActionsList;

View File

@@ -0,0 +1,6 @@
export function handleActionToggle(uuid: string) {
// This function handles the action toggle for the event properties.
// It updates the selected action and its properties based on the provided UUID.
// The function is currently empty and needs to be implemented.
// You can add your logic here to handle the action toggle.
}

View File

@@ -0,0 +1,6 @@
export function handleDeleteAction(uuid: string) {
// This function handles the action toggle for the event properties.
// It updates the selected action and its properties based on the provided UUID.
// The function is currently empty and needs to be implemented.
// You can add your logic here to handle the action toggle.
}

View File

@@ -0,0 +1,286 @@
import { useEffect, useState } from "react";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import DelayAction from "../actions/DelayAction";
import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import DespawnAction from "../actions/DespawnAction";
import SwapAction from "../actions/SwapAction";
import SpawnAction from "../actions/SpawnAction";
import DefaultAction from "../actions/DefaultAction";
import Trigger from "../trigger/Trigger";
import { useSelectedAction, useSelectedEventData } from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
import { useParams } from "react-router-dom";
function ConveyorMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default");
const [selectedPointData, setSelectedPointData] = useState<ConveyorPointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { setSelectedAction, clearSelectedAction } = useSelectedAction();
const { projectId } = useParams();
useEffect(() => {
if (selectedEventData) {
const point = getPointByUuid(
selectedProduct.productUuid,
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");
setSelectedAction(point.action.actionUuid, point.action.actionName);
}
} else {
clearSelectedAction();
}
}, [selectedProduct, selectedEventData]);
const updateBackend = (
productName: string,
productUuid: string,
projectId: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productUuid: productUuid,
projectId: projectId,
eventDatas: eventData
})
}
const handleSpeedChange = (value: string) => {
if (!selectedEventData) return;
const event = updateEvent(selectedProduct.productUuid, selectedEventData.data.modelUuid, {
speed: parseFloat(value),
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId ||'',
event
);
}
};
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
const validOption = option as | "default" | "spawn" | "swap" | "delay" | "despawn";
setActiveOption(validOption);
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
actionType: validOption,
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId ||'',
event
);
}
};
const handleRenameAction = (newName: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { actionName: newName });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId ||'',
event
);
}
};
const handleSpawnCountChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
spawnCount: parseFloat(value),
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId ||'',
event
);
}
};
const handleSpawnIntervalChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
spawnInterval: parseFloat(value),
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId ||'',
event
);
}
};
const handleMaterialSelect = (material: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { material });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId ||'',
event
);
}
};
const handleDelayChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
delay: parseFloat(value),
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId ||'',
event
);
}
};
const availableActions = {
defaultOption: "default",
options: ["default", "spawn", "swap", "delay", "despawn"],
};
// Get current values from store
const currentSpeed = (getEventByModelUuid(
selectedProduct.productUuid, 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 (
<>
<div key={selectedPointData?.uuid} className="global-props section">
<div className="property-list-container">
<div className="property-item">
<InputWithDropDown
label="Speed"
value={currentSpeed}
min={0}
step={0.1}
defaultValue={"0.5"}
max={10}
activeOption="m/s"
onClick={() => { }}
onChange={handleSpeedChange}
/>
</div>
</div>
</div>
<section>
<ActionsList
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={
selectedPointData
? selectedPointData.action.actionType
: "default"
}
options={availableActions.options}
onSelect={handleActionTypeChange}
/>
{activeOption === "default" && <DefaultAction />}
{activeOption === "spawn" && (
<SpawnAction
onChangeCount={handleSpawnCountChange}
options={["Default material", "Material 1", "Material 2", "Material 3"]}
defaultOption={currentMaterial}
onSelect={handleMaterialSelect}
onChangeInterval={handleSpawnIntervalChange}
intervalValue={currentSpawnInterval}
countValue={currentSpawnCount}
intervalMin={1}
intervalMax={60}
intervalDefaultValue="1"
countMin={1}
countMax={100}
countDefaultValue="1"
/>
)}
{activeOption === "swap" && (
<SwapAction
options={["Default material", "Material 1", "Material 2", "Material 3"]}
defaultOption={currentMaterial}
onSelect={handleMaterialSelect}
/>
)}
{activeOption === "despawn" && <DespawnAction />}
{activeOption === "delay" && (
<DelayAction
value={currentDelay}
defaultValue="0"
min={0}
max={60}
onChange={handleDelayChange}
/>
)}
</div>
</div>
<div className="tirgger">
<Trigger selectedPointData={selectedPointData as any} type={'Conveyor'} />
</div>
</section>
</>
);
}
export default ConveyorMechanics;

View File

@@ -0,0 +1,181 @@
import { useEffect, useState } from "react";
import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from "../trigger/Trigger";
import { useSelectedAction, useSelectedEventData } from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import ProcessAction from "../actions/ProcessAction";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
import { useParams } from "react-router-dom";
function MachineMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "process">("default");
const [selectedPointData, setSelectedPointData] = useState<MachinePointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateAction } = useProductStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { setSelectedAction, clearSelectedAction } = useSelectedAction();
const { projectId } = useParams();
useEffect(() => {
if (selectedEventData) {
const point = getPointByUuid(
selectedProduct.productUuid,
selectedEventData?.data.modelUuid,
selectedEventData?.selectedPoint
) as MachinePointSchema | undefined;
if (point && "action" in point) {
setSelectedPointData(point);
setActiveOption(point.action.actionType as "process");
setSelectedAction(point.action.actionUuid, point.action.actionName);
}
} else {
clearSelectedAction();
}
}, [selectedProduct, selectedEventData]);
const updateBackend = (
productName: string,
productUuid: string,
projectId: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productUuid: productUuid,
projectId: projectId,
eventDatas: eventData
})
}
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
const validOption = option as "process";
setActiveOption(validOption);
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
actionType: validOption,
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
const handleRenameAction = (newName: string) => {
if (!selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { actionName: newName });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
const handleProcessTimeChange = (value: string) => {
if (!selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
processTime: parseFloat(value),
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
const handleMaterialSelect = (material: string) => {
if (!selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
swapMaterial: material,
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
// Get current values from store
const currentActionName = selectedPointData
? selectedPointData.action.actionName
: "Action Name";
const currentProcessTime = selectedPointData
? selectedPointData.action.processTime.toString()
: "1";
const currentMaterial = selectedPointData
? selectedPointData.action.swapMaterial
: "Default material";
const availableActions = {
defaultOption: "process",
options: ["process"],
};
return (
<>
{selectedEventData && (
<section>
<div className="selected-actions-details">
<div className="selected-actions-header">
<RenameInput
value={currentActionName}
onRename={handleRenameAction}
/>
</div>
<ActionsList
selectedPointData={selectedPointData}
/>
<div className="selected-actions-list">
<LabledDropdown
defaultOption="process"
options={availableActions.options}
onSelect={handleActionTypeChange}
/>
{activeOption === "process" && (
<ProcessAction
value={currentProcessTime}
min={0.1}
max={60}
defaultValue="1"
onChange={handleProcessTimeChange}
swapOptions={["Default material", "Material 1", "Material 2", "Material 3"]}
swapDefaultOption={currentMaterial}
onSwapSelect={handleMaterialSelect}
/>
)}
</div>
</div>
<div className="tirgger">
<Trigger selectedPointData={selectedPointData as any} type={'Machine'} />
</div>
</section>
)}
</>
);
}
export default MachineMechanics;

View File

@@ -0,0 +1,276 @@
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, 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/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
import { useParams } from "react-router-dom";
function RoboticArmMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default");
const [selectedPointData, setSelectedPointData] = useState<RoboticArmPointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction, addAction, removeAction, } = useProductStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
const { projectId } = useParams();
useEffect(() => {
if (selectedEventData) {
const point = getPointByUuid(
selectedProduct.productUuid,
selectedEventData.data.modelUuid,
selectedEventData.selectedPoint
) as RoboticArmPointSchema | undefined;
if (point?.actions) {
setSelectedPointData(point);
if (point.actions.length > 0) {
setActiveOption(
point.actions[0].actionType as "default" | "pickAndPlace"
);
setSelectedAction(
point.actions[0].actionUuid,
point.actions[0].actionName
);
}
}
} else {
clearSelectedAction();
}
}, [selectedEventData, selectedProduct]);
const updateBackend = (
productName: string,
productUuid: string,
projectId: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productUuid: productUuid,
projectId: projectId,
eventDatas: eventData,
});
};
const handleRenameAction = (newName: string) => {
if (!selectedAction.actionId) return;
const event = updateAction(
selectedProduct.productUuid,
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 (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
const handleSpeedChange = (value: string) => {
if (!selectedEventData) return;
const event = updateEvent(
selectedProduct.productUuid,
selectedEventData.data.modelUuid,
{ speed: parseFloat(value), }
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
const handleClearPoints = () => {
if (!selectedAction.actionId || !selectedPointData) return;
const event = updateAction(
selectedProduct.productUuid,
selectedAction.actionId,
{
process: {
startPoint: null,
endPoint: null,
},
}
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
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.productUuid,
selectedEventData.data.modelUuid,
selectedEventData.selectedPoint,
newAction
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
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(selectedProduct.productUuid, actionUuid);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
const index = selectedPointData.actions.findIndex((a) => a.actionUuid === actionUuid);
const newActions = selectedPointData.actions.filter((a) => a.actionUuid !== actionUuid);
const updatedPoint = {
...selectedPointData,
actions: newActions,
};
setSelectedPointData(updatedPoint);
if (selectedAction.actionId === actionUuid) {
const nextAction = newActions[index] || newActions[index - 1];
if (nextAction) {
setSelectedAction(nextAction.actionUuid, nextAction.actionName);
} else {
clearSelectedAction();
}
}
};
const availableActions = {
defaultOption: "pickAndPlace",
options: ["pickAndPlace"],
};
const currentSpeed = (getEventByModelUuid(selectedProduct.productUuid, 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 (
<>
<div className="global-props section">
<div className="property-list-container">
<div className="property-item">
<InputWithDropDown
label="Speed"
value={currentSpeed}
min={0}
step={0.1}
defaultValue={"0.5"}
max={10}
activeOption="m/s"
onClick={() => { }}
onChange={handleSpeedChange}
/>
</div>
</div>
</div>
<section>
<ActionsList
selectedPointData={selectedPointData}
multipleAction
handleAddAction={handleAddAction}
handleDeleteAction={handleDeleteAction}
/>
{selectedAction.actionId && currentAction && (
<div className="selected-actions-details">
<div className="selected-actions-header">
<RenameInput
value={selectedAction.actionName || ""}
onRename={handleRenameAction}
/>
</div>
<div className="selected-actions-list">
<LabledDropdown
defaultOption={activeOption}
options={availableActions.options}
onSelect={() => { }}
disabled={true}
/>
<PickAndPlaceAction clearPoints={handleClearPoints} />
</div>
<div className="tirgger">
<Trigger
selectedPointData={selectedPointData as any}
type={"RoboticArm"}
/>
</div>
</div>
)}
</section>
</>
);
}
export default RoboticArmMechanics;

View File

@@ -0,0 +1,220 @@
import { useEffect, useMemo, useState } from "react";
import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from "../trigger/Trigger";
import StorageAction from "../actions/StorageAction";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import { useSelectedAction, useSelectedEventData } from "../../../../../../store/simulation/useSimulationStore";
import * as THREE from 'three';
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
import { useParams } from "react-router-dom";
function StorageMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default");
const [selectedPointData, setSelectedPointData] = useState<StoragePointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, updateAction } = useProductStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { setSelectedAction, clearSelectedAction } = useSelectedAction();
const { projectId } = useParams();
const updateSelectedPointData = () => {
if (selectedEventData && selectedProduct) {
const point = getPointByUuid(
selectedProduct.productUuid,
selectedEventData?.data.modelUuid,
selectedEventData?.selectedPoint
) as StoragePointSchema | undefined;
if (point && "action" in point) {
setSelectedPointData(point);
const uiOption = point.action.actionType === "retrieve" ? "spawn" : point.action.actionType;
setActiveOption(uiOption as "store" | "spawn");
setSelectedAction(point.action.actionUuid, point.action.actionName);
}
}
};
useEffect(() => {
if (selectedEventData) {
const point = getPointByUuid(
selectedProduct.productUuid,
selectedEventData?.data.modelUuid,
selectedEventData?.selectedPoint
) as StoragePointSchema | undefined;
if (point && "action" in point) {
setSelectedPointData(point);
const uiOption = point.action.actionType === "retrieve" ? "spawn" : point.action.actionType;
setActiveOption(uiOption as "store" | "spawn");
setSelectedAction(point.action.actionUuid, point.action.actionName);
}
} else {
clearSelectedAction();
}
}, [selectedProduct, selectedEventData]);
const updateBackend = (
productName: string,
productUuid: string,
projectId: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productUuid: productUuid,
projectId: projectId,
eventDatas: eventData
})
}
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
const internalOption = actionTypeMap[option as keyof typeof actionTypeMap] as "store" | "retrieve";
setActiveOption(option as "store" | "spawn");
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
actionType: internalOption,
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
updateSelectedPointData();
}
};
const handleRenameAction = (newName: string) => {
if (!selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { actionName: newName });
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
updateSelectedPointData();
}
};
const handleCapacityChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const newCapacity = parseInt(value);
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
storageCapacity: newCapacity,
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
updateSelectedPointData();
}
};
const createNewMaterial = (materialType: string): { materialType: string; materialId: string } | null => {
if (!selectedEventData || !selectedPointData) return null;
const materialId = THREE.MathUtils.generateUUID();
return {
materialType,
materialId
};
};
const handleMaterialTypeChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
materialType: value,
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
updateSelectedPointData();
}
};
const currentActionName = useMemo(() =>
selectedPointData ? selectedPointData.action.actionName : "Action Name",
[selectedPointData]
);
const currentCapacity = useMemo(() =>
selectedPointData ? selectedPointData.action.storageCapacity.toString() : "0",
[selectedPointData]
);
const currentMaterialType = useMemo(() =>
selectedPointData?.action.materialType || "Default material",
[selectedPointData]
);
const availableActions = {
defaultOption: "store",
options: ["store", "spawn"],
};
const actionTypeMap = {
spawn: "retrieve",
store: "store"
};
return (
<>
{selectedEventData && (
<section>
<ActionsList
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={activeOption}
options={availableActions.options}
onSelect={handleActionTypeChange}
/>
<StorageAction
type={activeOption}
value={currentCapacity}
defaultValue="0"
min={0}
currentMaterialType={currentMaterialType}
handleCapacityChange={handleCapacityChange}
handleMaterialTypeChange={handleMaterialTypeChange}
/>
</div>
</div>
<div className="tirgger">
<Trigger selectedPointData={selectedPointData as any} type={'StorageUnit'} />
</div>
</section>
)}
</>
);
}
export default StorageMechanics;

View File

@@ -0,0 +1,296 @@
import { useEffect, useState } from "react";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from "../trigger/Trigger";
import {
useSelectedAction,
useSelectedEventData,
} from "../../../../../../store/simulation/useSimulationStore";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import TravelAction from "../actions/TravelAction";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
import { useParams } from "react-router-dom";
function VehicleMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "travel">("default");
const [selectedPointData, setSelectedPointData] = useState<VehiclePointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { setSelectedAction, clearSelectedAction } = useSelectedAction();
const { projectId } = useParams();
useEffect(() => {
if (selectedEventData && selectedEventData.data.type === "vehicle") {
const point = getPointByUuid(
selectedProduct.productUuid,
selectedEventData.data.modelUuid,
selectedEventData.selectedPoint
) as VehiclePointSchema | undefined;
if (point) {
setSelectedPointData(point);
setActiveOption(point.action.actionType as "travel");
setSelectedAction(point.action.actionUuid, point.action.actionName);
}
} else {
clearSelectedAction();
}
}, [selectedProduct, selectedEventData]);
const updateBackend = (
productName: string,
productUuid: string,
projectId: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productUuid: productUuid,
projectId: projectId,
eventDatas: eventData,
});
};
const handleSpeedChange = (value: string) => {
if (!selectedEventData) return;
const event = updateEvent(
selectedProduct.productUuid,
selectedEventData.data.modelUuid,
{
speed: parseFloat(value),
}
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
const validOption = option as "travel";
setActiveOption(validOption);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{
actionType: validOption,
}
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
const handleRenameAction = (newName: string) => {
if (!selectedPointData) return;
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{ actionName: newName }
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
const handleLoadCapacityChange = (value: string) => {
if (!selectedPointData) return;
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{
loadCapacity: parseFloat(value),
}
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
const handleUnloadDurationChange = (value: string) => {
if (!selectedPointData) return;
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{
unLoadDuration: parseFloat(value),
}
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
const handlePickPointChange = (value: string) => {
if (!selectedPointData) return;
};
const handleUnloadPointChange = (value: string) => {
if (!selectedPointData) return;
};
// Get current values from store
const currentSpeed =
(
getEventByModelUuid(
selectedProduct.productUuid,
selectedEventData?.data.modelUuid || ""
) as VehicleEventSchema | undefined
)?.speed?.toString() || "0.5";
const currentActionName = selectedPointData
? selectedPointData.action.actionName
: "Action Name";
const currentLoadCapacity = selectedPointData
? selectedPointData.action.loadCapacity.toString()
: "1";
const currentUnloadDuration = selectedPointData
? selectedPointData.action.unLoadDuration.toString()
: "1";
function handleClearPoints() {
if (!selectedEventData || !selectedPointData?.action.actionUuid) return;
const event = updateAction(
selectedProduct.productUuid, selectedPointData.action.actionUuid, {
pickUpPoint: null,
unLoadPoint: null,
steeringAngle: 0,
})
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
}
const availableActions = {
defaultOption: "travel",
options: ["travel"],
};
return (
<>
{selectedEventData && (
<>
<div className="global-props section">
<div className="property-list-container">
<div className="property-item">
<InputWithDropDown
label="Speed"
value={currentSpeed}
min={0}
step={0.1}
defaultValue={"0.5"}
max={10}
activeOption="m/s"
onClick={() => { }}
onChange={handleSpeedChange}
/>
</div>
</div>
</div>
<section>
<ActionsList 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}
/>
{activeOption === "travel" && (
<TravelAction
loadCapacity={{
value: currentLoadCapacity,
min: 1,
max: 100,
defaultValue: "1",
onChange: handleLoadCapacityChange,
}}
unloadDuration={{
value: currentUnloadDuration,
min: 1,
max: 60,
defaultValue: "1",
onChange: handleUnloadDurationChange,
}}
clearPoints={handleClearPoints}
// pickPoint={{
// value: currentPickPoint,
// onChange: handlePickPointChange,
// }}
// unloadPoint={{
// value: currentUnloadPoint,
// onChange: handleUnloadPointChange,
// }}
/>
)}
</div>
</div>
<div className="tirgger">
<Trigger
selectedPointData={selectedPointData as any}
type={"Vehicle"}
/>
</div>
</section>
</>
)}
</>
);
}
export default VehicleMechanics;

View File

@@ -0,0 +1,442 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import * as THREE from "three";
import { AddIcon, RemoveIcon, ResizeHeightIcon } from "../../../../../icons/ExportCommonIcons";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import RenameInput from "../../../../../ui/inputs/RenameInput";
import { handleResize } from "../../../../../../functions/handleResizePannel";
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
import { useSelectedAction } from "../../../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
import { useParams } from "react-router-dom";
type TriggerProps = {
selectedPointData?: PointsScheme | undefined;
type?: "Conveyor" | "Vehicle" | "RoboticArm" | "Machine" | "StorageUnit";
};
const Trigger = ({ selectedPointData, type }: TriggerProps) => {
const [currentAction, setCurrentAction] = useState<string | undefined>();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { getActionByUuid, getEventByModelUuid, getPointByUuid, getTriggerByUuid, addTrigger, removeTrigger, updateTrigger, renameTrigger, getProductById, } = useProductStore();
const [triggers, setTriggers] = useState<TriggerSchema[]>([]);
const [selectedTrigger, setSelectedTrigger] = useState<TriggerSchema | undefined>();
const [activeOption, setActiveOption] = useState<"onComplete" | "onStart" | "onStop" | "delay" | "onError">("onComplete");
const triggersContainerRef = useRef<HTMLDivElement>(null);
const { selectedAction } = useSelectedAction();
const { projectId } = useParams();
useEffect(() => {
if (!selectedPointData || !selectedProduct) return;
let actionUuid: string | undefined;
if (type === "Conveyor" || type === "Vehicle" || type === "Machine" || type === "StorageUnit") {
actionUuid = (selectedPointData as | ConveyorPointSchema | VehiclePointSchema | MachinePointSchema | StoragePointSchema).action?.actionUuid;
} else if (type === "RoboticArm" && selectedAction.actionId) {
actionUuid = selectedAction.actionId;
}
setCurrentAction(actionUuid);
}, [selectedPointData, selectedProduct, type, selectedAction]);
const updateBackend = (
productName: string,
productUuid: string,
projectId: string,
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productUuid: productUuid,
projectId: projectId,
eventDatas: eventData,
});
};
useEffect(() => {
if (!currentAction || !selectedProduct) return;
const action = getActionByUuid(selectedProduct.productUuid, currentAction);
const actionTriggers = action?.triggers || [];
setTriggers(actionTriggers);
setSelectedTrigger(actionTriggers[0]);
}, [currentAction, selectedProduct]);
const triggeredModel = useMemo(() => {
if (!selectedProduct || !selectedTrigger?.triggeredAsset?.triggeredModel?.modelUuid)
return undefined;
return getEventByModelUuid(
selectedProduct.productUuid,
selectedTrigger.triggeredAsset.triggeredModel.modelUuid
);
}, [selectedProduct, selectedTrigger]);
const triggeredPoint = useMemo(() => {
if (!selectedProduct || !triggeredModel || !selectedTrigger?.triggeredAsset?.triggeredPoint?.pointUuid)
return undefined;
return getPointByUuid(
selectedProduct.productUuid,
triggeredModel.modelUuid,
selectedTrigger.triggeredAsset.triggeredPoint.pointUuid
);
}, [selectedProduct, triggeredModel, selectedTrigger]);
const triggeredAction = useMemo(() => {
if (!selectedProduct || !selectedTrigger?.triggeredAsset?.triggeredAction?.actionUuid)
return undefined;
return getActionByUuid(
selectedProduct.productUuid,
selectedTrigger.triggeredAsset.triggeredAction.actionUuid
);
}, [selectedProduct, selectedTrigger]);
const modelOptions = getProductById(selectedProduct.productUuid)?.eventDatas || [];
const pointOptions: PointsScheme[] = useMemo(() => {
if (!triggeredModel) return [];
const model = modelOptions.find((m) => m.modelUuid === triggeredModel.modelUuid);
if (!model) return [];
if ("points" in model) {
return (model).points;
} else if ("point" in model) {
return [model.point];
}
return [];
}, [triggeredModel, modelOptions]);
const actionOptions: any = useMemo(() => {
if (!triggeredPoint) return [];
const point = pointOptions.find((p) => p.uuid === triggeredPoint.uuid);
if (!point) return [];
if ("action" in point) {
const typedPoint = point;
return typedPoint.action ? [typedPoint.action] : [];
} else if ("actions" in point) {
const typedPoint = point;
return typedPoint.actions;
}
return [];
}, [triggeredPoint, pointOptions]);
const handleModelSelect = (option: string, triggerUuid: string) => {
if (!selectedProduct) return;
const selectedModel = modelOptions.find((m) => m.modelName === option);
if (!selectedModel) return;
const event = updateTrigger(selectedProduct.productUuid, triggerUuid, {
triggeredAsset: {
triggeredModel: {
modelName: selectedModel.modelName,
modelUuid: selectedModel.modelUuid,
},
triggeredPoint: null,
triggeredAction: null,
},
});
if (event) {
const updatedTrigger = getTriggerByUuid(
selectedProduct.productUuid,
triggerUuid
);
setSelectedTrigger(updatedTrigger);
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
const handlePointSelect = (option: string, triggerUuid: string) => {
if (!selectedProduct || !selectedTrigger) return;
const pointUuid = pointOptions.find((p) => `Point ${p.uuid.slice(0, 4)}` === option)?.uuid;
if (!pointUuid) return;
if (selectedTrigger.triggeredAsset?.triggeredModel) {
const event = updateTrigger(selectedProduct.productUuid, triggerUuid, {
triggeredAsset: {
...selectedTrigger.triggeredAsset,
triggeredPoint: {
pointName: option,
pointUuid: pointUuid,
},
triggeredAction: null,
},
});
if (event) {
const updatedTrigger = getTriggerByUuid(
selectedProduct.productUuid,
triggerUuid
);
setSelectedTrigger(updatedTrigger);
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
}
};
const handleActionSelect = (option: string, triggerUuid: string) => {
if (!selectedProduct || !selectedTrigger) return;
const selectedAction = actionOptions.find((a: any) => a.actionName === option);
if (!selectedAction) return;
if (selectedTrigger.triggeredAsset?.triggeredPoint) {
const event = updateTrigger(selectedProduct.productUuid, triggerUuid, {
triggeredAsset: {
...selectedTrigger.triggeredAsset,
triggeredAction: {
actionName: option,
actionUuid: selectedAction.actionUuid,
},
},
});
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
}
};
const handleAddTrigger = () => {
if (!selectedProduct || !currentAction) return;
const newTrigger: TriggerSchema = {
triggerUuid: THREE.MathUtils.generateUUID(),
triggerName: `New Trigger ${triggers.length + 1}`,
triggerType: activeOption,
delay: 0,
triggeredAsset: null,
};
const event = addTrigger(
selectedProduct.productUuid,
currentAction,
newTrigger
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
const updatedAction = getActionByUuid(
selectedProduct.productUuid,
currentAction
);
const updatedTriggers = updatedAction?.triggers || [];
setTriggers(updatedTriggers);
setSelectedTrigger(newTrigger);
};
const handleRemoveTrigger = (triggerUuid: string) => {
if (!selectedProduct || !currentAction) return;
const event = removeTrigger(selectedProduct.productUuid, triggerUuid);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
const index = triggers.findIndex((t) => t.triggerUuid === triggerUuid);
const newTriggers = triggers.filter((t) => t.triggerUuid !== triggerUuid);
setTriggers(newTriggers);
if (selectedTrigger?.triggerUuid === triggerUuid) {
const nextTrigger = newTriggers[index] || newTriggers[index - 1];
setSelectedTrigger(nextTrigger);
}
};
const handleTriggerRename = (triggerUuid: string, newName: string) => {
if (!selectedProduct) return;
const event = renameTrigger(
selectedProduct.productUuid,
triggerUuid,
newName
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
const handleTriggerTypeChange = (option: string) => {
if (!selectedTrigger || !selectedProduct) return;
const validTypes: Array<TriggerSchema["triggerType"]> = ["onComplete", "onStart", "onStop", "delay", "onError",];
if (!validTypes.includes(option as TriggerSchema["triggerType"])) return;
setActiveOption(option as TriggerSchema["triggerType"]);
const event = updateTrigger(
selectedProduct.productUuid,
selectedTrigger.triggerUuid,
{
triggerType: option as TriggerSchema["triggerType"],
}
);
if (event) {
updateBackend(
selectedProduct.productName,
selectedProduct.productUuid,
projectId || '',
event
);
}
};
return (
<div className="trigger-wrapper">
<div className="header">
<div className="title">Trigger</div>
<button
id="add-trigger-button"
className="add-button"
onClick={handleAddTrigger}
style={{ cursor: "pointer" }}
disabled={!currentAction}
>
<AddIcon /> Add
</button>
</div>
<div className="trigger-list">
<div
className="lists-main-container"
ref={triggersContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{triggers.map((trigger) => (
<div
key={trigger.triggerUuid}
className={`list-item ${selectedTrigger?.triggerUuid === trigger.triggerUuid
? "active"
: ""
}`}
onClick={() => setSelectedTrigger(trigger)}
>
<button id="trigger" className="value">
<RenameInput
value={trigger.triggerName}
onRename={(newName) =>
handleTriggerRename(trigger.triggerUuid, newName)
}
/>
</button>
{triggers.length > 1 && (
<button
id="remove-trigger-button"
className="remove-button"
onClick={(e) => {
e.stopPropagation();
handleRemoveTrigger(trigger.triggerUuid);
}}
>
<RemoveIcon />
</button>
)}
</div>
))}
</div>
<button
className="resize-icon"
id="action-resize"
onMouseDown={(e: any) => handleResize(e, triggersContainerRef)}
>
<ResizeHeightIcon />
</button>
</div>
{selectedTrigger && (
<div className="trigger-item">
<div className="trigger-name">{selectedTrigger.triggerName}</div>
<LabledDropdown
label="Trigger Type"
defaultOption={selectedTrigger.triggerType}
// options={["onComplete", "onStart", "onStop", "delay", "onError"]}
options={["onComplete"]}
onSelect={handleTriggerTypeChange}
/>
<div className="trigger-options">
<LabledDropdown
label="Triggered Object"
defaultOption={triggeredModel?.modelName || ""}
options={[...modelOptions.map((option) => option.modelName)]}
onSelect={(option) => {
handleModelSelect(option, selectedTrigger.triggerUuid);
}}
/>
<LabledDropdown
label="Triggered Point"
defaultOption={
triggeredPoint?.uuid
? `Point ${triggeredPoint?.uuid.slice(0, 4)}`
: ""
}
options={[
...pointOptions.map(
(option) => `Point ${option.uuid.slice(0, 4)}`
),
]}
onSelect={(option) => {
handlePointSelect(option, selectedTrigger.triggerUuid);
}}
/>
<LabledDropdown
label="Triggered Action"
defaultOption={triggeredAction?.actionName || ""}
options={[
...actionOptions.map((option: any) => option.actionName),
]}
onSelect={(option) => {
handleActionSelect(option, selectedTrigger.triggerUuid);
}}
/>
</div>
</div>
)}
</div>
</div>
);
};
export default Trigger;

View File

@@ -0,0 +1,278 @@
import React, { useEffect, useRef, useState } from "react";
import { AddIcon, ArrowIcon, RemoveIcon, ResizeHeightIcon, } from "../../../icons/ExportCommonIcons";
import RenameInput from "../../../ui/inputs/RenameInput";
import { handleResize } from "../../../../functions/handleResizePannel";
import { useSelectedAsset } 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 { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct";
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
import { deleteEventDataApi } from "../../../../services/simulation/products/deleteEventDataApi";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { deleteProductApi } from "../../../../services/simulation/products/deleteProductApi";
import { renameProductApi } from "../../../../services/simulation/products/renameProductApi";
import { determineExecutionMachineSequences } from "../../../../modules/simulation/simulator/functions/determineExecutionMachineSequences";
import ComparePopUp from "../../../ui/compareVersion/Compare";
import { useCompareStore, useSaveVersion, } from "../../../../store/builder/store";
import { useToggleStore } from "../../../../store/useUIToggleStore";
import { useProductContext } from "../../../../modules/simulation/products/productContext";
import { useParams } from "react-router-dom";
interface Event {
modelName: string;
modelId: string;
}
interface ListProps {
val: Event;
}
const List: React.FC<ListProps> = ({ val }) => {
return (
<div className="process-container">
<div className="value">{val.modelName}</div>
</div>
);
};
const Simulations: React.FC = () => {
const productsContainerRef = useRef<HTMLDivElement>(null);
const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent, getProductById, } = useProductStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct, setSelectedProduct } = selectedProductStore();
const { getEventByModelUuid } = useEventsStore();
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
const [openObjects, setOpenObjects] = useState(true);
const [processes, setProcesses] = useState<Event[][]>();
const { setToggleUI } = useToggleStore();
const { projectId } = useParams();
const { comparePopUp, setComparePopUp } = useCompareStore();
const { setIsVersionSaved } = useSaveVersion();
const handleSaveVersion = () => {
setIsVersionSaved(true);
setComparePopUp(false);
setToggleUI(false, false);
};
const handleAddProduct = () => {
const id = generateUUID();
const name = `Product ${products.length + 1}`;
addProduct(name, id);
upsertProductOrEventApi({
productName: name,
productUuid: id,
projectId: projectId,
});
};
const handleRemoveProduct = (productUuid: string) => {
const currentIndex = products.findIndex((p) => p.productUuid === productUuid);
const isSelected = selectedProduct.productUuid === productUuid;
const updatedProducts = products.filter((p) => p.productUuid !== productUuid);
if (isSelected) {
if (updatedProducts.length > 0) {
let newSelectedIndex = currentIndex;
if (currentIndex >= updatedProducts.length) {
newSelectedIndex = updatedProducts.length - 1;
}
setSelectedProduct(
updatedProducts[newSelectedIndex].productUuid,
updatedProducts[newSelectedIndex].productName
);
} else {
setSelectedProduct("", "");
}
}
removeProduct(productUuid);
deleteProductApi({
productUuid,
projectId
});
};
const handleRenameProduct = (productUuid: string, newName: string) => {
renameProduct(productUuid, newName);
renameProductApi({ productName: newName, productUuid, projectId: projectId || '' });
if (selectedProduct.productUuid === productUuid) {
setSelectedProduct(productUuid, newName);
}
};
const handleRemoveEventFromProduct = () => {
if (selectedAsset) {
deleteEventDataApi({
productUuid: selectedProduct.productUuid,
modelUuid: selectedAsset.modelUuid,
projectId: projectId,
});
removeEvent(selectedProduct.productUuid, selectedAsset.modelUuid);
clearSelectedAsset();
}
};
useEffect(() => {
const processes: Event[][] = [];
const selectedProductData = getProductById(selectedProduct.productUuid);
if (selectedProductData) {
determineExecutionMachineSequences([selectedProductData]).then(
(sequences) => {
sequences.forEach((sequence) => {
const events: Event[] =
sequence.map((event) => ({
modelName: event.modelName,
modelId: event.modelUuid,
})) || [];
processes.push(events);
});
setProcesses(processes);
}
);
}
}, [selectedProduct.productUuid, products]);
return (
<div className="simulations-container">
<div className="header">Simulations</div>
<div className="add-product-container">
<div className="actions section">
<div className="header">
<div className="header-value">Products</div>
<button
id="add-simulation"
className="add-button"
onClick={handleAddProduct}
>
<AddIcon /> Add
</button>
</div>
<div
className="lists-main-container"
ref={productsContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{products.map((product, index) => (
<div
key={product.productUuid}
className={`list-item ${selectedProduct.productUuid === product.productUuid
? "active"
: ""
}`}
>
{/* eslint-disable-next-line */}
<div
className="value"
onClick={() =>
setSelectedProduct(product.productUuid, product.productName)
}
>
<input
type="radio"
name="products"
checked={selectedProduct.productUuid === product.productUuid}
readOnly
/>
<RenameInput
value={product.productName}
onRename={(newName) =>
handleRenameProduct(product.productUuid, newName)
}
/>
</div>
{products.length > 1 && (
<button
id="remove-product-button"
className="remove-button"
onClick={() => handleRemoveProduct(product.productUuid)}
>
<RemoveIcon />
</button>
)}
</div>
))}
</div>
<button
className="resize-icon"
id="action-resize"
onMouseDown={(e: any) => handleResize(e, productsContainerRef)}
>
<ResizeHeightIcon />
</button>
</div>
</div>
<div className="simulation-process section">
<button
id="collapse-header"
className="collapse-header-container"
onClick={() => setOpenObjects(!openObjects)}
>
<div className="header">Process Flow</div>
<div className="arrow-container">
<ArrowIcon />
</div>
</button>
{openObjects &&
processes?.map((process, index) => (
<section key={index}>
{process.map((event, index) => (
<List key={`${index}-${event.modelName}`} val={event} />
))}
</section>
))}
</div>
<div className="compare-simulations-container">
<div className="compare-simulations-header">
Need to Compare Layout?
</div>
<div className="content">
Click '<span>Compare</span>' to review and analyze the layout
differences between them.
</div>
<button className="input" onClick={() => setComparePopUp(true)}>
<input type="button" value={"Compare"} className="submit" />
</button>
</div>
</div>
{selectedAsset && (
<RenderOverlay>
<EditWidgetOption
options={["Add to Product", "Remove from Product"]}
onClick={(option) => {
if (option === "Add to Product") {
handleAddEventToProduct({
event: getEventByModelUuid(selectedAsset.modelUuid),
addEvent,
selectedProduct,
clearSelectedAsset,
projectId: projectId || ''
});
} else {
handleRemoveEventFromProduct();
}
}}
/>
</RenderOverlay>
)}
{comparePopUp && (
<RenderOverlay>
<ComparePopUp onClose={handleSaveVersion} />
</RenderOverlay>
)}
</div>
);
};
export default Simulations;

View File

@@ -0,0 +1,147 @@
import React, { useState } from "react";
import {
AddIcon,
ArrowIcon,
CloseIcon,
KebabIcon,
LocationIcon,
} from "../../../icons/ExportCommonIcons";
import RenameInput from "../../../ui/inputs/RenameInput";
import { useVersionStore } from "../../../../store/builder/store";
import { generateUniqueId } from "../../../../functions/generateUniqueId";
const VersionHistory = () => {
const userName = localStorage.getItem("userName") ?? "Anonymous";
const { versions, addVersion, setVersions, updateVersion } =
useVersionStore();
const [selectedVersion, setSelectedVersion] = useState(
versions.length > 0 ? versions[0] : null
);
const addNewVersion = () => {
const newVersion = {
id: generateUniqueId(),
versionLabel: `v${versions.length + 1}.0`,
versionName: "",
timestamp: new Date().toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "2-digit",
}),
savedBy: userName,
};
const newVersions = [newVersion, ...versions];
addVersion(newVersion);
setSelectedVersion(newVersion);
setVersions(newVersions);
};
const handleSelectVersion = (version: any) => {
setSelectedVersion(version);
const reordered = [version, ...versions.filter((v) => v.id !== version.id)];
setVersions(reordered);
};
const handleVersionNameChange = (newName: string, versionId: string) => {
const updated = versions.map((v) =>
v.id === versionId ? { ...v, versionName: newName } : v
);
setVersions(updated);
updateVersion(versionId, { versionName: newName });
};
return (
<div className="version-history-container">
{/* Header */}
<div className="version-history-header">
<div className="version-history-title">Version History</div>
<div className="version-history-icons">
<button
id="add-version"
className="icon add-icon"
onClick={addNewVersion}
>
<AddIcon />
</button>
<div id="version-kebab" className="icon kebab-icon">
<KebabIcon />
</div>
<div id="version-close" className="icon close-icon">
<CloseIcon />
</div>
</div>
</div>
{/* Shortcut Info */}
<div className="version-history-shortcut-info">
<div className="info-icon">i</div>
<div className="shortcut-text">
Press Ctrl + Alt + S to add to version history while editing
</div>
</div>
{/* Current Version Display */}
{selectedVersion && (
<div className="version-history-location">
<div className="location-label">
<LocationIcon />
</div>
<div className="location-details">
<div className="current-version">
Current Version ({selectedVersion.versionLabel})
</div>
<div className="saved-history-count">
{versions.length} Saved History
</div>
</div>
</div>
)}
{/* Versions List */}
<div className="saved-versions-list">
{versions.length === 0 ? (
<div className="no-versions-message">No saved versions</div>
) : (
versions.map((version) => (
<button
key={version.id}
className="saved-version"
onClick={() => handleSelectVersion(version)}
>
<div className="version-name">{version.versionLabel}</div>
<div className="version-details">
<div className="details">
<span className="timestamp">
{version.versionName ? (
<RenameInput
value={version.versionName}
onRename={(newName) =>
handleVersionNameChange(newName, version.id)
}
/>
) : (
<RenameInput
value={version.timestamp}
onRename={(newName) =>
handleVersionNameChange(newName, version.id)
}
/>
)}
</span>
<span className="saved-by">
<div className="user-profile">{version.savedBy[0]}</div>
<div className="user-name">{version.savedBy}</div>
</span>
</div>
<ArrowIcon />
</div>
</button>
))
)}
</div>
</div>
);
};
export default VersionHistory;

View File

@@ -0,0 +1,207 @@
import React, { useState, useEffect, useRef } from "react";
import { useVersionStore } from "../../../../store/builder/store";
import {
CloseIcon,
FinishEditIcon,
RenameVersionIcon,
SaveIcon,
SaveVersionIcon,
} from "../../../icons/ExportCommonIcons";
import RenderOverlay from "../../../templates/Overlay";
const VersionSaved = () => {
const { versions, updateVersion } = useVersionStore();
const [isEditing, setIsEditing] = useState(false);
const [shouldDismiss, setShouldDismiss] = useState(false);
const [showNotification, setShowNotification] = useState(false);
const [newName, setNewName] = useState("");
const [description, setDescription] = useState("");
const [showEditedFinish, setShowEditedFinish] = useState(false);
const [editedVersionName, setEditedVersionName] = useState("");
const prevVersionCount = useRef(versions.length);
const dismissTimerRef = useRef<NodeJS.Timeout | null>(null);
const latestVersion = versions?.[0];
useEffect(() => {
return () => {
if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current);
};
}, []);
useEffect(() => {
if (versions.length > prevVersionCount.current && latestVersion) {
setShowNotification(true);
setShouldDismiss(false);
setIsEditing(false);
setNewName(latestVersion.versionName ?? "");
setDescription(latestVersion.description ?? "");
setEditedVersionName(latestVersion.versionName ?? ""); // Initialize editedVersionName
if (!isEditing) {
startDismissTimer();
}
prevVersionCount.current = versions.length;
} else if (versions.length < prevVersionCount.current) {
prevVersionCount.current = versions.length;
}
}, [versions, isEditing, latestVersion]);
const startDismissTimer = (delay = 5000) => {
if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current);
dismissTimerRef.current = setTimeout(() => {
setShouldDismiss(true);
}, delay);
};
useEffect(() => {
if (shouldDismiss) {
const timer = setTimeout(() => setShowNotification(false), 200);
return () => clearTimeout(timer);
}
}, [shouldDismiss]);
const handleEditName = () => {
if (!latestVersion) return;
setIsEditing(true);
setNewName(latestVersion.versionName ?? "");
setDescription(latestVersion.description ?? "");
if (dismissTimerRef.current) {
clearTimeout(dismissTimerRef.current);
dismissTimerRef.current = null;
}
};
const handleFinishEdit = () => {
if (!latestVersion) return;
const updatedName =
(newName.trim() || latestVersion.versionName) ?? latestVersion.timestamp;
updateVersion(latestVersion.id, {
versionName: updatedName,
description,
});
setEditedVersionName(updatedName);
setIsEditing(false);
setShowEditedFinish(true);
setTimeout(() => {
setShowEditedFinish(false);
}, 5000);
startDismissTimer();
};
const handleCancel = () => {
setIsEditing(false);
startDismissTimer();
};
const handleClose = () => {
setShouldDismiss(true);
if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current);
};
if (!showNotification || !latestVersion) return null;
return (
<div className={`versionSaved ${shouldDismiss ? "dismissing" : ""}`}>
{!isEditing && !showEditedFinish && (
<div className="versionSaved-wrapper">
<div className="version-header">
<div className="header-wrapper">
<div className="icon">
<SaveIcon />
</div>
<span>Saved New Version</span>
</div>
<button className="close-btn" onClick={handleClose}>
<CloseIcon />
</button>
</div>
<div className="version-details">
<SaveVersionIcon />
<div className="details">
<div className="details-wrapper">
New Version Created {latestVersion.versionLabel}{" "}
{latestVersion.timestamp.toUpperCase()}
</div>
<button onClick={handleEditName}>Edit name</button>
</div>
</div>
</div>
)}
{isEditing && (
<RenderOverlay>
<div className="edit-version-popup-wrapper">
<div className="details-wrapper-popup-container">
<div className="header-wrapper">
<RenameVersionIcon />
<div className="label">Rename Version</div>
</div>
<div className="details-wrapper">
<div className="version-name">
<input
type="text"
value={newName}
onChange={(e) => setNewName(e.target.value)}
placeholder="Enter new version name"
/>
<div className="label">
by @{latestVersion.savedBy}{" "}
{new Date(latestVersion.timestamp).toLocaleString("en-US", {
month: "short",
day: "numeric",
year: "2-digit",
hour: "numeric",
minute: "2-digit",
})}
</div>
</div>
<div className="version-description">
<textarea
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="Add description"
style={{ resize: "none" }}
/>
</div>
</div>
<div className="btn-wrapper">
<button className="cancel" onClick={handleCancel}>
Cancel
</button>
<button className="save" onClick={handleFinishEdit}>
Save
</button>
</div>
</div>
</div>
</RenderOverlay>
)}
{showEditedFinish && (
<RenderOverlay>
<div className="finishEdit-version-popup-wrapper">
<div className="finishEdit-wrapper-popup-container">
<div className="icon">
<FinishEditIcon />
</div>
<div className="versionname">
{editedVersionName || latestVersion.versionName}
</div>
<div className="success-message">Saved Successfully!</div>
</div>
</div>
</RenderOverlay>
)}
</div>
);
};
export default VersionSaved;

View File

@@ -0,0 +1,241 @@
import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import useChartStore from "../../../../../store/visualization/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
import { useParams } from "react-router-dom";
import { useSocketStore } from "../../../../../store/builder/store";
type Props = {};
const BarChartInput = (props: Props) => {
const [widgetName, setWidgetName] = useState("Widget");
const { setMeasurements, updateDuration, updateName } = useChartStore();
const [duration, setDuration] = useState("1h");
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<
Record<string, { name: string; fields: string }>
>({});
const { selectedZone } = useSelectedZoneStore();
const { selectedChartId } = useWidgetStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const [isLoading, setLoading] = useState<boolean>(true);
const { projectId } = useParams();
const { visualizationSocket } = useSocketStore();
useEffect(() => {
const fetchZoneData = async () => {
try {
setLoading(true);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);
setLoading(false);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.log("Failed to fetch zone data");
console.error("There was an error!", error);
}
};
fetchZoneData();
}, []);
useEffect(() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`,
{
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
}
);
if (response.status === 200) {
setSelections(response.data.Data.measurements);
setDuration(response.data.Data.duration);
setWidgetName(response.data.widgetName);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch saved inputs");
console.error("There was an error!", error);
}
}
};
fetchSavedInputes();
}, [selectedChartId]);
// Sync Zustand state when component mounts
useEffect(() => {
setMeasurements(selections);
updateDuration(duration);
updateName(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async (
inputMeasurement: any,
inputDuration: any,
inputName: any
) => {
// const userId = localStorage.getItem("userId");
// let newWidget = {
// id: selectedChartId.id,
// panel: selectedChartId.panel,
// widgetName: inputName,
// Data: {
// measurements: inputMeasurement,
// duration: inputDuration,
// }
// }
// const adding3dWidget = {
// organization: organization,
// widget: newWidget,
// zoneUuid: selectedZone.zoneUuid,
// projectId, userId
// };
// if (visualizationSocket) {
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
// }
try {
const response = await axios.post(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
{
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
},
{
organization: organization,
zoneUuid: selectedZone.zoneUuid,
widget: {
id: selectedChartId.id,
panel: selectedChartId.panel,
widgetName: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration,
},
},
} as any
);
if (response.status === 200) {
return true;
} else {
console.log("Unexpected response:", response);
return false;
}
} catch (error) {
echo.error("Failed to send input");
console.error("There was an error!", error);
return false;
}
};
const handleSelect = async (
inputKey: string,
selectedData: { name: string; fields: string } | null
) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
// console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
// sendInputes(newSelections, duration); // Send data to server
// return newSelections;
// };
};
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
// setDuration(option);
};
const handleNameChange = async (name: any) => {
console.log("name change requested", name);
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
};
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput
value={widgetName || selectedChartId?.title}
onRename={handleNameChange}
/>
</div>
{[...Array(3)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
<div key={index} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropdown
data={dropDowndata}
onSelect={(selectedData) =>
handleSelect(inputKey, selectedData)
}
onUnselect={() => handleSelect(inputKey, null)}
selectedValue={selections[inputKey]} // Load from Zustand
isLoading={isLoading}
allSelections={selections}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
<div>
<div className="datas">
<div className="datas__label">Duration</div>
<div className="datas__class">
<RegularDropDown
header={duration}
options={["1h", "2h", "12h"]}
onSelect={handleSelectDuration}
search={false}
/>
</div>
</div>
</div>
</>
);
};
export default BarChartInput;

View File

@@ -0,0 +1,205 @@
import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import useChartStore from "../../../../../store/visualization/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
type Props = {};
const FleetEfficiencyInputComponent = (props: Props) => {
const [widgetName, setWidgetName] = useState("Widget");
const { setFlotingMeasurements, updateFlotingDuration, updateHeader } =
useChartStore();
const [duration, setDuration] = useState("1h");
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<
Record<string, { name: string; fields: string }>
>({});
const { selectedZone } = useSelectedZoneStore();
const { selectedChartId } = useWidgetStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const [isLoading, setLoading] = useState<boolean>(true);
const isSelected = () => {};
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
setLoading(true);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);
setLoading(false);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch zone data");
console.error("There was an error!", error);
}
};
fetchZoneData();
}, []);
useEffect(() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`
);
if (response.status === 200) {
setSelections(response.data.Data.measurements);
setDuration(response.data.Data.duration);
setWidgetName(response.data.header);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch saved inputs");
console.error("There was an error!", error);
}
}
};
fetchSavedInputes();
}, [selectedChartId.id]);
// Sync Zustand state when component mounts
useEffect(() => {
setFlotingMeasurements(selections);
updateFlotingDuration(duration);
updateHeader(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async (
inputMeasurement: any,
inputDuration: any,
inputName: any
) => {
try {
const response = await axios.post(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`,
{
organization: organization,
zoneUuid: selectedZone.zoneUuid,
widget: {
id: selectedChartId.id,
header: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration,
},
},
} as any
);
if (response.status === 200) {
return true;
} else {
console.log("Unexpected response:", response);
return false;
}
} catch (error) {
echo.error("Failed to send input");
console.error("There was an error!", error);
return false;
}
};
const handleSelect = async (
inputKey: string,
selectedData: { name: string; fields: string } | null
) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
// console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
// sendInputes(newSelections, duration); // Send data to server
// return newSelections;
// };
};
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
// setDuration(option);
};
const handleNameChange = async (name: any) => {
console.log("name change requested", name);
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
};
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput
value={widgetName || selectedChartId?.header}
onRename={handleNameChange}
/>
</div>
{[...Array(1)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
<div key={index} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropdown
data={dropDowndata}
onSelect={(selectedData) =>
handleSelect(inputKey, selectedData)
}
onUnselect={() => handleSelect(inputKey, null)}
selectedValue={selections[inputKey]} // Load from Zustand
isLoading={isLoading}
allSelections={selections}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
<div>
{/* <div className="datas">
<div className="datas__label">Duration</div>
<div className="datas__class">
<RegularDropDown
header={duration}
options={["1h", "2h", "12h"]}
onSelect={handleSelectDuration}
search={false}
/>
</div>
</div> */}
</div>
</>
);
};
export default FleetEfficiencyInputComponent;

View File

@@ -0,0 +1,204 @@
import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import useChartStore from "../../../../../store/visualization/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
type Props = {};
const FlotingWidgetInput = (props: Props) => {
const [widgetName, setWidgetName] = useState("Widget");
const { setFlotingMeasurements, updateFlotingDuration, updateHeader } =
useChartStore();
const [duration, setDuration] = useState("1h");
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<
Record<string, { name: string; fields: string }>
>({});
const { selectedZone } = useSelectedZoneStore();
const { selectedChartId } = useWidgetStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const [isLoading, setLoading] = useState<boolean>(true);
useEffect(() => {
const fetchZoneData = async () => {
try {
setLoading(true);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);
setLoading(false);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch zone data");
console.error("There was an error!", error);
}
};
fetchZoneData();
}, []);
useEffect(() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`
);
if (response.status === 200) {
setSelections(response.data.Data.measurements);
setDuration(response.data.Data.duration);
setWidgetName(response.data.header);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch saved inputs");
console.error("There was an error!", error);
}
}
};
fetchSavedInputes();
}, [selectedChartId.id]);
// Sync Zustand state when component mounts
useEffect(() => {
setFlotingMeasurements(selections);
updateFlotingDuration(duration);
updateHeader(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async (
inputMeasurement: any,
inputDuration: any,
inputName: any
) => {
try {
const response = await axios.post(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`,
{
organization: organization,
zoneUuid: selectedZone.zoneUuid,
widget: {
id: selectedChartId.id,
header: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration,
},
},
} as any
);
if (response.status === 200) {
return true;
} else {
console.log("Unexpected response:", response);
return false;
}
} catch (error) {
echo.error("Failed to send input");
console.error("There was an error!", error);
return false;
}
};
const handleSelect = async (
inputKey: string,
selectedData: { name: string; fields: string } | null
) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
// console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
// sendInputes(newSelections, duration); // Send data to server
// return newSelections;
// };
};
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
// setDuration(option);
};
const handleNameChange = async (name: any) => {
console.log("name change requested", name);
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
};
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput
value={widgetName || selectedChartId?.header}
onRename={handleNameChange}
/>
</div>
{[...Array(6)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
<div key={index} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropdown
data={dropDowndata}
onSelect={(selectedData) =>
handleSelect(inputKey, selectedData)
}
onUnselect={() => handleSelect(inputKey, null)}
selectedValue={selections[inputKey]} // Load from Zustand
isLoading={isLoading}
allSelections={selections}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
<div>
<div className="datas">
<div className="datas__label">Duration</div>
<div className="datas__class">
<RegularDropDown
header={duration}
options={["1h", "2h", "12h"]}
onSelect={handleSelectDuration}
search={false}
/>
</div>
</div>
</div>
</>
);
};
export default FlotingWidgetInput;

View File

@@ -0,0 +1,209 @@
import React from 'react'
import LineGrapInput from './LineGrapInput'
import BarChartInput from './BarChartInput'
import PieChartInput from './PieChartInput'
import FlotingWidgetInput from './FlotingWidgetInput'
import FleetEfficiencyInputComponent from './FleetEfficiencyInputComponent'
import Progress1Input from './Progress1Input'
import Progress2Input from './Progress2Input'
import Widget2InputCard3D from './Widget2InputCard3D'
import Widget3InputCard3D from './Widget3InputCard3D'
import Widget4InputCard3D from './Widget4InputCard3D'
import WarehouseThroughputInputComponent from './WarehouseThroughputInputComponent'
import { useWidgetStore } from '../../../../../store/useWidgetStore'
// const InputSelecterComponent = () => {
// const { selectedChartId } = useWidgetStore();
// if (selectedChartId && selectedChartId.type && selectedChartId.type === 'bar' ) {
// return (
// <>
// <div className="sideBarHeader">2D Widget Input</div>
// <BarChartInput />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'line' ) {
// return (
// <>
// <div className="sideBarHeader">2D Widget Input</div>
// <LineGrapInput />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'pie' ) {
// return (
// <>
// <div className="sideBarHeader">2D Widget Input</div>
// <PieChartInput />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'doughnut' ) {
// return (
// <>
// <div className="sideBarHeader">2D Widget Input</div>
// <PieChartInput />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'polarArea' ) {
// return (
// <>
// <div className="sideBarHeader">2D Widget Input</div>
// <PieChartInput />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'progress 1' ) {
// return (
// <>
// <div className="sideBarHeader">2D Widget Input</div>
// <Progress1Input />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'progress 2' ) {
// return (
// <>
// <div className="sideBarHeader">2D Widget Input</div>
// <Progress2Input />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'warehouseThroughput floating' ) {
// return (
// <>
// <div className="sideBarHeader">Floting Widget Input</div>
// <WarehouseThroughputInputComponent />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'fleetEfficiency floating' ) {
// return (
// <>
// <div className="sideBarHeader">Floting Widget Input</div>
// <FleetEfficiencyInputComponent />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'floating total-card' ) {
// return (
// <>
// <div className="sideBarHeader">Floting Widget Input</div>
// <FleetEfficiencyInputComponent />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'ui-Widget 1' ) {
// return (
// <>
// <div className="sideBarHeader">3D Widget Input</div>
// <Widget4InputCard3D />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'ui-Widget 2' ) {
// return (
// <>
// <div className="sideBarHeader">3D Widget Input</div>
// <Widget2InputCard3D />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'ui-Widget 3' ) {
// return (
// <>
// <div className="sideBarHeader">3D Widget Input</div>
// <Widget3InputCard3D />
// </>
// )
// }
// else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'ui-Widget 4' ) {
// return (
// <>
// <div className="sideBarHeader">3D Widget Input</div>
// <Widget4InputCard3D />
// </>
// )
// }
// else {
// return (
// <div>No chart selected</div>
// )
// }
// }
const chartTypeMap: Record<| 'bar'| 'line'| 'pie' | 'doughnut' | 'polarArea'| 'progress 1' | 'progress 2'
| 'ui-Widget 1'| 'ui-Widget 2'| 'ui-Widget 3'| 'ui-Widget 4',JSX.Element> = {
bar: <BarChartInput />,
line: <LineGrapInput />,
pie: <PieChartInput />,
doughnut: <PieChartInput />,
polarArea: <PieChartInput />,
'progress 1': <Progress1Input />,
'progress 2': <Progress2Input />,
'ui-Widget 1': <Widget4InputCard3D />,
'ui-Widget 2': <Widget2InputCard3D />,
'ui-Widget 3': <Widget3InputCard3D />,
'ui-Widget 4': <Widget4InputCard3D />,
};
const classNameMap: Record<
| 'warehouseThroughput floating'
| 'fleetEfficiency floating'
| 'floating total-card',
JSX.Element
> = {
'warehouseThroughput floating': <WarehouseThroughputInputComponent />,
'fleetEfficiency floating': <FleetEfficiencyInputComponent />,
'floating total-card': <FleetEfficiencyInputComponent />,
};
const InputSelecterComponent = () => {
const { selectedChartId } = useWidgetStore();
if (selectedChartId) {
const { type, className } = selectedChartId;
if (type && chartTypeMap[type as keyof typeof chartTypeMap]) {
const label = ['ui-Widget 1', 'ui-Widget 2', 'ui-Widget 3', 'ui-Widget 4'].includes(type)
? '3D Widget Input'
: '2D Widget Input';
return (
<>
<div className="sideBarHeader">{label}</div>
{chartTypeMap[type as keyof typeof chartTypeMap]}
</>
);
}
if (className && classNameMap[className as keyof typeof classNameMap]) {
return (
<>
<div className="sideBarHeader">Floting Widget Input</div>
{classNameMap[className as keyof typeof classNameMap]}
</>
);
}
}
return <div>No chart selected</div>;
};
export default InputSelecterComponent;

View File

@@ -0,0 +1,356 @@
// import React, { useEffect, useState } from 'react'
// import MultiLevelDropdown from '../../../../ui/inputs/MultiLevelDropDown'
// import { AddIcon } from '../../../../icons/ExportCommonIcons'
// import RegularDropDown from '../../../../ui/inputs/RegularDropDown'
// import useChartStore from '../../../../../store/useChartStore'
// import axios from 'axios'
// type Props = {}
// const LineGrapInput = (props: Props) => {
// const [dropDowndata, setDropDownData] = useState({})
// const [selections, setSelections] = useState<Record<string, { name: string, fields: string }>>({})
// const [selectedOption, setSelectedOption] = useState('1h')
// const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
// const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
// const handleSelectDuration = (option: string) => {
// updateDuration(option); // Normalize for key matching
// };
// useEffect(() => {
// const fetchZoneData = async () => {
// try {
// const response = await axios.get(`http://${iotApiUrl}/getinput`);
// if (response.status === 200) {
// console.log('dropdown data:', response.data);
// setDropDownData(response.data)
// } else {
// console.log('Unexpected response:', response);
// }
// } catch (error) {
// console.error('There was an error!', error);
// }
// };
// fetchZoneData();
// }, []);
// useEffect(() => {
// console.log(selections);
// }, [selections])
// const handleSelect = (inputKey: string, selectedData: { name: string, fields: string } | null) => {
// setSelections(prev => {
// if (selectedData === null) {
// const newSelections = { ...prev };
// delete newSelections[inputKey];
// return newSelections;
// } else {
// return {
// ...prev,
// [inputKey]: selectedData
// };
// }
// });
// };
// interface Measurement {
// name: string;
// fields: string;
// }
// interface InputData {
// [key: string]: Measurement;
// }
// const extractMeasurements = (input: InputData): Measurement[] => {
// return Object.values(input);
// };
// useEffect(() => {
// const measurementsData = extractMeasurements(selections);
// setMeasurements(measurementsData);
// }, [selections]);
// return (
// <>
// <div className="inputs-wrapper">
// {[...Array(6)].map((_, index) => {
// const inputKey = `input${index + 1}`;
// return (
// <div key={index} className="datas">
// <div className="datas__label">Input {index + 1}</div>
// <div className="datas__class">
// <MultiLevelDropdown
// data={dropDowndata}
// onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
// onUnselect={() => handleSelect(inputKey, null)}
// selectedValue={selections[inputKey]}
// />
// <div className="icon">
// <AddIcon />
// </div>
// </div>
// </div>
// );
// })}
// </div>
// <div>
// <div className="datas">
// <div className="datas__label">duration</div>
// <div className="datas__class">
// <RegularDropDown
// header={duration}
// options={["1h", "2h", "12h"]}
// onSelect={handleSelectDuration}
// search={false}
// />
// </div>
// </div>
// </div>
// </>
// )
// }
// export default LineGrapInput
import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import useChartStore from "../../../../../store/visualization/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
import { useParams } from "react-router-dom";
import { useSocketStore } from "../../../../../store/builder/store";
type Props = {};
const LineGrapInput = (props: Props) => {
const [widgetName, setWidgetName] = useState("Widget");
const { setMeasurements, updateDuration, updateName } = useChartStore();
const [duration, setDuration] = useState("1h");
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<
Record<string, { name: string; fields: string }>
>({});
const { selectedZone } = useSelectedZoneStore();
const { selectedChartId } = useWidgetStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const [isLoading, setLoading] = useState<boolean>(true);
const { projectId } = useParams();
const { visualizationSocket } = useSocketStore();
useEffect(() => {
const fetchZoneData = async () => {
try {
setLoading(true);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);
setLoading(false);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch zone data");
console.error("There was an error!", error);
}
};
fetchZoneData();
}, []);
useEffect(() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`,
{
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
}
);
if (response.status === 200) {
setSelections(response.data.Data.measurements);
setDuration(response.data.Data.duration);
setWidgetName(response.data.widgetName);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch saved inputs");
console.error("There was an error!", error);
}
}
};
fetchSavedInputes();
}, [selectedChartId.id]);
// Sync Zustand state when component mounts
useEffect(() => {
setMeasurements(selections);
updateDuration(duration);
updateName(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async (
inputMeasurement: any,
inputDuration: any,
inputName: any
) => {
// const userId = localStorage.getItem("userId");
// let newWidget = {
// id: selectedChartId.id,
// panel: selectedChartId.panel,
// widgetName: inputName,
// Data: {
// measurements: inputMeasurement,
// duration: inputDuration,
// }
// }
// const adding3dWidget = {
// organization: organization,
// widget: newWidget,
// zoneUuid: selectedZone.zoneUuid,
// projectId, userId
// };
// if (visualizationSocket) {
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
// }
try {
const response = await axios.post(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
{
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
},
{
organization: organization,
zoneUuid: selectedZone.zoneUuid,
widget: {
id: selectedChartId.id,
panel: selectedChartId.panel,
widgetName: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration,
},
},
} as any
);
if (response.status === 200) {
return true;
} else {
console.log("Unexpected response:", response);
return false;
}
} catch (error) {
echo.error("Failed to send input");
console.error("There was an error!", error);
return false;
}
};
const handleSelect = async (
inputKey: string,
selectedData: { name: string; fields: string } | null
) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
// console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
// sendInputes(newSelections, duration); // Send data to server
// return newSelections;
// };
};
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
// setDuration(option);
};
const handleNameChange = async (name: any) => {
console.log("name change requested", name);
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
};
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput
value={widgetName || selectedChartId?.title}
onRename={handleNameChange}
/>
</div>
{[...Array(4)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
<div key={index} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropdown
data={dropDowndata}
onSelect={(selectedData) =>
handleSelect(inputKey, selectedData)
}
onUnselect={() => handleSelect(inputKey, null)}
selectedValue={selections[inputKey]} // Load from Zustand
isLoading={isLoading}
allSelections={selections}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
<div>
<div className="datas">
<div className="datas__label">Duration</div>
<div className="datas__class">
<RegularDropDown
header={duration}
options={["1h", "2h", "12h"]}
onSelect={handleSelectDuration}
search={false}
/>
</div>
</div>
</div>
</>
);
};
export default LineGrapInput;

View File

@@ -0,0 +1,242 @@
import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import useChartStore from "../../../../../store/visualization/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
import { useParams } from "react-router-dom";
import { useSocketStore } from "../../../../../store/builder/store";
type Props = {};
const PieChartInput = (props: Props) => {
const [widgetName, setWidgetName] = useState("Widget");
const { setMeasurements, updateDuration, updateName } = useChartStore();
const [duration, setDuration] = useState("1h");
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<
Record<string, { name: string; fields: string }>
>({});
const { selectedZone } = useSelectedZoneStore();
const { selectedChartId } = useWidgetStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const [isLoading, setLoading] = useState<boolean>(true);
const { projectId } = useParams();
const { visualizationSocket } = useSocketStore();
useEffect(() => {
const fetchZoneData = async () => {
try {
setLoading(true);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);
setLoading(false);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch zone data");
console.error("There was an error!", error);
}
};
fetchZoneData();
}, []);
useEffect(() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`,
{
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
}
);
if (response.status === 200) {
setSelections(response.data.Data.measurements);
setDuration(response.data.Data.duration);
setWidgetName(response.data.widgetName);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch saved inputs");
console.error("There was an error!", error);
}
}
};
fetchSavedInputes();
}, [selectedChartId.id]);
// Sync Zustand state when component mounts
useEffect(() => {
setMeasurements(selections);
updateDuration(duration);
updateName(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async (
inputMeasurement: any,
inputDuration: any,
inputName: any
) => {
// const userId = localStorage.getItem("userId");
// let newWidget = {
// id: selectedChartId.id,
// panel: selectedChartId.panel,
// widgetName: inputName,
// Data: {
// measurements: inputMeasurement,
// duration: inputDuration,
// },
// }
// const adding3dWidget = {
// organization: organization,
// widget: newWidget,
// zoneUuid: selectedZone.zoneUuid,
// projectId, userId
// };
// if (visualizationSocket) {
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
// }
try {
const response = await axios.post(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
{
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
},
{
organization: organization,
zoneUuid: selectedZone.zoneUuid,
widget: {
id: selectedChartId.id,
panel: selectedChartId.panel,
widgetName: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration,
},
},
} as any
);
if (response.status === 200) {
return true;
} else {
console.log("Unexpected response:", response);
return false;
}
} catch (error) {
echo.error("Failed to send input");
console.error("There was an error!", error);
return false;
}
};
const handleSelect = async (
inputKey: string,
selectedData: { name: string; fields: string } | null
) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
// console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
// sendInputes(newSelections, duration); // Send data to server
// return newSelections;
// };
};
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
// setDuration(option);
};
const handleNameChange = async (name: any) => {
console.log("name change requested", name);
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
};
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput
value={widgetName || selectedChartId?.title}
onRename={handleNameChange}
/>
</div>
{[...Array(2)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
<div key={index} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropdown
data={dropDowndata}
onSelect={(selectedData) =>
handleSelect(inputKey, selectedData)
}
onUnselect={() => handleSelect(inputKey, null)}
selectedValue={selections[inputKey]} // Load from Zustand
isLoading={isLoading}
allSelections={selections}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
<div>
<div className="datas">
<div className="datas__label">Duration</div>
<div className="datas__class">
<RegularDropDown
header={duration}
options={["1h", "2h", "12h"]}
onSelect={handleSelectDuration}
search={false}
/>
</div>
</div>
</div>
</>
);
};
export default PieChartInput;

View File

@@ -0,0 +1,235 @@
import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import useChartStore from "../../../../../store/visualization/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
import { useParams } from "react-router-dom";
import { useSocketStore } from "../../../../../store/builder/store";
type Props = {};
const Progress1Input = (props: Props) => {
const [widgetName, setWidgetName] = useState("Widget");
const { setMeasurements, updateDuration, updateName } = useChartStore();
const [duration, setDuration] = useState("1h");
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<
Record<string, { name: string; fields: string }>
>({});
const { selectedZone } = useSelectedZoneStore();
const { selectedChartId } = useWidgetStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const [isLoading, setLoading] = useState<boolean>(true);
const { projectId } = useParams();
const { visualizationSocket } = useSocketStore();
useEffect(() => {
const fetchZoneData = async () => {
try {
setLoading(true);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);
setLoading(false);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch zone data");
console.error("There was an error!", error);
}
};
fetchZoneData();
}, []);
useEffect(() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`,
{
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
}
);
if (response.status === 200) {
setSelections(response.data.Data.measurements);
setDuration(response.data.Data.duration);
setWidgetName(response.data.widgetName);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch saved inputs");
console.error("There was an error!", error);
}
}
};
fetchSavedInputes();
}, [selectedChartId.id]);
// Sync Zustand state when component mounts
useEffect(() => {
setMeasurements(selections);
updateDuration(duration);
updateName(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async (
inputMeasurement: any,
inputDuration: any,
inputName: any
) => {
// const userId = localStorage.getItem("userId");
// let newWidget = {
// id: selectedChartId.id,
// panel: selectedChartId.panel,
// widgetName: inputName,
// Data: {
// measurements: inputMeasurement,
// duration: inputDuration,
// },
// }
// const adding3dWidget = {
// organization: organization,
// widget: newWidget,
// zoneUuid: selectedZone.zoneUuid,
// projectId, userId
// };
// if (visualizationSocket) {
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
// }
try {
const response = await axios.post(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
{
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
},
{
organization: organization,
zoneUuid: selectedZone.zoneUuid,
widget: {
id: selectedChartId.id,
panel: selectedChartId.panel,
widgetName: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration,
},
},
} as any
);
if (response.status === 200) {
return true;
} else {
console.log("Unexpected response:", response);
return false;
}
} catch (error) {
echo.error("Failed to send input");
console.error("There was an error!", error);
return false;
}
};
const handleSelect = async (
inputKey: string,
selectedData: { name: string; fields: string } | null
) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
// console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
};
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
};
const handleNameChange = async (name: any) => {
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
};
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput
value={widgetName || selectedChartId?.title}
onRename={handleNameChange}
/>
</div>
{[...Array(1)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
<div key={index} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropdown
data={dropDowndata}
onSelect={(selectedData) =>
handleSelect(inputKey, selectedData)
}
onUnselect={() => handleSelect(inputKey, null)}
selectedValue={selections[inputKey]} // Load from Zustand
isLoading={isLoading}
allSelections={selections}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
{/* <div>
<div className="datas">
<div className="datas__label">Duration</div>
<div className="datas__class">
<RegularDropDown
header={duration}
options={["1h", "2h", "12h"]}
onSelect={handleSelectDuration}
search={false}
/>
</div>
</div>
</div> */}
</>
);
};
export default Progress1Input;

View File

@@ -0,0 +1,235 @@
import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import useChartStore from "../../../../../store/visualization/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
import { useParams } from "react-router-dom";
import { useSocketStore } from "../../../../../store/builder/store";
type Props = {};
const Progress2Input = (props: Props) => {
const [widgetName, setWidgetName] = useState("Widget");
const { setMeasurements, updateDuration, updateName } = useChartStore();
const [duration, setDuration] = useState("1h");
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<
Record<string, { name: string; fields: string }>
>({});
const { selectedZone } = useSelectedZoneStore();
const { selectedChartId } = useWidgetStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const [isLoading, setLoading] = useState<boolean>(true);
const { projectId } = useParams();
const { visualizationSocket } = useSocketStore();
useEffect(() => {
const fetchZoneData = async () => {
try {
setLoading(true);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);
setLoading(false);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch zone data");
console.error("There was an error!", error);
}
};
fetchZoneData();
}, []);
useEffect(() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`,
{
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
}
);
if (response.status === 200) {
setSelections(response.data.Data.measurements);
setDuration(response.data.Data.duration);
setWidgetName(response.data.widgetName);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch saved inputs");
console.error("There was an error!", error);
}
}
};
fetchSavedInputes();
}, [selectedChartId.id]);
// Sync Zustand state when component mounts
useEffect(() => {
setMeasurements(selections);
updateDuration(duration);
updateName(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async (
inputMeasurement: any,
inputDuration: any,
inputName: any
) => {
// const userId = localStorage.getItem("userId");
// let newWidget = {
// id: selectedChartId.id,
// panel: selectedChartId.panel,
// widgetName: inputName,
// Data: {
// measurements: inputMeasurement,
// duration: inputDuration,
// }
// }
// const adding3dWidget = {
// organization: organization,
// widget: newWidget,
// zoneUuid: selectedZone.zoneUuid,
// projectId, userId
// };
// if (visualizationSocket) {
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
// }
try {
const response = await axios.post(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
{
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
},
{
organization: organization,
zoneUuid: selectedZone.zoneUuid,
widget: {
id: selectedChartId.id,
panel: selectedChartId.panel,
widgetName: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration,
},
},
} as any
);
if (response.status === 200) {
return true;
} else {
console.log("Unexpected response:", response);
return false;
}
} catch (error) {
echo.error("Failed to send input");
console.error("There was an error!", error);
return false;
}
};
const handleSelect = async (
inputKey: string,
selectedData: { name: string; fields: string } | null
) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
// console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
};
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
};
const handleNameChange = async (name: any) => {
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
};
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput
value={widgetName || selectedChartId?.title}
onRename={handleNameChange}
/>
</div>
{[...Array(2)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
<div key={index} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropdown
data={dropDowndata}
onSelect={(selectedData) =>
handleSelect(inputKey, selectedData)
}
onUnselect={() => handleSelect(inputKey, null)}
selectedValue={selections[inputKey]} // Load from Zustand
isLoading={isLoading}
allSelections={selections}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
{/* <div>
<div className="datas">
<div className="datas__label">Duration</div>
<div className="datas__class">
<RegularDropDown
header={duration}
options={["1h", "2h", "12h"]}
onSelect={handleSelectDuration}
search={false}
/>
</div>
</div>
</div> */}
</>
);
};
export default Progress2Input;

View File

@@ -0,0 +1,201 @@
import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import useChartStore from "../../../../../store/visualization/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
type Props = {};
const WarehouseThroughputInputComponent = (props: Props) => {
const [widgetName, setWidgetName] = useState("Widget");
const { setFlotingMeasurements, updateFlotingDuration, updateHeader } =
useChartStore();
const [duration, setDuration] = useState("1h");
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<
Record<string, { name: string; fields: string }>
>({});
const { selectedZone } = useSelectedZoneStore();
const { selectedChartId } = useWidgetStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const [isLoading, setLoading] = useState<boolean>(true);
useEffect(() => {
const fetchZoneData = async () => {
try {
setLoading(true);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);
setLoading(false);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch zone data");
console.error("There was an error!", error);
}
};
fetchZoneData();
}, []);
useEffect(() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`
);
if (response.status === 200) {
setSelections(response.data.Data.measurements);
setDuration(response.data.Data.duration);
setWidgetName(response.data.header);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch saved inputs");
console.error("There was an error!", error);
}
}
};
fetchSavedInputes();
}, [selectedChartId.id]);
// Sync Zustand state when component mounts
useEffect(() => {
setFlotingMeasurements(selections);
updateFlotingDuration(duration);
updateHeader(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async (
inputMeasurement: any,
inputDuration: any,
inputName: any
) => {
try {
const response = await axios.post(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`,
{
organization: organization,
zoneUuid: selectedZone.zoneUuid,
widget: {
id: selectedChartId.id,
header: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration,
},
},
} as any
);
if (response.status === 200) {
return true;
} else {
console.log("Unexpected response:", response);
return false;
}
} catch (error) {
echo.error("Failed to send input");
console.error("There was an error!", error);
return false;
}
};
const handleSelect = async (
inputKey: string,
selectedData: { name: string; fields: string } | null
) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
// console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
// sendInputes(newSelections, duration); // Send data to server
// return newSelections;
// };
};
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
// setDuration(option);
};
const handleNameChange = async (name: any) => {
console.log("name change requested", name);
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
};
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput
value={widgetName || selectedChartId?.header}
onRename={handleNameChange}
/>
</div>
{[...Array(1)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
<div key={index} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropdown
data={dropDowndata}
onSelect={(selectedData) =>
handleSelect(inputKey, selectedData)
}
onUnselect={() => handleSelect(inputKey, null)}
selectedValue={selections[inputKey]} // Load from Zustand
isLoading={isLoading}
allSelections={selections}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
<div>
<div className="datas">
<div className="datas__label">Duration</div>
<div className="datas__class">
<RegularDropDown
header={duration}
options={["1h", "2h", "12h"]}
onSelect={handleSelectDuration}
search={false}
/>
</div>
</div>
</div>
</>
);
};
export default WarehouseThroughputInputComponent;

View File

@@ -0,0 +1,184 @@
import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import useChartStore from "../../../../../store/visualization/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
type Props = {};
const Widget2InputCard3D = (props: Props) => {
const { selectedChartId } = useWidgetStore();
const [widgetName, setWidgetName] = useState("untited");
const { setMeasurements, updateDuration, updateName } = useChartStore();
const [duration, setDuration] = useState("1h");
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<
Record<string, { name: string; fields: string }>
>({});
const { selectedZone } = useSelectedZoneStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const [isLoading, setLoading] = useState<boolean>(true);
useEffect(() => {
const fetchZoneData = async () => {
try {
setLoading(true);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);
setLoading(false);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch zone data");
console.error("There was an error!", error);
}
};
fetchZoneData();
}, []);
useEffect(() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${selectedChartId.id}/${organization}`
);
if (response.status === 200) {
setSelections(response.data.Data.measurements);
setDuration(response.data.Data.duration);
setWidgetName(response.data.widgetName);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch saved inputs");
console.error("There was an error!", error);
}
}
};
fetchSavedInputes();
}, [selectedChartId.id]);
// Sync Zustand state when component mounts
useEffect(() => {
setMeasurements(selections);
updateDuration(duration);
updateName(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async (
inputMeasurement: any,
inputDuration: any,
inputName: any
) => {
try {
const response = await axios.post(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
{
organization: organization,
zoneUuid: selectedZone.zoneUuid,
widget: {
id: selectedChartId.id,
widgetName: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration,
},
},
} as any
);
if (response.status === 200) {
return true;
} else {
console.log("Unexpected response:", response);
return false;
}
} catch (error) {
echo.error("Failed to send input");
console.error("There was an error!", error);
return false;
}
};
const handleSelect = async (
inputKey: string,
selectedData: { name: string; fields: string } | null
) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
// console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
// sendInputes(newSelections, duration); // Send data to server
// return newSelections;
// };
};
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
// setDuration(option);
};
const handleNameChange = async (name: any) => {
console.log("name change requested", name);
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
};
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput value={widgetName} onRename={handleNameChange} />
</div>
{[...Array(2)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
<div key={index} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropdown
data={dropDowndata}
onSelect={(selectedData) =>
handleSelect(inputKey, selectedData)
}
onUnselect={() => handleSelect(inputKey, null)}
selectedValue={selections[inputKey]} // Load from Zustand
isLoading={isLoading}
allSelections={selections}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
</>
);
};
export default Widget2InputCard3D;

View File

@@ -0,0 +1,177 @@
import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import useChartStore from "../../../../../store/visualization/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
const Widget3InputCard3D = () => {
const { selectedChartId } = useWidgetStore();
const [widgetName, setWidgetName] = useState("untited");
const { setMeasurements, updateDuration, updateName } = useChartStore();
const [duration, setDuration] = useState("1h");
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<
Record<string, { name: string; fields: string }>
>({});
const { selectedZone } = useSelectedZoneStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const [isLoading, setLoading] = useState<boolean>(true);
useEffect(() => {
const fetchZoneData = async () => {
try {
setLoading(true);
const response = await axios.get(`http://${iotApiUrl}/getinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);
setLoading(false);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch zone data");
console.error("There was an error!", error);
}
};
fetchZoneData();
}, []);
useEffect(() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${selectedChartId.id}/${organization}`
);
if (response.status === 200) {
setSelections(response.data.Data.measurements);
setDuration(response.data.Data.duration);
setWidgetName(response.data.widgetName);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch saved inputs");
console.error("There was an error!", error);
}
}
};
fetchSavedInputes();
}, [selectedChartId.id]);
useEffect(() => {
setMeasurements(selections);
updateDuration(duration);
updateName(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async (
inputMeasurement: any,
inputDuration: any,
inputName: any
) => {
try {
const response = await axios.post(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
{
organization: organization,
zoneUuid: selectedZone.zoneUuid,
widget: {
id: selectedChartId.id,
widgetName: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration,
},
},
} as any
);
if (response.status === 200) {
return true;
} else {
console.log("Unexpected response:", response);
return false;
}
} catch (error) {
echo.error("Failed to send input");
console.error("There was an error!", error);
return false;
}
};
const handleSelect = async (
inputKey: string,
selectedData: { name: string; fields: string } | null
) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
// console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
};
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
};
const handleNameChange = async (name: any) => {
console.log("name change requested", name);
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
};
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput value={widgetName} onRename={handleNameChange} />
</div>
{[...Array(7)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
<div key={index} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropdown
data={dropDowndata}
onSelect={(selectedData) =>
handleSelect(inputKey, selectedData)
}
onUnselect={() => handleSelect(inputKey, null)}
selectedValue={selections[inputKey]} // Load from Zustand
isLoading={isLoading}
allSelections={selections}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
</>
);
};
export default Widget3InputCard3D;

View File

@@ -0,0 +1,197 @@
import React, { useEffect, useState } from "react";
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
import { AddIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import useChartStore from "../../../../../store/visualization/useChartStore";
import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import axios from "axios";
import RenameInput from "../../../../ui/inputs/RenameInput";
type Props = {};
const Widget4InputCard3D = (props: Props) => {
const { selectedChartId } = useWidgetStore();
const [widgetName, setWidgetName] = useState("untited");
const { setMeasurements, updateDuration, updateName } = useChartStore();
const [duration, setDuration] = useState("1h");
const [dropDowndata, setDropDownData] = useState({});
const [selections, setSelections] = useState<
Record<string, { name: string; fields: string }>
>({});
const { selectedZone } = useSelectedZoneStore();
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const [isLoading, setLoading] = useState<boolean>(true);
useEffect(() => {
const fetchZoneData = async () => {
try {
setLoading(true);
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
if (response.status === 200) {
// console.log("dropdown data:", response.data);
setDropDownData(response.data);
setLoading(false);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch zone data");
console.error("There was an error!", error);
}
};
fetchZoneData();
}, []);
useEffect(() => {
const fetchSavedInputes = async () => {
if (selectedChartId.id !== "") {
try {
const response = await axios.get(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${selectedChartId.id}/${organization}`
);
if (response.status === 200) {
setSelections(response.data.Data.measurements);
setDuration(response.data.Data.duration);
setWidgetName(response.data.widgetName);
} else {
console.log("Unexpected response:", response);
}
} catch (error) {
echo.error("Failed to fetch saved inputs");
console.error("There was an error!", error);
}
}
};
fetchSavedInputes();
}, [selectedChartId.id]);
// Sync Zustand state when component mounts
useEffect(() => {
setMeasurements(selections);
updateDuration(duration);
updateName(widgetName);
}, [selections, duration, widgetName]);
const sendInputes = async (
inputMeasurement: any,
inputDuration: any,
inputName: any
) => {
try {
const response = await axios.post(
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
{
organization: organization,
zoneUuid: selectedZone.zoneUuid,
widget: {
id: selectedChartId.id,
widgetName: inputName,
Data: {
measurements: inputMeasurement,
duration: inputDuration,
},
},
} as any
);
if (response.status === 200) {
return true;
} else {
console.log("Unexpected response:", response);
return false;
}
} catch (error) {
echo.error("Failed to send input");
console.error("There was an error!", error);
return false;
}
};
const handleSelect = async (
inputKey: string,
selectedData: { name: string; fields: string } | null
) => {
// async() => {
const newSelections = { ...selections };
if (selectedData === null) {
delete newSelections[inputKey];
} else {
newSelections[inputKey] = selectedData;
}
// setMeasurements(newSelections); // Update Zustand store
// console.log(newSelections);
if (await sendInputes(newSelections, duration, widgetName)) {
setSelections(newSelections);
}
// sendInputes(newSelections, duration); // Send data to server
// return newSelections;
// };
};
const handleSelectDuration = async (option: string) => {
if (await sendInputes(selections, option, widgetName)) {
setDuration(option);
}
// setDuration(option);
};
const handleNameChange = async (name: any) => {
console.log("name change requested", name);
if (await sendInputes(selections, duration, name)) {
setWidgetName(name);
}
};
return (
<>
<div className="inputs-wrapper">
<div className="datas">
<div className="datas__label">Title</div>
<RenameInput value={widgetName} onRename={handleNameChange} />
</div>
{[...Array(1)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
<div key={index} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropdown
data={dropDowndata}
onSelect={(selectedData) =>
handleSelect(inputKey, selectedData)
}
onUnselect={() => handleSelect(inputKey, null)}
selectedValue={selections[inputKey]} // Load from Zustand
isLoading={isLoading}
allSelections={selections}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
<div>
<div className="datas">
<div className="datas__label">Duration</div>
<div className="datas__class">
<RegularDropDown
header={duration}
options={["1h", "2h", "12h"]}
onSelect={handleSelectDuration}
search={false}
/>
</div>
</div>
</div>
</>
);
};
export default Widget4InputCard3D;

View File

@@ -0,0 +1,27 @@
import { useState } from "react";
import ToggleHeader from "../../../ui/inputs/ToggleHeader";
import Data from "./data/Data";
import Design from "./design/Design";
const Visualization = () => {
const [activeOption, setActiveOption] = useState("Data");
const handleToggleClick = (option: string) => {
setActiveOption(option); // Update the active option
};
return (
<div className="visualization-right-sideBar">
<ToggleHeader
options={["Data","Design"]}
activeOption={activeOption}
handleClick={handleToggleClick}
/>
<div className="sidebar-right-content-container">
{activeOption === "Data" ? <Data /> : <Design />}
</div>
</div>
);
};
export default Visualization;

View File

@@ -0,0 +1,192 @@
import { useEffect, useState } from "react";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons";
import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown";
import LineGrapInput from "../IotInputCards/LineGrapInput";
import RenameInput from "../../../../ui/inputs/RenameInput";
import InputSelecterComponent from "../IotInputCards/InputSelecterComponent";
// Define the data structure for demonstration purposes
const DATA_STRUCTURE = {
furnace: {
coolingRate: "coolingRate",
furnaceTemperature: "furnaceTemperature",
heatingRate: "heatingRate",
machineId: "machineId",
powerConsumption: "powerConsumption",
status: "status",
timestamp: "timestamp",
vacuumLevel: "vacuumLevel",
},
testDevice: {
abrasiveLevel: {
data1: "Data 1",
data2: "Data 2",
data3: "Data 3",
},
airPressure: "airPressure",
machineId: "machineId",
powerConsumption: "powerConsumption",
status: "status",
temperature: {
data1: "Data 1",
data2: "Data 2",
data3: "Data 3",
},
timestamp: {
data1: {
Data01: "Data 01",
Data02: "Data 02",
Data03: "Data 03",
},
data2: "Data 2",
data3: "Data 3",
},
},
};
interface Child {
id: number;
easing: string;
}
interface Group {
id: number;
easing: string;
children: Child[];
}
const Data = () => {
const { selectedChartId } = useWidgetStore();
// State to store groups for all widgets (using Widget.id as keys)
const [chartDataGroups, setChartDataGroups] = useState<
Record<string, Group[]>
>({});
useEffect(() => {
// Initialize data groups for the newly selected widget if it doesn't exist
if (selectedChartId && !chartDataGroups[selectedChartId.id]) {
setChartDataGroups((prev) => ({
...prev,
[selectedChartId.id]: [
{
id: Date.now(),
easing: "Connecter 1",
children: [{ id: Date.now(), easing: "Linear" }],
},
],
}));
}
}, [selectedChartId]);
// Handle adding a new child to the group
const handleAddClick = (groupId: number) => {
setChartDataGroups((prevGroups) => {
const currentGroups = prevGroups[selectedChartId.id] || [];
const group = currentGroups.find((g) => g.id === groupId);
if (group && group.children.length < 7) {
const newChild = { id: Date.now(), easing: "Linear" };
return {
...prevGroups,
[selectedChartId.id]: currentGroups.map((g) =>
g.id === groupId ? { ...g, children: [...g.children, newChild] } : g
),
};
}
return prevGroups;
});
};
// Remove a child from a group
const removeChild = (groupId: number, childId: number) => {
setChartDataGroups((currentGroups) => {
const currentChartData = currentGroups[selectedChartId.id] || [];
return {
...currentGroups,
[selectedChartId.id]: currentChartData.map((group) =>
group.id === groupId
? {
...group,
children: group.children.filter(
(child) => child.id !== childId
),
}
: group
),
};
});
};
return (
<div className="dataSideBar">
{/* {selectedChartId?.title && (
<div className="sideBarHeader">{selectedChartId?.title}</div>
)} */}
{/* <RenameInput value={selectedChartId?.title || "untited"} /> */}
{/* Render groups dynamically */}
{
chartDataGroups[selectedChartId?.id] &&
<>
<InputSelecterComponent />
</>
}
{/* Info Box */}
<div className="infoBox">
<span className="infoIcon">i</span>
<p>
<em>
By adding templates and widgets, you create a customizable and
dynamic environment.
</em>
</p>
</div>
</div>
);
};
export default Data;
// {chartDataGroups[selectedChartId?.id]?.map((group) => (
// <div key={group.id} className="inputs-wrapper">
// {group.children.map((child, index) => (
// <div key={child.id} className="datas">
// <div className="datas__label">Input {index + 1}</div>
// <div className="datas__class">
// <MultiLevelDropDown data={DATA_STRUCTURE} />
// {/* Add Icon */}
// {group.children.length < 7 && (
// <div
// className="icon"
// onClick={() => handleAddClick(group.id)} // Pass groupId to handleAddClick
// >
// <AddIcon />
// </div>
// )}
// {/* Remove Icon */}
// <span
// className={`datas__separator ${
// group.children.length > 1 ? "" : "disable"
// }`}
// onClick={(e) => {
// e.stopPropagation(); // Prevent event bubbling
// removeChild(group.id, child.id); // Pass groupId and childId to removeChild
// }}
// >
// <RemoveIcon />
// </span>
// </div>
// </div>
// ))}
// </div>
// ))}

View File

@@ -0,0 +1,155 @@
import React, { useEffect, useState } from "react";
import { ArrowIcon } from "../../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
import InputRange from "../../../../ui/inputs/InputRange";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import ChartComponent from "../../../sidebarLeft/visualization/widgets/ChartComponent";
const defaultStyle = {
theme: "Glass",
elementColor: "#ffffff",
blurEffect: 10,
opacity: 10,
selectedElement: "Glass",
};
const defaultChartData = {
duration: "1h",
measurements: {},
datasets: [
{
data: [65, 59, 80, 81, 56, 55, 40],
backgroundColor: "#6f42c1",
borderColor: "#b392f0",
borderWidth: 1,
},
],
labels: ["January", "February", "March", "April", "May", "June", "July"],
};
const Design = () => {
const { selectedChartId } = useWidgetStore();
const [styles, setStyles] = useState<Record<string, typeof defaultStyle>>({});
const currentStyle = selectedChartId
? styles[selectedChartId.id] || defaultStyle
: defaultStyle;
const updateStyle = (updates: Partial<typeof defaultStyle>) => {
if (!selectedChartId) return;
setStyles((prev) => ({
...prev,
[selectedChartId.id]: { ...currentStyle, ...updates },
}));
};
useEffect(() => {
console.log("Styles", styles);
}, [styles]);
return (
<div className="design">
<div className="appearance-container">
<div className="header-container">
<div className="head">Appearance</div>
<div className="icon">
<ArrowIcon />
</div>
</div>
<div className="appearance-style">
<div className="theme-wrapper">
<div className="key">Theme</div>
<div className="value">
<RegularDropDown
header={currentStyle.theme}
options={["Glass", "Fill", "Transparent"]}
onSelect={(theme) => updateStyle({ theme })}
/>
</div>
</div>
{currentStyle.theme === "Glass" && (
<div className="blurEffect-wrapper">
<InputRange
label="Blur Effects"
disabled={false}
value={currentStyle.blurEffect}
min={0}
max={50}
onChange={(blurEffect) => updateStyle({ blurEffect })}
onPointerUp={() => {}}
/>
</div>
)}
{currentStyle.theme !== "Fill" && (
<div className="opacity-wrapper">
<InputRange
label="Opacity"
disabled={false}
value={currentStyle.opacity}
min={0}
max={50}
onChange={(opacity) => updateStyle({ opacity })}
onPointerUp={() => {}}
/>
</div>
)}
<div className="color-wrapper">
<div className="key">Color</div>
<div className="value">
<input
type="color"
value={currentStyle.elementColor}
onChange={(e) => updateStyle({ elementColor: e.target.value })}
/>
<span style={{ marginLeft: "10px" }}>
{currentStyle.elementColor}
</span>
</div>
</div>
</div>
</div>
<div className="element-container">
<div className="display-element">
{selectedChartId ? (
<ChartComponent
type={selectedChartId?.type ?? "bar"}
title={selectedChartId?.title ?? "Chart"}
data={{
labels:
selectedChartId?.data?.labels ?? defaultChartData.labels,
datasets: selectedChartId?.data?.datasets?.length
? selectedChartId.data.datasets
: defaultChartData.datasets,
}}
/>
) : (
"No Preview"
)}
</div>
<div className="name-wrapper">
<div className="key">Name</div>
<input className="value" type="text" />
</div>
<div className="element-wrapper">
<div className="key">Element</div>
<div className="value">
<RegularDropDown
header={currentStyle.selectedElement}
options={["Glass", "Fill", "Transparent"]}
onSelect={(selectedElement) => updateStyle({ selectedElement })}
/>
</div>
</div>
</div>
</div>
);
};
export default Design;