diff --git a/app/src/assets/image/wallTextures/defaultTexture.jpg b/app/src/assets/image/wallTextures/defaultTexture.jpg new file mode 100644 index 0000000..97dfb91 Binary files /dev/null and b/app/src/assets/image/wallTextures/defaultTexture.jpg differ diff --git a/app/src/assets/image/wallTextures/wallTexture.png b/app/src/assets/image/wallTextures/wallTexture.png new file mode 100644 index 0000000..d3a7a0a Binary files /dev/null and b/app/src/assets/image/wallTextures/wallTexture.png differ diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/WallProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/WallProperties.tsx new file mode 100644 index 0000000..ee1d87b --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/WallProperties.tsx @@ -0,0 +1,213 @@ +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"; + +// 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 [wallProperties, setWallProperties] = useState({ + height: "10", + thickness: "10", + length: "10", + }); + + const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1"); + + const [materials, setMaterials] = useState([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 handleInputChange = ( + key: keyof typeof wallProperties, + newValue: string + ) => { + setWallProperties((prev) => ({ + ...prev, + [key]: 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 ( +
+
Wall
+
+ handleInputChange("height", val)} + /> + handleInputChange("thickness", val)} + /> + handleInputChange("length", val)} + /> +
+ +
+
+
Materials
+ +
+ +
+
+
setActiveSide("side1")} + > +
Side 1
+
+ {selectedMaterials.side1 && ( + {selectedMaterials.side1.textureName} + )} +
+
+ +
setActiveSide("side2")} + > +
Side 2
+
+ {selectedMaterials.side2 && ( + {selectedMaterials.side2.textureName} + )} +
+
+
+ +
+ {selectedMaterials[activeSide] && ( + {selectedMaterials[activeSide]!.textureName} + )} +
+
+ +
+ {materials.length === 0 ? ( +
No materials added yet.
+ ) : ( +
+ {materials.map((material, index) => ( +
handleSelectMaterial(material)} + > +
+
+ {material.textureName} +
+
{material.textureName}
+
+
{ + e.stopPropagation(); + handleRemoveMaterial(index); + }} + > + +
+
+ ))} +
+ )} +
+
+
+ ); +}; + +export default WallProperties; diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index 5b567af..d5773a9 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -12,6 +12,7 @@ import { useRemovedLayer, useZones, useZonePoints, + useViewSceneStore, } from "../../../store/builder/store"; import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi"; @@ -525,7 +526,7 @@ const ZoneGroup: React.FC = () => { setEndPoint(point); } }); - + const { viewSceneLabels } = useViewSceneStore(); return ( @@ -577,6 +578,7 @@ const ZoneGroup: React.FC = () => { ); })} {!toggleView && + viewSceneLabels && (() => { const points3D = zone.points || []; const coords2D = points3D.map((p: any) => [p[0], p[2]]); diff --git a/app/src/modules/simulation/machine/instances/machineInstances.tsx b/app/src/modules/simulation/machine/instances/machineInstances.tsx index e228b01..83b96ae 100644 --- a/app/src/modules/simulation/machine/instances/machineInstances.tsx +++ b/app/src/modules/simulation/machine/instances/machineInstances.tsx @@ -2,19 +2,21 @@ import React from "react"; import MachineInstance from "./machineInstance/machineInstance"; import { useMachineStore } from "../../../../store/simulation/useMachineStore"; import MachineContentUi from "../../ui3d/MachineContentUi"; +import { useViewSceneStore } from "../../../../store/builder/store"; function MachineInstances() { - const { machines } = useMachineStore(); - return ( - <> - {machines.map((machine: MachineStatus) => ( - - - - - ))} - - ); + const { machines } = useMachineStore(); + const { viewSceneLabels } = useViewSceneStore(); + return ( + <> + {machines.map((machine: MachineStatus) => ( + + + {viewSceneLabels && } + + ))} + + ); } export default MachineInstances; diff --git a/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx b/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx index 29b6ea0..6a1d333 100644 --- a/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx +++ b/app/src/modules/simulation/storageUnit/instances/storageUnitInstances.tsx @@ -1,21 +1,23 @@ -import React from 'react' -import StorageUnitInstance from './storageUnitInstance/storageUnitInstance' -import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore' -import StorageContentUi from '../../ui3d/StorageContentUi'; +import React from "react"; +import StorageUnitInstance from "./storageUnitInstance/storageUnitInstance"; +import { useStorageUnitStore } from "../../../../store/simulation/useStorageUnitStore"; +import StorageContentUi from "../../ui3d/StorageContentUi"; +import { useViewSceneStore } from "../../../../store/builder/store"; function StorageUnitInstances() { - const { storageUnits } = useStorageUnitStore(); + const { storageUnits } = useStorageUnitStore(); + const { viewSceneLabels } = useViewSceneStore(); - return ( - <> - {storageUnits.map((storageUnit: StorageUnitStatus) => ( - - - - - ))} - - ) + return ( + <> + {storageUnits.map((storageUnit: StorageUnitStatus) => ( + + + {viewSceneLabels && } + + ))} + + ); } -export default StorageUnitInstances \ No newline at end of file +export default StorageUnitInstances; diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index 1c7cd51..35b8343 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -2,20 +2,22 @@ import React from "react"; import VehicleInstance from "./instance/vehicleInstance"; import { useVehicleStore } from "../../../../store/simulation/useVehicleStore"; import VehicleContentUi from "../../ui3d/VehicleContentUi"; +import { useViewSceneStore } from "../../../../store/builder/store"; function VehicleInstances() { - const { vehicles } = useVehicleStore(); + const { vehicles } = useVehicleStore(); + const { viewSceneLabels } = useViewSceneStore(); - return ( - <> - {vehicles.map((vehicle: VehicleStatus) => ( - - - - - ))} - - ); + return ( + <> + {vehicles.map((vehicle: VehicleStatus) => ( + + + {viewSceneLabels && } + + ))} + + ); } export default VehicleInstances; diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index dc6adc3..6b58301 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -14,6 +14,7 @@ import { useLoadingProgress, useWidgetSubOption, useSaveVersion, + useViewSceneStore, } from "../store/builder/store"; import { useNavigate } from "react-router-dom"; import { usePlayButtonStore } from "../store/usePlayButtonStore"; @@ -38,6 +39,7 @@ import RegularDropDown from "../components/ui/inputs/RegularDropDown"; import VersionSaved from "../components/layout/sidebarRight/versionHisory/VersionSaved"; import SimulationPlayer from "../components/ui/simulation/simulationPlayer"; import { useAssetsStore } from "../store/builder/useAssetStore"; +import InputToggle from "../components/ui/inputs/InputToggle"; const Project: React.FC = () => { let navigate = useNavigate(); @@ -110,6 +112,9 @@ const Project: React.FC = () => { setSelectedLayout(option); // Set selected layout console.log("Selected layout:", option); }; + + const { viewSceneLabels, setViewSceneLabels } = useViewSceneStore(); + return (
{!selectedUser && ( @@ -128,6 +133,16 @@ const Project: React.FC = () => { {activeModule !== "market" && !isPlaying && !isVersionSaved && ( )} + {isPlaying && activeModule === "simulation" && ( +
+ setViewSceneLabels(!viewSceneLabels)} + /> +
+ )} {isPlaying && activeModule === "simulation" && } {isPlaying && activeModule !== "simulation" && } diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index 70e8a63..99361bd 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -450,88 +450,85 @@ interface ShortcutStore { } export const useShortcutStore = create((set) => ({ - showShortcuts: false, - setShowShortcuts: (value) => set({ showShortcuts: value }), - toggleShortcuts: () => - set((state) => ({ showShortcuts: !state.showShortcuts })), + showShortcuts: false, + setShowShortcuts: (value) => set({ showShortcuts: value }), + toggleShortcuts: () => + set((state) => ({ showShortcuts: !state.showShortcuts })), })); export const useMachineCount = create((set: any) => ({ - machineCount: 0, - setMachineCount: (x: any) => set({ machineCount: x }), + machineCount: 0, + setMachineCount: (x: any) => set({ machineCount: x }), })); export const useMachineUptime = create((set: any) => ({ - machineActiveTime: 0, - setMachineActiveTime: (x: any) => set({ machineActiveTime: x }), + machineActiveTime: 0, + setMachineActiveTime: (x: any) => set({ machineActiveTime: x }), })); export const useMaterialCycle = create((set: any) => ({ - materialCycleTime: 0, - setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }), + materialCycleTime: 0, + setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }), })); export const useThroughPutData = create((set: any) => ({ - throughputData: 0, - setThroughputData: (x: any) => set({ throughputData: x }), + throughputData: 0, + setThroughputData: (x: any) => set({ throughputData: x }), })); export const useProductionCapacityData = create((set: any) => ({ - productionCapacityData: 0, - setProductionCapacityData: (x: any) => set({ productionCapacityData: x }), + productionCapacityData: 0, + setProductionCapacityData: (x: any) => set({ productionCapacityData: x }), })); export const useProcessBar = create((set: any) => ({ - processBar: [], - setProcessBar: (x: any) => set({ processBar: x }), + processBar: [], + setProcessBar: (x: any) => set({ processBar: x }), })); - type InputValuesStore = { - inputValues: Record; - setInputValues: (values: Record) => void; - updateInputValue: (label: string, value: string) => void; // <- New + inputValues: Record; + setInputValues: (values: Record) => void; + updateInputValue: (label: string, value: string) => void; // <- New }; export const useInputValues = create((set) => ({ - inputValues: {}, - setInputValues: (values) => set({ inputValues: values }), - updateInputValue: (label, value) => - set((state) => ({ - inputValues: { - ...state.inputValues, - [label]: value, - }, - })), + inputValues: {}, + setInputValues: (values) => set({ inputValues: values }), + updateInputValue: (label, value) => + set((state) => ({ + inputValues: { + ...state.inputValues, + [label]: value, + }, + })), })); export interface ROISummaryData { - productName: string; - roiPercentage: number; - paybackPeriod: number; - totalCost: number; - revenueGenerated: number; - netProfit: number; - netLoss: number; + productName: string; + roiPercentage: number; + paybackPeriod: number; + totalCost: number; + revenueGenerated: number; + netProfit: number; + netLoss: number; } interface ROISummaryStore { - roiSummary: ROISummaryData; - setRoiSummaryData: (values: ROISummaryData) => void; + roiSummary: ROISummaryData; + setRoiSummaryData: (values: ROISummaryData) => void; } export const useROISummaryData = create((set) => ({ - roiSummary: { - productName: "", - roiPercentage: 0, - paybackPeriod: 0, - totalCost: 0, - revenueGenerated: 0, - netProfit: 0, - netLoss: 0, - }, - setRoiSummaryData: (values) => set({ roiSummary: values }), + roiSummary: { + productName: "", + roiPercentage: 0, + paybackPeriod: 0, + totalCost: 0, + revenueGenerated: 0, + netProfit: 0, + netLoss: 0, + }, + setRoiSummaryData: (values) => set({ roiSummary: values }), })); - - interface CompareStore { comparePopUp: boolean; setComparePopUp: (value: boolean) => void; @@ -593,3 +590,13 @@ export const useVersionStore = create((set) => ({ ), })), })); + +interface ViewSceneState { + viewSceneLabels: boolean; + setViewSceneLabels: (value: boolean) => void; +} + +export const useViewSceneStore = create((set) => ({ + viewSceneLabels: false, + setViewSceneLabels: (value) => set({ viewSceneLabels: value }), +})); diff --git a/app/src/styles/scene/scene.scss b/app/src/styles/scene/scene.scss index 81c0451..246efeb 100644 --- a/app/src/styles/scene/scene.scss +++ b/app/src/styles/scene/scene.scss @@ -4,11 +4,21 @@ .distance-text-wrapper, .zone-name-wrapper, .pointer-none { - pointer-events: none !important; + pointer-events: auto !important; + background-color: gray; +} + +.zone-name-wrapper { + background: var(--background-color-accent); + color: var(--text-button-color); + outline: 1px solid var(--border-color); + border-radius: #{$border-radius-medium}; + backdrop-filter: blur(12px); } .distance-text { pointer-events: none !important; + div { position: absolute; transform: translate(-50%, -50%) scale(0.8); @@ -22,18 +32,16 @@ border-radius: #{$border-radius-medium}; box-shadow: var(--box-shadow-light); } + .area { background: #008cff; } } -.zone-name{ - background: var(--background-color); - padding: 2px 8px; +.zone-name { + padding: 2px 10px; text-wrap: nowrap; - backdrop-filter: blur(12px); - border-radius: #{$border-radius-medium}; - outline: 1px solid var(--border-color); + color: var(--text-button-color); } // @@ -55,18 +63,49 @@ outline: 1px solid var(--border-color); transform: translate(-50%, 12px); z-index: 100; + .presets-container { @include flex-center; gap: 4px; + .preset { background: var(--background-color); padding: 2px 8px; border-radius: #{$border-radius-large}; outline: 1px solid var(--border-color); } + .active { background: var(--background-color-accent); color: var(--text-button-color); } } } + + + +.label-toogler { + position: fixed; + bottom: 5%; + right: 2%; + z-index: 10; + + background: var(--background-color); + backdrop-filter: blur(10px); + outline: 1px solid var(--border-color); + border-radius: 8px; + + .input-toggle-container { + + display: flex; + flex-direction: column; + gap: 12px; + + .check-box { + .check-box-style { + + // background: var(--text-button-color) !important; + } + } + } +} \ No newline at end of file