changed marketplace assets
This commit is contained in:
@@ -9,6 +9,8 @@ import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
|
||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import { getAssetEventType } from '../../../../services/simulation/getAssetEventType';
|
||||
import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||
|
||||
async function addAssetModel(
|
||||
raycaster: THREE.Raycaster,
|
||||
@@ -58,6 +60,7 @@ async function addAssetModel(
|
||||
if (intersectPoint.y < 0) {
|
||||
intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z);
|
||||
}
|
||||
console.log('selectedItem: ', selectedItem);
|
||||
const cachedModel = THREE.Cache.get(selectedItem.id);
|
||||
if (cachedModel) {
|
||||
// console.log(`[Cache] Fetching ${selectedItem.name}`);
|
||||
@@ -136,51 +139,88 @@ async function handleModelLoad(
|
||||
modelname: selectedItem.name,
|
||||
modelfileID: selectedItem.id,
|
||||
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||
isLocked: false,
|
||||
isVisible: true
|
||||
};
|
||||
|
||||
setFloorItems((prevItems) => {
|
||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||
return updatedItems;
|
||||
});
|
||||
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||
|
||||
//REST
|
||||
getAssetEventType(selectedItem.id, organization).then(async (res) => {
|
||||
console.log('res: ', res);
|
||||
|
||||
// await setFloorItemApi(
|
||||
// organization,
|
||||
// newFloorItem.modeluuid,
|
||||
// newFloorItem.modelname,
|
||||
// newFloorItem.position,
|
||||
// { "x": model.rotation.x, "y": model.rotation.y, "z": model.rotation.z },
|
||||
// newFloorItem.modelfileID!,
|
||||
// false,
|
||||
// true,
|
||||
// );
|
||||
if (res.type === "Conveyor") {
|
||||
const pointUUIDs = res.points.map(() => THREE.MathUtils.generateUUID());
|
||||
|
||||
//SOCKET
|
||||
const eventData: Extract<Types.FloorItemType['eventData'], { type: 'Conveyor' }> = {
|
||||
type: 'Conveyor',
|
||||
points: res.points.map((point: any, index: number) => ({
|
||||
uuid: pointUUIDs[index],
|
||||
position: point.position as [number, number, number],
|
||||
rotation: point.rotation as [number, number, number],
|
||||
actions: [{
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
name: 'Action 1',
|
||||
type: 'Inherit',
|
||||
material: 'Inherit',
|
||||
delay: 'Inherit',
|
||||
spawnInterval: 'Inherit',
|
||||
isUsed: false
|
||||
}],
|
||||
triggers: [],
|
||||
connections: {
|
||||
source: { pathUUID: model.uuid, pointUUID: pointUUIDs[index] },
|
||||
targets: []
|
||||
}
|
||||
})),
|
||||
speed: 'Inherit'
|
||||
};
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
modeluuid: newFloorItem.modeluuid,
|
||||
modelname: newFloorItem.modelname,
|
||||
modelfileID: newFloorItem.modelfileID,
|
||||
position: newFloorItem.position,
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
};
|
||||
console.log('eventData: ', eventData);
|
||||
newFloorItem.eventData = eventData;
|
||||
}
|
||||
|
||||
socket.emit("v1:FloorItems:set", data);
|
||||
setFloorItems((prevItems) => {
|
||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||
return updatedItems;
|
||||
});
|
||||
|
||||
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
|
||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
|
||||
// API
|
||||
|
||||
// await setFloorItemApi(
|
||||
// organization,
|
||||
// newFloorItem.modeluuid,
|
||||
// newFloorItem.modelname,
|
||||
// newFloorItem.modelfileID,
|
||||
// newFloorItem.position,
|
||||
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||
// false,
|
||||
// true,
|
||||
// newFloorItem.eventData
|
||||
// );
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
modeluuid: newFloorItem.modeluuid,
|
||||
modelname: newFloorItem.modelname,
|
||||
modelfileID: newFloorItem.modelfileID,
|
||||
position: newFloorItem.position,
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
eventData: newFloorItem.eventData,
|
||||
socketId: socket.id
|
||||
};
|
||||
|
||||
socket.emit("v2:model-asset:add", data);
|
||||
|
||||
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
|
||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
|
||||
});
|
||||
}
|
||||
|
||||
export default addAssetModel;
|
||||
|
||||
@@ -1,90 +1,143 @@
|
||||
import { useEffect, useState } from "react"
|
||||
import { useEffect, useState } from "react";
|
||||
import { getLines } from "../../../../services/factoryBuilder/lines/getLinesApi";
|
||||
import * as THREE from "three";
|
||||
import { useActiveLayer, useDeletedLines, useNewLines, useToggleView } from "../../../../store/store";
|
||||
import {
|
||||
useActiveLayer,
|
||||
useDeletedLines,
|
||||
useNewLines,
|
||||
useToggleView,
|
||||
} from "../../../../store/store";
|
||||
import objectLinesToArray from "./lineConvertions/objectLinesToArray";
|
||||
import { Html } from "@react-three/drei";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
const DistanceText = () => {
|
||||
const [lines, setLines] = useState<{ distance: string; position: THREE.Vector3; userData: Types.Line; layer: string }[]>([]);
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { toggleView } = useToggleView();
|
||||
const { newLines, setNewLines } = useNewLines();
|
||||
const { deletedLines, setDeletedLines } = useDeletedLines();
|
||||
const [lines, setLines] = useState<
|
||||
{
|
||||
distance: string;
|
||||
position: THREE.Vector3;
|
||||
userData: Types.Line;
|
||||
layer: string;
|
||||
}[]
|
||||
>([]);
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { toggleView } = useToggleView();
|
||||
const { newLines, setNewLines } = useNewLines();
|
||||
const { deletedLines, setDeletedLines } = useDeletedLines();
|
||||
|
||||
useEffect(() => {
|
||||
const email = localStorage.getItem('email')
|
||||
if (!email) return;
|
||||
const organization = (email.split("@")[1]).split(".")[0];
|
||||
useEffect(() => {
|
||||
const email = localStorage.getItem("email");
|
||||
if (!email) return;
|
||||
const organization = email.split("@")[1].split(".")[0];
|
||||
|
||||
getLines(organization).then((data) => {
|
||||
data = objectLinesToArray(data);
|
||||
getLines(organization).then((data) => {
|
||||
data = objectLinesToArray(data);
|
||||
|
||||
const lines = data.filter((line: Types.Line) => line[0][2] === activeLayer)
|
||||
.map((line: Types.Line) => {
|
||||
const point1 = new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z);
|
||||
const point2 = new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z);
|
||||
const distance = point1.distanceTo(point2);
|
||||
const midpoint = new THREE.Vector3().addVectors(point1, point2).divideScalar(2);
|
||||
return {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer,
|
||||
};
|
||||
});
|
||||
setLines(lines)
|
||||
})
|
||||
}, [activeLayer])
|
||||
const lines = data
|
||||
.filter((line: Types.Line) => line[0][2] === activeLayer)
|
||||
.map((line: Types.Line) => {
|
||||
const point1 = new THREE.Vector3(
|
||||
line[0][0].x,
|
||||
line[0][0].y,
|
||||
line[0][0].z
|
||||
);
|
||||
const point2 = new THREE.Vector3(
|
||||
line[1][0].x,
|
||||
line[1][0].y,
|
||||
line[1][0].z
|
||||
);
|
||||
const distance = point1.distanceTo(point2);
|
||||
const midpoint = new THREE.Vector3()
|
||||
.addVectors(point1, point2)
|
||||
.divideScalar(2);
|
||||
return {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer,
|
||||
};
|
||||
});
|
||||
setLines(lines);
|
||||
});
|
||||
}, [activeLayer]);
|
||||
|
||||
useEffect(() => {
|
||||
if (newLines.length > 0) {
|
||||
if (newLines[0][0][2] !== activeLayer) return;
|
||||
const newLinesData = newLines.map((line: Types.Line) => {
|
||||
const point1 = new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z);
|
||||
const point2 = new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z);
|
||||
const distance = point1.distanceTo(point2);
|
||||
const midpoint = new THREE.Vector3().addVectors(point1, point2).divideScalar(2);
|
||||
useEffect(() => {
|
||||
if (newLines.length > 0) {
|
||||
if (newLines[0][0][2] !== activeLayer) return;
|
||||
const newLinesData = newLines.map((line: Types.Line) => {
|
||||
const point1 = new THREE.Vector3(
|
||||
line[0][0].x,
|
||||
line[0][0].y,
|
||||
line[0][0].z
|
||||
);
|
||||
const point2 = new THREE.Vector3(
|
||||
line[1][0].x,
|
||||
line[1][0].y,
|
||||
line[1][0].z
|
||||
);
|
||||
const distance = point1.distanceTo(point2);
|
||||
const midpoint = new THREE.Vector3()
|
||||
.addVectors(point1, point2)
|
||||
.divideScalar(2);
|
||||
|
||||
return {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer,
|
||||
};
|
||||
});
|
||||
setLines((prevLines) => [...prevLines, ...newLinesData]);
|
||||
setNewLines([]);
|
||||
}
|
||||
}, [newLines, activeLayer]);
|
||||
return {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer,
|
||||
};
|
||||
});
|
||||
setLines((prevLines) => [...prevLines, ...newLinesData]);
|
||||
setNewLines([]);
|
||||
}
|
||||
}, [newLines, activeLayer]);
|
||||
|
||||
useEffect(() => {
|
||||
if ((deletedLines as Types.Lines).length > 0) {
|
||||
setLines((prevLines) =>
|
||||
prevLines.filter(
|
||||
(line) =>
|
||||
!deletedLines.some(
|
||||
(deletedLine: any) =>
|
||||
deletedLine[0][1] === line.userData[0][1] &&
|
||||
deletedLine[1][1] === line.userData[1][1]
|
||||
)
|
||||
)
|
||||
);
|
||||
setDeletedLines([]);
|
||||
}
|
||||
}, [deletedLines]);
|
||||
|
||||
useEffect(() => {
|
||||
if ((deletedLines as Types.Lines).length > 0) {
|
||||
setLines((prevLines) =>
|
||||
prevLines.filter(
|
||||
(line) => !deletedLines.some((deletedLine: any) => deletedLine[0][1] === line.userData[0][1] && deletedLine[1][1] === line.userData[1][1])
|
||||
)
|
||||
);
|
||||
setDeletedLines([]);
|
||||
}
|
||||
}, [deletedLines]);
|
||||
return (
|
||||
<>
|
||||
{toggleView && (
|
||||
<group name="Distance_Text">
|
||||
{lines.map((text) => (
|
||||
<Html
|
||||
// data
|
||||
key={`${text.userData[0][1]}_${text.userData[1][1]}`}
|
||||
userData={text.userData}
|
||||
position={[text.position.x, 1, text.position.z]}
|
||||
// class
|
||||
wrapperClass="distance-text-wrapper"
|
||||
className="distance-text"
|
||||
// other
|
||||
zIndexRange={[100, 0]}
|
||||
prepend
|
||||
sprite
|
||||
>
|
||||
<div
|
||||
key={`${text.userData[0][1]}_${text.userData[1][1]}`}
|
||||
className={`distance line-${text.userData[0][1]}_${text.userData[1][1]}_${text.layer}`}
|
||||
>
|
||||
{text.distance} m
|
||||
</div>
|
||||
</Html>
|
||||
))}
|
||||
</group>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{toggleView && (
|
||||
<group name='Distance_Text'>
|
||||
{lines.map((text) => (
|
||||
<Html key={`${text.userData[0][1]}_${text.userData[1][1]}`} transform sprite userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }} >
|
||||
<div key={`${text.userData[0][1]}_${text.userData[1][1]}`} className={`Distance line-${text.userData[0][1]}_${text.userData[1][1]}_${text.layer}`} >{text.distance} m</div>
|
||||
</Html>
|
||||
))}
|
||||
</group>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
export default DistanceText;
|
||||
export default DistanceText;
|
||||
|
||||
@@ -60,6 +60,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
|
||||
};
|
||||
|
||||
getFloorItems(organization).then((data) => {
|
||||
console.log('data: ', data);
|
||||
const uniqueItems = (data as Types.FloorItems).filter((item, index, self) =>
|
||||
index === self.findIndex((t) => t.modelfileID === item.modelfileID)
|
||||
);
|
||||
@@ -305,7 +306,10 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
|
||||
};
|
||||
}, [deleteModels, transformMode, controls, selectedItem, state.camera, state.pointer, activeTool, activeModule]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
console.log('floorItems: ', floorItems);
|
||||
}, [floorItems])
|
||||
|
||||
useFrame(() => {
|
||||
if (controls)
|
||||
|
||||
@@ -434,9 +434,9 @@ const ZoneGroup: React.FC = () => {
|
||||
const point2 = new THREE.Vector3(nextPoint[0], nextPoint[1], nextPoint[2]);
|
||||
|
||||
const planeWidth = point1.distanceTo(point2);
|
||||
const planeHeight = CONSTANTS.wallConfig.height;
|
||||
const planeHeight = CONSTANTS.zoneConfig.height;
|
||||
|
||||
const midpoint = new THREE.Vector3((point1.x + point2.x) / 2, (CONSTANTS.wallConfig.height / 2) + ((zone.layer - 1) * CONSTANTS.wallConfig.height), (point1.z + point2.z) / 2);
|
||||
const midpoint = new THREE.Vector3((point1.x + point2.x) / 2, (CONSTANTS.zoneConfig.height / 2) + ((zone.layer - 1) * CONSTANTS.zoneConfig.height), (point1.z + point2.z) / 2);
|
||||
|
||||
const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x);
|
||||
|
||||
|
||||
@@ -81,7 +81,8 @@ export default function SocketResponses({
|
||||
// console.log('data: ', data);
|
||||
})
|
||||
|
||||
socket.on('FloorItemsUpdateResponse', async (data: any) => {
|
||||
socket.on('model-asset:response:updates', async (data: any) => {
|
||||
console.log('data: ', data);
|
||||
if (socket.id === data.socketId) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { getInitials } from "./functions/getInitials";
|
||||
import { getAvatarColor } from "./functions/getAvatarColor";
|
||||
|
||||
interface AvatarProps {
|
||||
name: string; // Name can be a full name or initials
|
||||
size?: number;
|
||||
index?: number;
|
||||
textColor?: string;
|
||||
}
|
||||
|
||||
const CustomAvatar: React.FC<AvatarProps> = ({
|
||||
name,
|
||||
size = 100,
|
||||
index = 0,
|
||||
textColor = "#ffffff",
|
||||
}) => {
|
||||
const [imageSrc, setImageSrc] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = document.createElement("canvas"); // Create an offscreen canvas
|
||||
canvas.width = size;
|
||||
canvas.height = size;
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (ctx) {
|
||||
const initials = getInitials(name); // Convert name to initials if needed
|
||||
|
||||
// Draw background
|
||||
ctx.fillStyle = getAvatarColor(index);
|
||||
ctx.fillRect(0, 0, size, size);
|
||||
|
||||
// Draw initials
|
||||
ctx.fillStyle = textColor;
|
||||
ctx.font = `bold ${size / 2}px Arial`;
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillText(initials, size / 2, size / 2);
|
||||
|
||||
// Generate image source
|
||||
const dataURL = canvas.toDataURL("image/png");
|
||||
setImageSrc(dataURL);
|
||||
}
|
||||
}, [name, size, textColor]);
|
||||
|
||||
if (!imageSrc) {
|
||||
return null; // Return null while the image is being generated
|
||||
}
|
||||
|
||||
return (
|
||||
<img
|
||||
className="user-image"
|
||||
src={imageSrc}
|
||||
alt="User Avatar"
|
||||
style={{ width: "100%", height: "100%" }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomAvatar;
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { getInitials } from "./functions/getInitials";
|
||||
import { getAvatarColor } from "./functions/getAvatarColor";
|
||||
|
||||
interface AvatarProps {
|
||||
name: string; // Name can be a full name or initials
|
||||
size?: number;
|
||||
index?: number;
|
||||
textColor?: string;
|
||||
}
|
||||
|
||||
const CustomAvatar: React.FC<AvatarProps> = ({
|
||||
name,
|
||||
size = 100,
|
||||
index = 0,
|
||||
textColor = "#ffffff",
|
||||
}) => {
|
||||
const [imageSrc, setImageSrc] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = document.createElement("canvas"); // Create an offscreen canvas
|
||||
canvas.width = size;
|
||||
canvas.height = size;
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (ctx) {
|
||||
const initials = getInitials(name); // Convert name to initials if needed
|
||||
|
||||
// Draw background
|
||||
ctx.fillStyle = getAvatarColor(index);
|
||||
ctx.fillRect(0, 0, size, size);
|
||||
|
||||
// Draw initials
|
||||
ctx.fillStyle = textColor;
|
||||
ctx.font = `bold ${size / 2}px Arial`;
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillText(initials, size / 2, size / 2);
|
||||
|
||||
// Generate image source
|
||||
const dataURL = canvas.toDataURL("image/png");
|
||||
setImageSrc(dataURL);
|
||||
}
|
||||
}, [name, size, textColor]);
|
||||
|
||||
if (!imageSrc) {
|
||||
return null; // Return null while the image is being generated
|
||||
}
|
||||
|
||||
return (
|
||||
<img
|
||||
className="user-image"
|
||||
src={imageSrc}
|
||||
alt="User Avatar"
|
||||
style={{ width: "100%", height: "100%" }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomAvatar;
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
const avatarColors: string[] = [
|
||||
"#FF5733", // Red Orange
|
||||
"#48ac2a", // Leaf Green
|
||||
"#0050eb", // Royal Blue
|
||||
"#FF33A1", // Hot Pink
|
||||
"#FF8C33", // Deep Orange
|
||||
"#8C33FF", // Violet
|
||||
"#FF3333", // Bright Red
|
||||
"#43c06d", // Emerald Green
|
||||
"#A133FF", // Amethyst Purple
|
||||
"#C70039", // Crimson
|
||||
"#900C3F", // Maroon
|
||||
"#581845", // Plum
|
||||
"#3498DB", // Sky Blue
|
||||
"#2ECC71", // Green Mint
|
||||
"#E74C3C", // Tomato Red
|
||||
"#00adff", // Azure
|
||||
"#DBAD05", // Amber Yellow
|
||||
"#FF5733", // Red Orange
|
||||
"#FF33A1", // Hot Pink
|
||||
"#900C3F", // Maroon
|
||||
];
|
||||
|
||||
export function getAvatarColor(index: number): string {
|
||||
return avatarColors[index % avatarColors.length];
|
||||
}
|
||||
const avatarColors: string[] = [
|
||||
"#FF5733", // Red Orange
|
||||
"#48ac2a", // Leaf Green
|
||||
"#0050eb", // Royal Blue
|
||||
"#FF33A1", // Hot Pink
|
||||
"#FF8C33", // Deep Orange
|
||||
"#8C33FF", // Violet
|
||||
"#FF3333", // Bright Red
|
||||
"#43c06d", // Emerald Green
|
||||
"#A133FF", // Amethyst Purple
|
||||
"#C70039", // Crimson
|
||||
"#900C3F", // Maroon
|
||||
"#581845", // Plum
|
||||
"#3498DB", // Sky Blue
|
||||
"#2ECC71", // Green Mint
|
||||
"#E74C3C", // Tomato Red
|
||||
"#00adff", // Azure
|
||||
"#DBAD05", // Amber Yellow
|
||||
"#FF5733", // Red Orange
|
||||
"#FF33A1", // Hot Pink
|
||||
"#900C3F", // Maroon
|
||||
];
|
||||
|
||||
export function getAvatarColor(index: number): string {
|
||||
return avatarColors[index % avatarColors.length];
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export const getInitials = (fullName: string): string => {
|
||||
// Extract initials from the name
|
||||
const words = fullName.split(" ");
|
||||
const initials = words
|
||||
.map((word) => word[0])
|
||||
.slice(0, 2)
|
||||
.join("")
|
||||
.toUpperCase();
|
||||
return initials;
|
||||
export const getInitials = (fullName: string): string => {
|
||||
// Extract initials from the name
|
||||
const words = fullName.split(" ");
|
||||
const initials = words
|
||||
.map((word) => word[0])
|
||||
.slice(0, 2)
|
||||
.join("")
|
||||
.toUpperCase();
|
||||
return initials;
|
||||
};
|
||||
@@ -42,6 +42,8 @@ const SelectionControls: React.FC = () => {
|
||||
itemsGroupRef.current = itemsGroup;
|
||||
|
||||
let isSelecting = false;
|
||||
let isRightClick = false;
|
||||
let rightClickMoved = false;
|
||||
let isCtrlSelecting = false;
|
||||
|
||||
const helper = new SelectionHelper(gl);
|
||||
@@ -52,16 +54,23 @@ const SelectionControls: React.FC = () => {
|
||||
}
|
||||
|
||||
const onPointerDown = (event: PointerEvent) => {
|
||||
if (event.button !== 0) return
|
||||
isSelecting = false;
|
||||
isCtrlSelecting = event.ctrlKey;
|
||||
if (event.ctrlKey && duplicatedObjects.length === 0) {
|
||||
if (controls) (controls as any).enabled = false;
|
||||
selectionBox.startPoint.set(pointer.x, pointer.y, 0);
|
||||
if (event.button === 2) {
|
||||
isRightClick = true;
|
||||
rightClickMoved = false;
|
||||
} else if (event.button === 0) {
|
||||
isSelecting = false;
|
||||
isCtrlSelecting = event.ctrlKey;
|
||||
if (event.ctrlKey && duplicatedObjects.length === 0) {
|
||||
if (controls) (controls as any).enabled = false;
|
||||
selectionBox.startPoint.set(pointer.x, pointer.y, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onPointerMove = (event: PointerEvent) => {
|
||||
if (isRightClick) {
|
||||
rightClickMoved = true;
|
||||
}
|
||||
isSelecting = true;
|
||||
if (helper.isDown && event.ctrlKey && duplicatedObjects.length === 0 && isCtrlSelecting) {
|
||||
selectionBox.endPoint.set(pointer.x, pointer.y, 0);
|
||||
@@ -69,6 +78,14 @@ const SelectionControls: React.FC = () => {
|
||||
};
|
||||
|
||||
const onPointerUp = (event: PointerEvent) => {
|
||||
if (event.button === 2) {
|
||||
isRightClick = false;
|
||||
if (!rightClickMoved) {
|
||||
clearSelection();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSelecting && isCtrlSelecting) {
|
||||
isCtrlSelecting = false;
|
||||
isSelecting = false;
|
||||
@@ -94,10 +111,13 @@ const SelectionControls: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const onContextMenu = (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
clearSelection();
|
||||
}
|
||||
if (!rightClickMoved) {
|
||||
clearSelection();
|
||||
}
|
||||
};
|
||||
|
||||
if (!toggleView && activeModule === "builder") {
|
||||
helper.enabled = true;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as THREE from 'three';
|
||||
import { useToggleView } from '../../../store/store';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
|
||||
const Ground = ({ grid, plane }: any) => {
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { toggleView } = useToggleView();
|
||||
const savedTheme: string | null = localStorage.getItem('theme');
|
||||
|
||||
return (
|
||||
|
||||
@@ -19,4 +19,4 @@ const Ground = ({ grid, plane }: any) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default Ground;
|
||||
export default Ground;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import { useMemo } from "react";
|
||||
import { Canvas } from "@react-three/fiber";
|
||||
import { Environment, KeyboardControls } from "@react-three/drei";
|
||||
|
||||
import World from "./world/world";
|
||||
import Controls from "./controls/controls";
|
||||
import TransformControl from "./controls/transformControls";
|
||||
import PostProcessing from "./postProcessing/postProcessing"
|
||||
import PostProcessing from "./postProcessing/postProcessing";
|
||||
import Sun from "./environment/sky";
|
||||
import CamModelsGroup from "../collaboration/collabCams";
|
||||
import Shadows from "./environment/shadow";
|
||||
@@ -15,33 +15,31 @@ import background from "../../assets/textures/hdr/mudroadpuresky2k.hdr";
|
||||
import SelectionControls from "./controls/selection/selectionControls";
|
||||
import MeasurementTool from "./tools/measurementTool";
|
||||
import Simulation from "../simulation/simulation";
|
||||
import DroppedObjects from "../../components/ui/componets/DroppedFloatingWidgets";
|
||||
|
||||
// import Simulation from "./simulationtemp/simulation";
|
||||
import ZoneCentreTarget from "../../components/ui/componets/zoneCameraTarget";
|
||||
import ProductionCapacity from "../../components/layout/3D-cards/cards/ProductionCapacity";
|
||||
import Dropped3dWidgets from "../../components/ui/componets/Dropped3dWidget";
|
||||
import { useWidgetSubOption } from "../../store/store";
|
||||
|
||||
export default function Scene() {
|
||||
|
||||
const map = useMemo(() => [
|
||||
{ name: "forward", keys: ["ArrowUp", "w", "W"] },
|
||||
{ name: "backward", keys: ["ArrowDown", "s", "S"] },
|
||||
{ name: "left", keys: ["ArrowLeft", "a", "A"] },
|
||||
{ name: "right", keys: ["ArrowRight", "d", "D"] },
|
||||
], [])
|
||||
const map = useMemo(
|
||||
() => [
|
||||
{ name: "forward", keys: ["ArrowUp", "w", "W"] },
|
||||
{ name: "backward", keys: ["ArrowDown", "s", "S"] },
|
||||
{ name: "left", keys: ["ArrowLeft", "a", "A"] },
|
||||
{ name: "right", keys: ["ArrowRight", "d", "D"] },
|
||||
],
|
||||
[]
|
||||
);
|
||||
const savedTheme: string | null = localStorage.getItem("theme");
|
||||
|
||||
return (
|
||||
<KeyboardControls map={map}>
|
||||
<Canvas
|
||||
// style={{ width: "100vw", height: "100vh" }}
|
||||
eventPrefix="client"
|
||||
gl={{ powerPreference: "high-performance", antialias: true }}
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
|
||||
>
|
||||
<Dropped3dWidgets />
|
||||
<Controls />
|
||||
@@ -52,7 +50,7 @@ export default function Scene() {
|
||||
<ZoneCentreTarget />
|
||||
<Simulation />
|
||||
<PostProcessing />
|
||||
<Sun />
|
||||
{savedTheme !== "dark" && <Sun />}
|
||||
<Shadows />
|
||||
<CamModelsGroup />
|
||||
<MqttEvents />
|
||||
|
||||
@@ -364,7 +364,7 @@ export default function World() {
|
||||
anglesnappedPoint={anglesnappedPoint}
|
||||
/>
|
||||
|
||||
<DrieHtmlTemp itemsGroup={itemsGroup} />
|
||||
{/* <DrieHtmlTemp itemsGroup={itemsGroup} /> */}
|
||||
|
||||
<Agv lines={lines} plane={plane} />
|
||||
</>
|
||||
|
||||
@@ -67,7 +67,7 @@ function Behaviour() {
|
||||
point: {
|
||||
uuid: pointUUID,
|
||||
position: [pointPosition.x, pointPosition.y, pointPosition.z],
|
||||
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: '', hitCount: 1, end: '', buffer: 0 },
|
||||
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
||||
connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
||||
speed: 2,
|
||||
},
|
||||
|
||||
@@ -96,24 +96,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||
};
|
||||
const existingTargets = path.point.connections.targets || [];
|
||||
|
||||
// Check if we're trying to add a connection to a Conveyor
|
||||
// Check if target is a Conveyor
|
||||
const toPath = simulationPaths.find(p => p.modeluuid === toPathUUID);
|
||||
const isConnectingToConveyor = toPath?.type === 'Conveyor';
|
||||
|
||||
// Count existing connections
|
||||
if (existingTargets.length >= 2) {
|
||||
console.log("Vehicle can have maximum 2 connections");
|
||||
if (toPath?.type !== 'Conveyor') {
|
||||
console.log("Vehicle can only connect to Conveyors");
|
||||
return path;
|
||||
}
|
||||
|
||||
// Check if we already have a Conveyor connection and trying to add another
|
||||
const hasConveyorConnection = existingTargets.some(target => {
|
||||
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
|
||||
return targetPath?.type === 'Conveyor';
|
||||
});
|
||||
|
||||
if (hasConveyorConnection && isConnectingToConveyor) {
|
||||
console.log("Vehicle can only have one connection to a Conveyor");
|
||||
// Check if already has a connection
|
||||
if (existingTargets.length >= 1) {
|
||||
console.log("Vehicle can have only one connection");
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -141,24 +133,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||
};
|
||||
const existingTargets = path.point.connections.targets || [];
|
||||
|
||||
// Check if we're receiving a connection from a Conveyor
|
||||
// Check if source is a Conveyor
|
||||
const fromPath = simulationPaths.find(p => p.modeluuid === fromPathUUID);
|
||||
const isConnectingFromConveyor = fromPath?.type === 'Conveyor';
|
||||
|
||||
// Count existing connections
|
||||
if (existingTargets.length >= 2) {
|
||||
console.log("Vehicle can have maximum 2 connections");
|
||||
if (fromPath?.type !== 'Conveyor') {
|
||||
console.log("Vehicle can only connect to Conveyors");
|
||||
return path;
|
||||
}
|
||||
|
||||
// Check if we already have a Conveyor connection and trying to add another
|
||||
const hasConveyorConnection = existingTargets.some(target => {
|
||||
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
|
||||
return targetPath?.type === 'Conveyor';
|
||||
});
|
||||
|
||||
if (hasConveyorConnection && isConnectingFromConveyor) {
|
||||
console.log("Vehicle can only have one connection to a Conveyor");
|
||||
// Check if already has a connection
|
||||
if (existingTargets.length >= 1) {
|
||||
console.log("Vehicle can have only one connection");
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -212,6 +196,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onContextMenu = (evt: MouseEvent) => {
|
||||
evt.preventDefault();
|
||||
if (drag || evt.button === 0) return;
|
||||
@@ -282,7 +267,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||
return;
|
||||
}
|
||||
|
||||
// For Vehicles, skip the "already connected" check since they can have multiple connections
|
||||
// For Vehicles, check if they're already connected to anything
|
||||
if (intersected.userData.path.type === 'Vehicle') {
|
||||
const vehicleConnections = intersected.userData.path.point.connections.targets.length;
|
||||
if (vehicleConnections >= 1) {
|
||||
console.log("Vehicle can only have one connection");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// For non-Vehicle paths, check if already connected
|
||||
if (intersected.userData.path.type !== 'Vehicle') {
|
||||
const isAlreadyConnected = simulationPaths.some(path => {
|
||||
if (path.type === 'Conveyor') {
|
||||
@@ -300,48 +294,14 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||
}
|
||||
}
|
||||
|
||||
// Check vehicle connection limits
|
||||
const checkVehicleConnections = (pathUUID: string) => {
|
||||
const path = simulationPaths.find(p => p.modeluuid === pathUUID);
|
||||
if (path?.type === 'Vehicle') {
|
||||
return path.point.connections.targets.length >= 2;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (firstSelected) {
|
||||
// Check if either selected point is from a Vehicle with max connections
|
||||
if (checkVehicleConnections(firstSelected.pathUUID) ||
|
||||
checkVehicleConnections(pathUUID)) {
|
||||
console.log("Vehicle already has maximum connections");
|
||||
// Check if trying to connect Vehicle to non-Conveyor
|
||||
if ((firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') ||
|
||||
(secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor')) {
|
||||
console.log("Vehicle can only connect to Conveyors");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we're trying to add a second Conveyor connection to a Vehicle
|
||||
if (firstPath?.type === 'Vehicle' && secondPath?.type === 'Conveyor') {
|
||||
const hasConveyorConnection = firstPath.point.connections.targets.some(target => {
|
||||
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
|
||||
return targetPath?.type === 'Conveyor';
|
||||
});
|
||||
|
||||
if (hasConveyorConnection) {
|
||||
console.log("Vehicle can only have one connection to a Conveyor");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (secondPath?.type === 'Vehicle' && firstPath?.type === 'Conveyor') {
|
||||
const hasConveyorConnection = secondPath.point.connections.targets.some(target => {
|
||||
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
|
||||
return targetPath?.type === 'Conveyor';
|
||||
});
|
||||
|
||||
if (hasConveyorConnection) {
|
||||
console.log("Vehicle can only have one connection to a Conveyor");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent same-path connections
|
||||
if (firstSelected.pathUUID === pathUUID) {
|
||||
console.log("Cannot connect spheres on the same path.");
|
||||
@@ -478,28 +438,19 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
||||
return false;
|
||||
});
|
||||
|
||||
// Check vehicle connection limits
|
||||
// Check vehicle connection rules
|
||||
const isVehicleAtMaxConnections = pathData.type === 'Vehicle' &&
|
||||
pathData.point.connections.targets.length >= 2;
|
||||
|
||||
const isVehicleConveyorConflict =
|
||||
(firstPath?.type === 'Vehicle' && secondPath?.type === 'Conveyor' &&
|
||||
firstPath.point.connections.targets.some(t => {
|
||||
const targetPath = simulationPaths.find(p => p.modeluuid === t.pathUUID);
|
||||
return targetPath?.type === 'Conveyor';
|
||||
})) ||
|
||||
(secondPath?.type === 'Vehicle' && firstPath?.type === 'Conveyor' &&
|
||||
secondPath.point.connections.targets.some(t => {
|
||||
const targetPath = simulationPaths.find(p => p.modeluuid === t.pathUUID);
|
||||
return targetPath?.type === 'Conveyor';
|
||||
}));
|
||||
pathData.point.connections.targets.length >= 1;
|
||||
const isVehicleConnectingToNonConveyor =
|
||||
(firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') ||
|
||||
(secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor');
|
||||
|
||||
if (
|
||||
!isDuplicateConnection &&
|
||||
!isVehicleToVehicle &&
|
||||
!isNonVehicleAlreadyConnected &&
|
||||
!isVehicleAtMaxConnections &&
|
||||
!isVehicleConveyorConflict &&
|
||||
!isVehicleConnectingToNonConveyor &&
|
||||
firstSelected.sphereUUID !== sphereUUID &&
|
||||
firstSelected.pathUUID !== pathUUID &&
|
||||
(firstSelected.isCorner || isConnectable)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import { useRef, useState, useEffect } from 'react';
|
||||
import { useRef, useState, useEffect, useMemo } from 'react';
|
||||
import { Sphere, TransformControls } from '@react-three/drei';
|
||||
import { useIsConnecting, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store';
|
||||
import { useEditingPoint, useEyeDropMode, useIsConnecting, usePreviewPosition, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store';
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import { useSubModuleStore } from '../../../store/useModuleStore';
|
||||
|
||||
@@ -10,13 +10,18 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||
const { renderDistance } = useRenderDistance();
|
||||
const { setSubModule } = useSubModuleStore();
|
||||
const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere();
|
||||
const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
|
||||
const { editingPoint, setEditingPoint } = useEditingPoint();
|
||||
const { previewPosition, setPreviewPosition } = usePreviewPosition();
|
||||
const { raycaster, camera, pointer, gl } = useThree();
|
||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||
const { setSelectedPath } = useSelectedPath();
|
||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||
const { isConnecting } = useIsConnecting();
|
||||
const { camera } = useThree();
|
||||
|
||||
|
||||
const groupRefs = useRef<{ [key: string]: THREE.Group }>({});
|
||||
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
||||
const isMovingRef = useRef(false);
|
||||
const transformRef = useRef<any>(null);
|
||||
const [transformMode, setTransformMode] = useState<'translate' | 'rotate' | null>(null);
|
||||
|
||||
@@ -77,6 +82,83 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
useFrame(() => {
|
||||
if (eyeDropMode) {
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersectionPoint = new THREE.Vector3();
|
||||
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||
|
||||
if (point) {
|
||||
setPreviewPosition({ x: point.x, y: point.z });
|
||||
}
|
||||
} else {
|
||||
setPreviewPosition(null);
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!camera) return;
|
||||
const canvasElement = gl.domElement;
|
||||
canvasElement.tabIndex = 0;
|
||||
|
||||
|
||||
const onPointerDown = () => {
|
||||
isMovingRef.current = false;
|
||||
};
|
||||
|
||||
const onPointerMove = () => {
|
||||
isMovingRef.current = true;
|
||||
};
|
||||
|
||||
const onPointerUp = (event: PointerEvent) => {
|
||||
if (!isMovingRef.current && eyeDropMode && event.button === 0 && previewPosition) {
|
||||
event.preventDefault();
|
||||
if (editingPoint) {
|
||||
handlePointUpdate(editingPoint, previewPosition.x, previewPosition.y);
|
||||
setEditingPoint(null);
|
||||
setEyeDropMode(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (eyeDropMode) {
|
||||
canvasElement.addEventListener("pointerdown", onPointerDown);
|
||||
canvasElement.addEventListener("pointermove", onPointerMove);
|
||||
canvasElement.addEventListener("pointerup", onPointerUp);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("pointerdown", onPointerDown);
|
||||
canvasElement.removeEventListener("pointermove", onPointerMove);
|
||||
canvasElement.removeEventListener("pointerup", onPointerUp);
|
||||
};
|
||||
}, [eyeDropMode, editingPoint, previewPosition]);
|
||||
|
||||
const handlePointUpdate = (pointType: 'start' | 'end', x: number, z: number) => {
|
||||
if (!selectedActionSphere?.point?.uuid) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => {
|
||||
if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) {
|
||||
return {
|
||||
...path,
|
||||
point: {
|
||||
...path.point,
|
||||
actions: {
|
||||
...path.point.actions,
|
||||
[pointType]: {
|
||||
...path.point.actions[pointType],
|
||||
x: x,
|
||||
y: z
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return path;
|
||||
});
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
return (
|
||||
<group name='simulation-simulationPaths-group' ref={pathsGroupRef}>
|
||||
@@ -92,7 +174,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||
position={path.assetPosition}
|
||||
rotation={path.assetRotation}
|
||||
onClick={(e) => {
|
||||
if (isConnecting) return;
|
||||
if (isConnecting || eyeDropMode) return;
|
||||
e.stopPropagation();
|
||||
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
||||
setSelectedActionSphere(null);
|
||||
@@ -100,6 +182,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||
setSubModule('mechanics');
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
if (eyeDropMode) return;
|
||||
setSelectedPath(null);
|
||||
setSubModule('properties');
|
||||
}}
|
||||
@@ -113,7 +196,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||
name='events-sphere'
|
||||
ref={el => (sphereRefs.current[point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
if (isConnecting) return;
|
||||
if (isConnecting || eyeDropMode) return;
|
||||
e.stopPropagation();
|
||||
setSelectedActionSphere({
|
||||
path,
|
||||
@@ -124,6 +207,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||
}}
|
||||
userData={{ point, path }}
|
||||
onPointerMissed={() => {
|
||||
if (eyeDropMode) return;
|
||||
setSubModule('properties');
|
||||
setSelectedActionSphere(null);
|
||||
}}
|
||||
@@ -155,7 +239,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||
ref={el => (groupRefs.current[path.modeluuid] = el!)}
|
||||
position={path.assetPosition}
|
||||
onClick={(e) => {
|
||||
if (isConnecting) return;
|
||||
if (isConnecting || eyeDropMode) return;
|
||||
e.stopPropagation();
|
||||
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
||||
setSelectedActionSphere(null);
|
||||
@@ -163,6 +247,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||
setSubModule('mechanics');
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
if (eyeDropMode) return;
|
||||
setSelectedPath(null);
|
||||
setSubModule('properties');
|
||||
}}
|
||||
@@ -175,7 +260,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||
name='events-sphere'
|
||||
ref={el => (sphereRefs.current[path.point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
if (isConnecting) return;
|
||||
if (isConnecting || eyeDropMode) return;
|
||||
e.stopPropagation();
|
||||
setSelectedActionSphere({
|
||||
path,
|
||||
@@ -186,6 +271,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
||||
}}
|
||||
userData={{ point: path.point, path }}
|
||||
onPointerMissed={() => {
|
||||
if (eyeDropMode) return;
|
||||
setSubModule('properties');
|
||||
setSelectedActionSphere(null);
|
||||
}}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { useState, useEffect, useRef, useMemo } from 'react';
|
||||
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../store/store';
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import * as THREE from 'three';
|
||||
import Behaviour from './behaviour/behaviour';
|
||||
import PathCreation from './path/pathCreation';
|
||||
@@ -14,7 +13,6 @@ function Simulation() {
|
||||
const [processes, setProcesses] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('simulationPaths: ', simulationPaths);
|
||||
}, [simulationPaths]);
|
||||
|
||||
// useEffect(() => {
|
||||
@@ -29,9 +27,10 @@ function Simulation() {
|
||||
// }
|
||||
// }, [selectedPath]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Behaviour/>
|
||||
<Behaviour />
|
||||
{activeModule === 'simulation' && (
|
||||
<>
|
||||
<PathCreation pathsGroupRef={pathsGroupRef} />
|
||||
|
||||
@@ -1,74 +1,89 @@
|
||||
import { saveTemplateApi } from "../../services/realTimeVisulization/zoneData/saveTempleteApi";
|
||||
import { Template } from "../../store/useTemplateStore";
|
||||
import { captureVisualization } from "./captureVisualization";
|
||||
|
||||
type HandleSaveTemplateProps = {
|
||||
addTemplate: (template: Template) => void;
|
||||
floatingWidget: []; // Updated type from `[]` to `any[]` for clarity
|
||||
widgets3D: []; // Updated type from `[]` to `any[]` for clarity
|
||||
selectedZone: {
|
||||
panelOrder: string[]; // Adjust the type based on actual data structure
|
||||
widgets: any[]; // Replace `any` with the actual widget type
|
||||
panelOrder: string[];
|
||||
widgets: any[];
|
||||
};
|
||||
templates?: Template[];
|
||||
};
|
||||
|
||||
// Generate a unique ID (placeholder function)
|
||||
// Generate a unique ID
|
||||
const generateUniqueId = (): string => {
|
||||
return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
||||
};
|
||||
|
||||
// Refactored function
|
||||
export const handleSaveTemplate = async ({
|
||||
addTemplate,
|
||||
floatingWidget,
|
||||
widgets3D,
|
||||
selectedZone,
|
||||
templates = [],
|
||||
}: HandleSaveTemplateProps): Promise<void> => {
|
||||
try {
|
||||
// Check if the selected zone has any widgets
|
||||
if (!selectedZone.widgets || selectedZone.widgets.length === 0) {
|
||||
console.warn("Cannot save an empty template.");
|
||||
console.warn("No widgets found in the selected zone.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the template already exists
|
||||
const isDuplicate = templates.some((template) => {
|
||||
const isSamePanelOrder =
|
||||
const isDuplicate = templates.some(
|
||||
(template) =>
|
||||
JSON.stringify(template.panelOrder) ===
|
||||
JSON.stringify(selectedZone.panelOrder);
|
||||
const isSameWidgets =
|
||||
JSON.stringify(selectedZone.panelOrder) &&
|
||||
JSON.stringify(template.widgets) ===
|
||||
JSON.stringify(selectedZone.widgets);
|
||||
return isSamePanelOrder && isSameWidgets;
|
||||
});
|
||||
JSON.stringify(selectedZone.widgets)
|
||||
);
|
||||
|
||||
if (isDuplicate) {
|
||||
console.warn("This template already exists.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Capture visualization snapshot
|
||||
const snapshot = await captureVisualization();
|
||||
if (!snapshot) {
|
||||
console.error("Failed to capture visualization snapshot.");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("snapshot: ", snapshot);
|
||||
// if (!snapshot) {
|
||||
// return;
|
||||
// }
|
||||
// Create a new template
|
||||
const newTemplate: Template = {
|
||||
id: generateUniqueId(),
|
||||
name: `Template ${Date.now()}`,
|
||||
name: `Template ${new Date().toISOString()}`, // Better name formatting
|
||||
panelOrder: selectedZone.panelOrder,
|
||||
widgets: selectedZone.widgets,
|
||||
snapshot,
|
||||
floatingWidget,
|
||||
widgets3D,
|
||||
};
|
||||
|
||||
console.log("Saving template:", newTemplate);
|
||||
// Extract organization from email
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email.includes("@")
|
||||
? email.split("@")[1]?.split(".")[0]
|
||||
: "";
|
||||
|
||||
if (!organization) {
|
||||
console.error("Organization could not be determined from email.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Save the template
|
||||
try {
|
||||
const response = await saveTemplateApi(organization, newTemplate);
|
||||
console.log("Save API Response:", response);
|
||||
|
||||
// Add template only if API call succeeds
|
||||
addTemplate(newTemplate);
|
||||
} catch (error) {
|
||||
console.error("Failed to add template:", error);
|
||||
} catch (apiError) {
|
||||
console.error("Error saving template to API:", apiError);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to save template:", error);
|
||||
console.error("Error in handleSaveTemplate:", error);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user