added ui fro and iintegerated ui for decal modification

This commit is contained in:
2025-08-26 15:50:02 +05:30
parent 547fd1af12
commit 165325468a
9 changed files with 204 additions and 45 deletions

View File

@@ -1,23 +1,29 @@
import React from "react";
interface RotationInputProps {
heading?: string; // Optional label for the input
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)
heading?: string;
label?: string;
onChange: (value: string) => void;
placeholder?: string;
type?: string;
value?: number;
disabled?: boolean; // Disable the input if true
disabled?: boolean;
min?: number;
max?: number;
step?: number;
}
const RotationInput: React.FC<RotationInputProps> = ({
label = "Rotate :", // Default label
heading = "Rotation", // Default heading
label = "Rotate :",
heading = "Rotation",
onChange,
placeholder = "Enter value", // Default placeholder
type = "number", // Default type
value = "number",
placeholder = "Enter value",
type = "number",
value,
disabled = false,
min,
max,
step,
}) => {
return (
<div className="custom-input-container">
@@ -32,6 +38,9 @@ const RotationInput: React.FC<RotationInputProps> = ({
placeholder={placeholder}
value={value}
disabled={disabled}
min={min}
max={max}
step={step}
/>
</div>
</div>

View File

@@ -1,42 +1,178 @@
import { useParams } from "react-router-dom";
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
import { useSceneContext } from "../../../../modules/scene/sceneContext";
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
import { LayeringBottomIcon, LayeringTopIcon } from "../../../icons/ExportCommonIcons";
import { useSocketStore } from "../../../../store/builder/store";
import InputRange from "../../../ui/inputs/InputRange";
import RotationInput from "../customInput/RotationInput";
import { getUserData } from "../../../../functions/getUserData";
// import { upsertWallApi } from "../../../../services/factoryBuilder/wall/upsertWallApi";
// import { upsertFloorApi } from "../../../../services/factoryBuilder/floor/upsertFloorApi";
const SelectedDecalProperties = () => {
const { selectedDecal, setSelectedDecal } = useBuilderStore();
const { wallStore, floorStore } = useSceneContext();
const { updateDecal: updateDecalFromWall } = wallStore();
const { updateDecal: updateDecalFromFloor } = floorStore();
const { userId, organization } = getUserData();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
const { socket } = useSocketStore();
const updateBackend = (updatedData: Wall | Floor) => {
if ('wallUuid' in updatedData) {
if (projectId && updatedData) {
// API
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedData);
// SOCKET
const data = {
wallData: updatedData,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:model-Wall:add', data);
}
} else if ('floorUuid' in updatedData) {
if (projectId && updatedData) {
// API
// upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedData);
// SOCKET
const data = {
floorData: updatedData,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:model-Floor:add', data);
}
}
}
const handleRotationChange = (value: number) => {
if (!selectedDecal) return;
const updatedDecal = { ...selectedDecal.decalData, decalRotation: value };
setSelectedDecal({ ...selectedDecal, decalData: updatedDecal });
if ('wallUuid' in selectedDecal.decalData.decalType) {
const updatedWall = updateDecalFromWall(updatedDecal.decalUuid, updatedDecal);
if (updatedWall) updateBackend(updatedWall);
} else if ('floorUuid' in selectedDecal.decalData.decalType) {
const updatedFloor = updateDecalFromFloor(updatedDecal.decalUuid, updatedDecal);
if (updatedFloor) updateBackend(updatedFloor);
}
}
const handleScaleChange = (value: number) => {
if (!selectedDecal) return;
const updatedDecal = { ...selectedDecal.decalData, decalScale: value };
setSelectedDecal({ ...selectedDecal, decalData: updatedDecal });
if ('wallUuid' in selectedDecal.decalData.decalType) {
const updatedWall = updateDecalFromWall(updatedDecal.decalUuid, updatedDecal);
if (updatedWall) updateBackend(updatedWall);
} else if ('floorUuid' in selectedDecal.decalData.decalType) {
const updatedFloor = updateDecalFromFloor(updatedDecal.decalUuid, updatedDecal);
if (updatedFloor) updateBackend(updatedFloor);
}
}
const handleOpacityChange = (value: number) => {
if (!selectedDecal) return;
const updatedDecal = { ...selectedDecal.decalData, decalOpacity: value };
setSelectedDecal({ ...selectedDecal, decalData: updatedDecal });
if ('wallUuid' in selectedDecal.decalData.decalType) {
const updatedWall = updateDecalFromWall(updatedDecal.decalUuid, updatedDecal);
if (updatedWall) updateBackend(updatedWall);
} else if ('floorUuid' in selectedDecal.decalData.decalType) {
const updatedFloor = updateDecalFromFloor(updatedDecal.decalUuid, updatedDecal);
if (updatedFloor) updateBackend(updatedFloor);
}
}
const handleLayerChange = (direction: "up" | "down") => {
if (!selectedDecal) return;
const position: [number, number, number] = [...(selectedDecal.decalData.decalPosition || [0, 0, 0]),];
if (direction === "up") {
position[2] = Math.abs(position[2]);
} else {
position[2] = -Math.abs(position[2]);
}
const updatedDecal: Decal = { ...selectedDecal.decalData, decalPosition: position, };
setSelectedDecal({ ...selectedDecal, decalData: updatedDecal });
if ("wallUuid" in selectedDecal.decalData.decalType) {
const updatedWall = updateDecalFromWall(updatedDecal.decalUuid, updatedDecal);
if (updatedWall) updateBackend(updatedWall);
} else if ("floorUuid" in selectedDecal.decalData.decalType) {
const updatedFloor = updateDecalFromFloor(updatedDecal.decalUuid, updatedDecal);
if (updatedFloor) updateBackend(updatedFloor);
}
};
if (!selectedDecal) return null;
return (
<div className="decal-transformation-container">
<div className="header">Decal Properties</div>
<section>
<RotationInput
onChange={() => { }}
value={10}
onChange={(e) => { handleRotationChange(parseFloat(e)) }}
value={selectedDecal.decalData.decalRotation || 0}
/>
<RotationInput
min={0.1}
max={10}
step={0.1}
heading="Scaling"
label="Scale :"
onChange={() => { }}
value={10}
onChange={(e) => { handleScaleChange(parseFloat(e)) }}
value={selectedDecal.decalData.decalScale || 1}
/>
</section>
<section>
<InputRange
label="Opacity"
value={1}
min={0}
value={selectedDecal.decalData.decalOpacity || 1}
min={0.1}
step={0.1}
max={1}
onChange={(value: number) => console.log(value)}
onChange={(value: number) => handleOpacityChange(value)}
/>
<div className="transformation-wrapper opacity">
<div className="transformation-header">Layering</div>
<div className="layers-list">
<button className="layer-move-btn">
<button
className="layer-move-btn"
onClick={() => handleLayerChange("down")}
>
<LayeringBottomIcon />
</button>
<button className="layer-move-btn">
<button
className="layer-move-btn"
onClick={() => handleLayerChange("up")}
>
<LayeringTopIcon />
</button>
</div>

View File

@@ -93,7 +93,7 @@ function DecalInstance({ parent, visible = true, decal, zPosition = decal.decalP
// debug
visible={visible}
position={[decal.decalPosition[0], decal.decalPosition[1], zPosition]}
rotation={[0, 0, 0]}
rotation={[0, 0, decal.decalRotation * (Math.PI / 180)]}
scale={[decal.decalScale, decal.decalScale, 0.01]}
userData={decal}
onClick={(e) => {
@@ -101,7 +101,7 @@ function DecalInstance({ parent, visible = true, decal, zPosition = decal.decalP
if (e.object.userData.decalUuid) {
e.stopPropagation();
if (toolMode === 'cursor') {
setSelectedDecal(e.object);
setSelectedDecal({ decalMesh: e.object, decalData: decal });
setSelectedWall(null);
setSelectedFloor(null);
} else if (toolMode === '3D-Delete') {
@@ -131,7 +131,7 @@ function DecalInstance({ parent, visible = true, decal, zPosition = decal.decalP
}
}}
onPointerMissed={() => {
if (selectedDecal && selectedDecal.userData.decalUuid === decal.decalUuid) {
if (selectedDecal && selectedDecal.decalMesh.userData.decalUuid === decal.decalUuid) {
setSelectedDecal(null);
}
}}
@@ -141,6 +141,8 @@ function DecalInstance({ parent, visible = true, decal, zPosition = decal.decalP
side={THREE.DoubleSide}
polygonOffset
polygonOffsetFactor={-1}
transparent
opacity={decal.decalOpacity}
/>
</Decal>
)

View File

@@ -167,6 +167,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
decalId: 'Default Decal',
decalPosition: [0, 0, wall.wallThickness / 2 + 0.001],
decalRotation: 0,
decalOpacity: 1,
decalScale: 1,
decalType: { type: 'Wall', wallUuid: wall.wallUuid }
}
@@ -183,7 +184,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
<MeshDiscardMaterial />
{wall.decals.map((decal) => (
<DecalInstance parent={wall} zPosition={wall.wallThickness / 2 + 0.001} visible={visible} key={decal.decalUuid} decal={decal} />
<DecalInstance parent={wall} visible={visible} key={decal.decalUuid} decal={decal} />
))}
</mesh>
</mesh>

View File

@@ -165,7 +165,7 @@ export default function PostProcessing() {
)}
{selectedDecal && (
<Outline
selection={selectedDecal}
selection={selectedDecal.decalMesh}
selectionLayer={10}
width={2000}
blendFunction={BlendFunction.ALPHA}

View File

@@ -38,7 +38,7 @@ interface BuilderState {
zoneColor: string;
// Decal Settings
selectedDecal: Object3D | null;
selectedDecal: { decalMesh: Object3D, decalData: Decal } | null;
deletableDecal: Object3D | null;
// Aisle General
@@ -87,7 +87,7 @@ interface BuilderState {
setZoneColor: (color: string) => void;
// Setters - Decal
setSelectedDecal: (decal: Object3D | null) => void;
setSelectedDecal: (decal: { decalMesh: Object3D, decalData: Decal } | null) => void;
setDeletableDecal: (decal: Object3D | null) => void;
// Setters - Aisle General
@@ -290,7 +290,7 @@ export const useBuilderStore = create<BuilderState>()(
// === Setters: Decal ===
setSelectedDecal: (decal: Object3D | null) => {
setSelectedDecal: (decal: { decalMesh: Object3D, decalData: Decal } | null) => {
set((state) => {
state.selectedDecal = decal;
})

View File

@@ -20,7 +20,7 @@ interface FloorStore {
setDepth: (uuid: string, depth: number) => void;
setMaterial: (uuid: string, sideMaterial: string, topMaterial: string) => void;
addDecal: (floors: string, decal: Decal) => void;
updateDecal: (decalUuid: string, decal: Decal) => void;
updateDecal: (decalUuid: string, decal: Decal) => Floor | undefined;
removeDecal: (decalUuid: string) => Floor | undefined;
updateDecalPosition: (decalUuid: string, position: [number, number, number]) => void;
updateDecalRotation: (decalUuid: string, rotation: number) => void;
@@ -203,15 +203,20 @@ export const createFloorStore = () => {
}
}),
updateDecal: (decalUuid, updatedDecal) => set(state => {
for (const floor of state.floors) {
const index = floor.decals.findIndex(d => d.decalUuid === decalUuid);
if (index !== -1) {
floor.decals[index] = updatedDecal;
break;
updateDecal: (decalUuid, updatedDecal) => {
let affectedFloor: Floor | undefined;
set(state => {
for (const floor of state.floors) {
const index = floor.decals.findIndex(d => d.decalUuid === decalUuid);
if (index !== -1) {
floor.decals[index] = updatedDecal;
affectedFloor = JSON.parse(JSON.stringify(floor));
break;
}
}
}
}),
})
return affectedFloor;
},
removeDecal: (decalUuid) => {
let affectedFloor: Floor | undefined;

View File

@@ -10,7 +10,7 @@ interface WallStore {
clearWalls: () => void;
removeWallByPoints: (Points: [Point, Point]) => Wall | undefined;
addDecal: (wallUuid: string, decal: Decal) => void;
updateDecal: (decalUuid: string, decal: Decal) => void;
updateDecal: (decalUuid: string, decal: Decal) => Wall | undefined;
removeDecal: (decalUuid: string) => Wall | undefined;
updateDecalPosition: (decalUuid: string, position: [number, number, number]) => void;
updateDecalRotation: (decalUuid: string, rotation: number) => void;
@@ -90,14 +90,19 @@ export const createWallStore = () => {
}
}),
updateDecal: (decalUuid, decal) => set((state) => {
for (const wall of state.walls) {
const decalToUpdate = wall.decals.find(d => d.decalUuid === decalUuid);
if (decalToUpdate) {
Object.assign(decalToUpdate, decal);
updateDecal: (decalUuid, decal) => {
let affectedWall: Wall | undefined;
set((state) => {
for (const wall of state.walls) {
const decalToUpdate = wall.decals.find(d => d.decalUuid === decalUuid);
if (decalToUpdate) {
Object.assign(decalToUpdate, decal);
affectedWall = JSON.parse(JSON.stringify(wall));
}
}
}
}),
});
return affectedWall;
},
removeDecal: (decalUuid) => {
let affectedWall: Wall | undefined;

View File

@@ -88,6 +88,7 @@ interface Decal {
decalType: WallDecal | FloorDecal;
decalPosition: [number, number, number];
decalRotation: number;
decalOpacity: number;
decalScale: number;
}