diff --git a/app/src/modules/collaboration/collabCams.tsx b/app/src/modules/collaboration/collabCams.tsx index 20d983e..a1383f2 100644 --- a/app/src/modules/collaboration/collabCams.tsx +++ b/app/src/modules/collaboration/collabCams.tsx @@ -12,203 +12,189 @@ import CollabUserIcon from "./collabUserIcon"; import { getAvatarColor } from "./users/functions/getAvatarColor"; const CamModelsGroup = () => { - let navigate = useNavigate(); - const groupRef = useRef(null); - const email = localStorage.getItem("email"); - const { activeUsers, setActiveUsers } = useActiveUsers(); - const { socket } = useSocketStore(); - const loader = new GLTFLoader(); - const dracoLoader = new DRACOLoader(); - const [cams, setCams] = useState([]); - const [models, setModels] = useState>({}); + const navigate = useNavigate(); + const groupRef = useRef(null); + const email = localStorage.getItem("email"); + const { activeUsers, setActiveUsers } = useActiveUsers(); + const { socket } = useSocketStore(); - dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/"); - loader.setDRACOLoader(dracoLoader); + const loader = new GLTFLoader(); + const dracoLoader = new DRACOLoader(); + dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/"); + loader.setDRACOLoader(dracoLoader); - useEffect(() => { - if (!email) { - navigate("/"); - } - if (!socket) return; - const organization = email!.split("@")[1].split(".")[0]; + const [cams, setCams] = useState([]); + const [models, setModels] = useState>({}); - socket.on("userConnectResponse", (data: any) => { - if (!groupRef.current) return; - if (data.data.userData.email === email) return; - if (socket.id === data.socketId || organization !== data.organization) - return; + const dedupeCams = (cams: any[]) => { + const seen = new Set(); + return cams.filter((cam) => { + if (seen.has(cam.uuid)) return false; + seen.add(cam.uuid); + return true; + }); + }; - const model = groupRef.current.getObjectByProperty( - "uuid", - data.data.userData._id - ); - if (model) { - groupRef.current.remove(model); - } - loader.load(camModel, (gltf) => { - const newModel = gltf.scene.clone(); - newModel.uuid = data.data.userData._id; - newModel.position.set( - data.data.position.x, - data.data.position.y, - data.data.position.z - ); - newModel.rotation.set( - data.data.rotation.x, - data.data.rotation.y, - data.data.rotation.z - ); - newModel.userData = data.data.userData; - setCams((prev) => [...prev, newModel]); - setActiveUsers([...activeUsers, data.data.userData]); - }); - }); + const dedupeUsers = (users: any[]) => { + const seen = new Set(); + return users.filter((user) => { + if (seen.has(user._id)) return false; + seen.add(user._id); + return true; + }); + }; - // socket.on("users:online", (data: any) => { - // console.log('users online: ', data); - // }) + useEffect(() => { + if (!email) navigate("/"); - socket.on("userDisConnectResponse", (data: any) => { - if (!groupRef.current) return; - if (socket.id === data.socketId || organization !== data.organization) - return; + if (!socket) return; + const organization = email!.split("@")[1].split(".")[0]; - setCams((prev) => - prev.filter((cam) => cam.uuid !== data.data.userData._id) - ); - setActiveUsers( - activeUsers.filter((user: any) => user._id !== data.data.userData._id) - ); - }); + socket.on("userConnectResponse", (data: any) => { + if (!groupRef.current) return; + if (data.data.userData.email === email) return; + if (socket.id === data.socketId || organization !== data.organization) return; - socket.on("cameraUpdateResponse", (data: any) => { - if ( - !groupRef.current || - socket.id === data.socketId || - organization !== data.organization - ) - return; + const model = groupRef.current.getObjectByProperty("uuid", data.data.userData._id); + if (model) { + groupRef.current.remove(model); + } - setModels((prev) => ({ - ...prev, - [data.data.userId]: { - targetPosition: new THREE.Vector3( - data.data.position.x, - data.data.position.y, - data.data.position.z - ), - targetRotation: new THREE.Euler( - data.data.rotation.x, - data.data.rotation.y, - data.data.rotation.z - ), - }, - })); - }); + loader.load(camModel, (gltf) => { + const newModel = gltf.scene.clone(); + newModel.uuid = data.data.userData._id; + newModel.position.set( + data.data.position.x, + data.data.position.y, + data.data.position.z + ); + newModel.rotation.set( + data.data.rotation.x, + data.data.rotation.y, + data.data.rotation.z + ); + newModel.userData = data.data.userData; - return () => { - socket.off("userConnectRespones"); - socket.off("userDisConnectRespones"); - socket.off("cameraUpdateResponse"); - }; - }, [socket]); + setCams((prev) => dedupeCams([...prev, newModel])); + setActiveUsers((prev: any) => + dedupeUsers([...prev, data.data.userData]) + ); + }); + }); + socket.on("userDisConnectResponse", (data: any) => { + if (!groupRef.current) return; + if (socket.id === data.socketId || organization !== data.organization) return; - // useEffect(() => { - // console.log(activeUsers); - // }, [activeUsers]) + setCams((prev) => + prev.filter((cam) => cam.uuid !== data.data.userData._id) + ); + setActiveUsers((prev: any) => + prev.filter((user: any) => user._id !== data.data.userData._id) + ); + }); - // useEffect(() => { - // console.log(models); - // }, [models]) + socket.on("cameraUpdateResponse", (data: any) => { + if ( + !groupRef.current || + socket.id === data.socketId || + organization !== data.organization + ) + return; - useFrame(() => { - if (!groupRef.current) return; - Object.keys(models).forEach((uuid) => { - const model = groupRef.current!.getObjectByProperty("uuid", uuid); - if (!model) return; + setModels((prev) => ({ + ...prev, + [data.data.userId]: { + targetPosition: new THREE.Vector3( + data.data.position.x, + data.data.position.y, + data.data.position.z + ), + targetRotation: new THREE.Euler( + data.data.rotation.x, + data.data.rotation.y, + data.data.rotation.z + ), + }, + })); + }); - const { targetPosition, targetRotation } = models[uuid]; - model.position.lerp(targetPosition, 0.1); - model.rotation.x = THREE.MathUtils.lerp( - model.rotation.x, - targetRotation.x, - 0.1 - ); - model.rotation.y = THREE.MathUtils.lerp( - model.rotation.y, - targetRotation.y, - 0.1 - ); - model.rotation.z = THREE.MathUtils.lerp( - model.rotation.z, - targetRotation.z, - 0.1 - ); - }); - }); + return () => { + socket.off("userConnectResponse"); + socket.off("userDisConnectResponse"); + socket.off("cameraUpdateResponse"); + }; + }, [socket]); - useEffect(() => { - if (!groupRef.current) return; - const organization = email!.split("@")[1].split(".")[0]; - getActiveUsersData(organization).then((data) => { - const filteredData = data.cameraDatas.filter( - (camera: any) => camera.userData.email !== email - ); - let a: any = []; - if (filteredData.length > 0) { - loader.load(camModel, (gltf) => { - const newCams = filteredData.map((cam: any) => { - const newModel = gltf.scene.clone(); - newModel.uuid = cam.userData._id; - newModel.position.set( - cam.position.x, - cam.position.y, - cam.position.z - ); - newModel.rotation.set( - cam.rotation.x, - cam.rotation.y, - cam.rotation.z - ); - newModel.userData = cam.userData; - a.push(cam.userData); - return newModel; - }); - setActiveUsers(a); - setCams((prev) => [...prev, ...newCams]); - }); - } - }); - }, []); + useFrame(() => { + if (!groupRef.current) return; + Object.keys(models).forEach((uuid) => { + const model = groupRef.current!.getObjectByProperty("uuid", uuid); + if (!model) return; - return ( - - {cams.map((cam, index) => ( - - - - - - ))} - - ); + const { targetPosition, targetRotation } = models[uuid]; + model.position.lerp(targetPosition, 0.1); + model.rotation.x = THREE.MathUtils.lerp(model.rotation.x, targetRotation.x, 0.1); + model.rotation.y = THREE.MathUtils.lerp(model.rotation.y, targetRotation.y, 0.1); + model.rotation.z = THREE.MathUtils.lerp(model.rotation.z, targetRotation.z, 0.1); + }); + }); + + useEffect(() => { + if (!groupRef.current) return; + const organization = email!.split("@")[1].split(".")[0]; + + getActiveUsersData(organization).then((data) => { + const filteredData = data.cameraDatas.filter( + (camera: any) => camera.userData.email !== email + ); + + if (filteredData.length > 0) { + loader.load(camModel, (gltf) => { + const newCams = filteredData.map((cam: any) => { + const newModel = gltf.scene.clone(); + newModel.uuid = cam.userData._id; + newModel.position.set(cam.position.x, cam.position.y, cam.position.z); + newModel.rotation.set(cam.rotation.x, cam.rotation.y, cam.rotation.z); + newModel.userData = cam.userData; + return newModel; + }); + + const users = filteredData.map((cam: any) => cam.userData); + setActiveUsers((prev: any) => dedupeUsers([...prev, ...users])); + setCams((prev) => dedupeCams([...prev, ...newCams])); + }); + } + }); + }, []); + + return ( + + {cams.map((cam, index) => ( + + + + + + ))} + + ); }; export default CamModelsGroup; diff --git a/app/src/modules/collaboration/collabUserIcon.tsx b/app/src/modules/collaboration/collabUserIcon.tsx index acc3fa0..4cea436 100644 --- a/app/src/modules/collaboration/collabUserIcon.tsx +++ b/app/src/modules/collaboration/collabUserIcon.tsx @@ -20,7 +20,24 @@ const CollabUserIcon: React.FC = ({ {userImage ? ( {userName} ) : ( - + + //
+ // {userName[0]} + //
)}
diff --git a/app/src/modules/collaboration/socketResponses.dev.tsx b/app/src/modules/collaboration/socketResponses.dev.tsx index 8771303..ceef567 100644 --- a/app/src/modules/collaboration/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socketResponses.dev.tsx @@ -233,7 +233,7 @@ export default function SocketResponses({ } } else if (data.message === "Model updated successfully") { - itemsGroup.current.children.forEach((item: THREE.Group) => { + itemsGroup.current?.children.forEach((item: THREE.Group) => { if (item.uuid === data.data.modeluuid) { item.position.set(...data.data.position as [number, number, number]); item.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); diff --git a/app/src/modules/collaboration/users/Avatar.tsx b/app/src/modules/collaboration/users/Avatar.tsx index f08a545..b04ff7d 100644 --- a/app/src/modules/collaboration/users/Avatar.tsx +++ b/app/src/modules/collaboration/users/Avatar.tsx @@ -7,6 +7,7 @@ interface AvatarProps { size?: number; index?: number; textColor?: string; + color?: string; // Optional color prop for future use } const CustomAvatar: React.FC = ({ @@ -14,6 +15,7 @@ const CustomAvatar: React.FC = ({ size = 100, index = 0, textColor = "#ffffff", + color, // Optional color prop for future use }) => { const [imageSrc, setImageSrc] = useState(null); @@ -26,7 +28,7 @@ const CustomAvatar: React.FC = ({ const initials = getInitials(name); // Convert name to initials if needed // Draw background - ctx.fillStyle = getAvatarColor(index); + ctx.fillStyle = color || getAvatarColor(index); // Use color prop or generate color based on index ctx.fillRect(0, 0, size, size); // Draw initials @@ -40,7 +42,7 @@ const CustomAvatar: React.FC = ({ const dataURL = canvas.toDataURL("image/png"); setImageSrc(dataURL); } - }, [name, size, textColor]); + }, [name, size, textColor, index]); if (!imageSrc) { return null; // Return null while the image is being generated @@ -53,6 +55,18 @@ const CustomAvatar: React.FC = ({ alt="User Avatar" style={{ width: "100%", height: "100%" }} /> + //
+ // {name[0]} + //
); }; diff --git a/app/src/services/factoryBuilder/environment/findEnvironment.ts b/app/src/services/factoryBuilder/environment/findEnvironment.ts index de5b6a6..08cfe68 100644 --- a/app/src/services/factoryBuilder/environment/findEnvironment.ts +++ b/app/src/services/factoryBuilder/environment/findEnvironment.ts @@ -26,7 +26,7 @@ export const findEnvironment = async (organization: string, userId: string) => { false, false, false, - 0, + 40, true ); return userpos; diff --git a/app/src/store/store.ts b/app/src/store/store.ts index fc30aba..725180b 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -14,7 +14,7 @@ export const useSocketStore = create((set: any, get: any) => ({ const socket = io( `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, { - reconnection: false, + reconnection: true, auth: { email, organization }, } ); @@ -22,7 +22,7 @@ export const useSocketStore = create((set: any, get: any) => ({ const visualizationSocket = io( `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`, { - reconnection: false, + reconnection: true, auth: { email, organization }, } ); @@ -302,7 +302,13 @@ export const useDrieTemp = create((set: any) => ({ export const useActiveUsers = create((set: any) => ({ activeUsers: [], - setActiveUsers: (x: any) => set({ activeUsers: x }), + setActiveUsers: (callback: (prev: any[]) => any[] | any[]) => + set((state: { activeUsers: any[] }) => ({ + activeUsers: + typeof callback === "function" + ? callback(state.activeUsers) + : callback, + })), })); export const useDrieUIValue = create((set: any) => ({