545 lines
21 KiB
TypeScript
545 lines
21 KiB
TypeScript
import React, { useEffect, useState } from "react";
|
|
import { useParams } from "react-router-dom";
|
|
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 InputToggle from "../../../ui/inputs/InputToggle";
|
|
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
|
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
|
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
|
import { useSocketStore } from "../../../../store/builder/store";
|
|
import { getUserData } from "../../../../functions/getUserData";
|
|
|
|
// import { upsertAisleApi } from "../../../../services/factoryBuilder/aisle/upsertAisleApi";
|
|
|
|
interface TextureItem {
|
|
color: string;
|
|
id: AisleColors;
|
|
brief: string;
|
|
texture: string;
|
|
}
|
|
|
|
const SelectedAisleProperties: React.FC = () => {
|
|
const [collapsePresets, setCollapsePresets] = useState(false);
|
|
const [collapseTexture, setCollapseTexture] = useState(true);
|
|
const { aisleStore } = useSceneContext();
|
|
const { getAisleById, updateAisle, setDashedAisleProperties, setDottedAisleProperties, setArrowsAisleProperties, setArcAisleWidth, setColor } = aisleStore();
|
|
const { selectedVersionStore } = useVersionContext();
|
|
const { selectedVersion } = selectedVersionStore();
|
|
const { socket } = useSocketStore();
|
|
const { userId, organization } = getUserData();
|
|
const { projectId } = useParams();
|
|
const [selectedAisleData, setSelectedAisleData] = useState<Aisle | undefined>();
|
|
|
|
const { selectedAisle, setSelectedAisle } = useBuilderStore();
|
|
|
|
useEffect(() => {
|
|
const aisleData = getAisleById(selectedAisle?.aisleMesh?.uuid || "");
|
|
setSelectedAisleData(aisleData);
|
|
}, [selectedAisle, getAisleById]);
|
|
|
|
if (!selectedAisleData) return null;
|
|
|
|
const updateBackend = (updatedAisle: Aisle) => {
|
|
if (updatedAisle && projectId) {
|
|
|
|
// API
|
|
|
|
// upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '');
|
|
|
|
// SOCKET
|
|
|
|
const data = {
|
|
projectId: projectId,
|
|
versionId: selectedVersion?.versionId || '',
|
|
userId: userId,
|
|
organization: organization,
|
|
aisleUuid: updatedAisle.aisleUuid,
|
|
points: updatedAisle.points,
|
|
type: updatedAisle.type
|
|
}
|
|
|
|
socket.emit('v1:model-aisle:add', data);
|
|
}
|
|
}
|
|
|
|
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 createAisleTypeObject = (newType: AisleTypes, currentType: AisleType): AisleType => {
|
|
switch (newType) {
|
|
case 'solid-aisle':
|
|
return {
|
|
aisleType: 'solid-aisle',
|
|
aisleColor: currentType.aisleColor,
|
|
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1
|
|
} as SolidAisle;
|
|
|
|
case 'dashed-aisle':
|
|
return {
|
|
aisleType: 'dashed-aisle',
|
|
aisleColor: currentType.aisleColor,
|
|
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1,
|
|
dashLength: 'dashLength' in currentType ? (currentType as DashedAisle).dashLength : 0.5,
|
|
gapLength: 'gapLength' in currentType ? (currentType as DashedAisle).gapLength : 0.3
|
|
} as DashedAisle;
|
|
|
|
case 'dotted-aisle':
|
|
return {
|
|
aisleType: 'dotted-aisle',
|
|
aisleColor: currentType.aisleColor,
|
|
dotRadius: 'dotRadius' in currentType ? (currentType as DottedAisle).dotRadius : 0.1,
|
|
gapLength: 'gapLength' in currentType ? (currentType as DottedAisle).gapLength : 0.3
|
|
} as DottedAisle;
|
|
|
|
case 'arrow-aisle':
|
|
return {
|
|
aisleType: 'arrow-aisle',
|
|
aisleColor: currentType.aisleColor,
|
|
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1
|
|
} as ArrowAisle;
|
|
|
|
case 'arrows-aisle':
|
|
return {
|
|
aisleType: 'arrows-aisle',
|
|
aisleColor: currentType.aisleColor,
|
|
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1,
|
|
aisleLength: 'aisleLength' in currentType ? (currentType as ArrowsAisle).aisleLength : 0.6,
|
|
gapLength: 'gapLength' in currentType ? (currentType as ArrowsAisle).gapLength : 0.3
|
|
} as ArrowsAisle;
|
|
|
|
case 'arc-aisle':
|
|
return {
|
|
aisleType: 'arc-aisle',
|
|
aisleColor: currentType.aisleColor,
|
|
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1,
|
|
isFlipped: 'isFlipped' in currentType ? (currentType as ArcAisle).isFlipped : false
|
|
} as ArcAisle;
|
|
|
|
case 'circle-aisle':
|
|
return {
|
|
aisleType: 'circle-aisle',
|
|
aisleColor: currentType.aisleColor,
|
|
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1
|
|
} as CircleAisle;
|
|
|
|
case 'junction-aisle':
|
|
return {
|
|
aisleType: 'junction-aisle',
|
|
aisleColor: currentType.aisleColor,
|
|
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1,
|
|
isFlipped: 'isFlipped' in currentType ? (currentType as JunctionAisle).isFlipped : false
|
|
} as JunctionAisle;
|
|
|
|
default:
|
|
return {
|
|
aisleType: 'solid-aisle',
|
|
aisleColor: currentType.aisleColor,
|
|
aisleWidth: 0.1
|
|
} as SolidAisle;
|
|
}
|
|
};
|
|
|
|
const handleAisleTypeChange = (newType: AisleTypes) => {
|
|
if (!selectedAisle?.aisleData) return;
|
|
const newAisleType = createAisleTypeObject(newType, selectedAisleData.type);
|
|
|
|
const updatedAisle = updateAisle(selectedAisleData.aisleUuid, {
|
|
type: newAisleType
|
|
});
|
|
|
|
setSelectedAisle({ aisleData: selectedAisle.aisleData, aisleMesh: null });
|
|
|
|
setSelectedAisleData({
|
|
...selectedAisleData,
|
|
type: newAisleType
|
|
});
|
|
|
|
if (updatedAisle) {
|
|
updateBackend(updatedAisle);
|
|
}
|
|
};
|
|
|
|
const handleColorChange = (value: AisleColors) => {
|
|
const updatedAisle = setColor(selectedAisleData.aisleUuid, value);
|
|
|
|
setSelectedAisleData({
|
|
...selectedAisleData,
|
|
type: {
|
|
...selectedAisleData.type,
|
|
aisleColor: value
|
|
}
|
|
})
|
|
|
|
if (updatedAisle) {
|
|
updateBackend(updatedAisle);
|
|
}
|
|
};
|
|
|
|
const handleAisleWidthChange = (value: string) => {
|
|
const width = parseFloat(value);
|
|
if (!isNaN(width) && selectedAisleData.type.aisleType !== 'dotted-aisle') {
|
|
const updatedAisle = updateAisle(selectedAisleData.aisleUuid, {
|
|
type: {
|
|
...selectedAisleData.type,
|
|
aisleWidth: width
|
|
}
|
|
});
|
|
|
|
setSelectedAisleData({
|
|
...selectedAisleData,
|
|
type: {
|
|
...selectedAisleData.type,
|
|
aisleWidth: width
|
|
}
|
|
})
|
|
|
|
if (updatedAisle) {
|
|
updateBackend(updatedAisle);
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleDashLengthChange = (value: string) => {
|
|
const length = parseFloat(value);
|
|
if (!isNaN(length) && selectedAisleData.type.aisleType === 'dashed-aisle') {
|
|
const updatedAisle = setDashedAisleProperties(selectedAisleData.aisleUuid, {
|
|
dashLength: length
|
|
});
|
|
|
|
setSelectedAisleData({
|
|
...selectedAisleData,
|
|
type: {
|
|
...(selectedAisleData.type as DashedAisle),
|
|
dashLength: length
|
|
}
|
|
})
|
|
|
|
if (updatedAisle) {
|
|
updateBackend(updatedAisle);
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleGapLengthChange = (value: string) => {
|
|
const length = parseFloat(value);
|
|
if (!isNaN(length) && (selectedAisleData.type.aisleType === 'dashed-aisle' || selectedAisleData.type.aisleType === 'dotted-aisle' || selectedAisleData.type.aisleType === 'arrows-aisle')) {
|
|
if (selectedAisleData.type.aisleType === 'dashed-aisle') {
|
|
const updatedAisle = setDashedAisleProperties(selectedAisleData.aisleUuid, {
|
|
gapLength: length
|
|
});
|
|
|
|
setSelectedAisleData({
|
|
...selectedAisleData,
|
|
type: {
|
|
...(selectedAisleData.type as DashedAisle),
|
|
gapLength: length
|
|
}
|
|
})
|
|
|
|
if (updatedAisle) {
|
|
updateBackend(updatedAisle);
|
|
}
|
|
} else if (selectedAisleData.type.aisleType === 'dotted-aisle') {
|
|
const updatedAisle = setDottedAisleProperties(selectedAisleData.aisleUuid, {
|
|
gapLength: length
|
|
});
|
|
|
|
setSelectedAisleData({
|
|
...selectedAisleData,
|
|
type: {
|
|
...(selectedAisleData.type as DottedAisle),
|
|
gapLength: length
|
|
}
|
|
})
|
|
|
|
if (updatedAisle) {
|
|
updateBackend(updatedAisle);
|
|
}
|
|
} else if (selectedAisleData.type.aisleType === 'arrows-aisle') {
|
|
const updatedAisle = setArrowsAisleProperties(selectedAisleData.aisleUuid, {
|
|
gapLength: length
|
|
});
|
|
|
|
setSelectedAisleData({
|
|
...selectedAisleData,
|
|
type: {
|
|
...(selectedAisleData.type as ArrowsAisle),
|
|
gapLength: length
|
|
}
|
|
})
|
|
|
|
if (updatedAisle) {
|
|
updateBackend(updatedAisle);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleDotRadiusChange = (value: string) => {
|
|
const radius = parseFloat(value);
|
|
if (!isNaN(radius) && selectedAisleData.type.aisleType === 'dotted-aisle') {
|
|
const updatedAisle = setDottedAisleProperties(selectedAisleData.aisleUuid, {
|
|
dotRadius: radius
|
|
});
|
|
|
|
setSelectedAisleData({
|
|
...selectedAisleData,
|
|
type: {
|
|
...(selectedAisleData.type as DottedAisle),
|
|
dotRadius: radius
|
|
}
|
|
})
|
|
|
|
if (updatedAisle) {
|
|
updateBackend(updatedAisle);
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleAisleLengthChange = (value: string) => {
|
|
const length = parseFloat(value);
|
|
if (!isNaN(length) && selectedAisleData.type.aisleType === 'arrows-aisle') {
|
|
const updatedAisle = setArrowsAisleProperties(selectedAisleData.aisleUuid, {
|
|
aisleLength: length
|
|
});
|
|
|
|
setSelectedAisleData({
|
|
...selectedAisleData,
|
|
type: {
|
|
...(selectedAisleData.type as ArrowsAisle),
|
|
aisleLength: length
|
|
}
|
|
})
|
|
|
|
if (updatedAisle) {
|
|
updateBackend(updatedAisle);
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleIsFlippedChange = () => {
|
|
if (selectedAisleData.type.aisleType === 'arc-aisle' || selectedAisleData.type.aisleType === 'junction-aisle') {
|
|
const currentType = selectedAisleData.type as ArcAisle | JunctionAisle;
|
|
const currentFlipped = currentType.isFlipped || false;
|
|
const updatedAisle = setArcAisleWidth(selectedAisleData.aisleUuid, {
|
|
isFlipped: !currentFlipped
|
|
});
|
|
|
|
setSelectedAisleData({
|
|
...selectedAisleData,
|
|
type: {
|
|
...currentType,
|
|
isFlipped: !currentFlipped
|
|
}
|
|
})
|
|
|
|
if (updatedAisle) {
|
|
updateBackend(updatedAisle);
|
|
}
|
|
}
|
|
};
|
|
|
|
const renderAdvancedProperties = () => {
|
|
switch (selectedAisleData.type.aisleType) {
|
|
case 'dashed-aisle':
|
|
const dashedType = selectedAisleData.type as DashedAisle;
|
|
return (
|
|
<>
|
|
<InputWithDropDown
|
|
label="Dash Length"
|
|
value={`${dashedType.dashLength}`}
|
|
min={0.1}
|
|
step={0.1}
|
|
max={2}
|
|
onChange={handleDashLengthChange}
|
|
/>
|
|
<InputWithDropDown
|
|
label="Gap Length"
|
|
value={`${dashedType.gapLength}`}
|
|
min={0.1}
|
|
step={0.1}
|
|
max={2}
|
|
onChange={handleGapLengthChange}
|
|
/>
|
|
</>
|
|
);
|
|
case 'dotted-aisle':
|
|
const dottedType = selectedAisleData.type as DottedAisle;
|
|
return (
|
|
<>
|
|
<InputWithDropDown
|
|
label="Dot Radius"
|
|
value={`${dottedType.dotRadius}`}
|
|
min={0.1}
|
|
step={0.1}
|
|
max={2}
|
|
onChange={handleDotRadiusChange}
|
|
/>
|
|
<InputWithDropDown
|
|
label="Gap Length"
|
|
value={`${dottedType.gapLength}`}
|
|
min={0.1}
|
|
step={0.1}
|
|
max={2}
|
|
onChange={handleGapLengthChange}
|
|
/>
|
|
</>
|
|
);
|
|
case 'arrows-aisle':
|
|
const arrowsType = selectedAisleData.type as ArrowsAisle;
|
|
return (
|
|
<>
|
|
<InputWithDropDown
|
|
label="Arrow Length"
|
|
value={`${arrowsType.aisleLength}`}
|
|
min={0.1}
|
|
step={0.1}
|
|
max={2}
|
|
onChange={handleAisleLengthChange}
|
|
/>
|
|
<InputWithDropDown
|
|
label="Gap Length"
|
|
value={`${arrowsType.gapLength}`}
|
|
min={0.1}
|
|
step={0.1}
|
|
max={2}
|
|
onChange={handleGapLengthChange}
|
|
/>
|
|
</>
|
|
);
|
|
case 'junction-aisle':
|
|
case 'arc-aisle':
|
|
const flippedType = selectedAisleData.type as ArcAisle | JunctionAisle;
|
|
return (
|
|
<InputToggle
|
|
inputKey="Flip Aisle"
|
|
label="Flip Aisle"
|
|
value={flippedType.isFlipped || false}
|
|
onClick={handleIsFlippedChange}
|
|
/>
|
|
);
|
|
default:
|
|
return null;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="aisle-properties-container">
|
|
<div className="header">Properties</div>
|
|
|
|
{/* Basic Properties */}
|
|
<section>
|
|
{selectedAisleData.type.aisleType !== 'dotted-aisle' &&
|
|
<InputWithDropDown
|
|
label="Aisle Width"
|
|
value={`${selectedAisleData.type.aisleWidth || 0.5}`}
|
|
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 ${selectedAisleData.type.aisleType === val.type ? "selected" : ""}`}
|
|
title={val.name}
|
|
onClick={() => handleAisleTypeChange(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 ${selectedAisleData.type.aisleColor === val.id ? "selected" : ""}`}
|
|
onClick={() => handleColorChange(val.id)}
|
|
aria-pressed={selectedAisleData.type.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 SelectedAisleProperties; |