diff --git a/app/src/app.tsx b/app/src/app.tsx
index 2b2a25d..a2d7df7 100644
--- a/app/src/app.tsx
+++ b/app/src/app.tsx
@@ -1,14 +1,16 @@
-import React, { useEffect } from "react";
import { Cache } from "three";
+import React, { useEffect } from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
+import { LoggerProvider } from "./components/ui/log/LoggerContext";
+
+import UserAuth from "./pages/UserAuth";
+import ForgotPassword from "./pages/ForgotPassword";
import Dashboard from "./pages/Dashboard";
import Project from "./pages/Project";
-import UserAuth from "./pages/UserAuth";
-import "./styles/main.scss";
-import { LoggerProvider } from "./components/ui/log/LoggerContext";
-import ForgotPassword from "./pages/ForgotPassword";
import PageNotFound from "./pages/PageNotFound";
+import "./styles/main.scss";
+
const App: React.FC = () => {
useEffect(() => {
Cache.clear();
diff --git a/app/src/components/layout/scenes/MainScene.tsx b/app/src/components/layout/scenes/MainScene.tsx
index b2d0c99..701517d 100644
--- a/app/src/components/layout/scenes/MainScene.tsx
+++ b/app/src/components/layout/scenes/MainScene.tsx
@@ -65,7 +65,9 @@ function MainScene() {
useEffect(() => {
if (builderSocket && projectId) {
- builderSocket.emit("joinRoom", { projectId: projectId });
+ setTimeout(() => {
+ builderSocket.emit("joinRoom", { projectId: projectId });
+ }, 1000);
}
}, [builderSocket, projectId]);
diff --git a/app/src/components/layout/sidebarRight/Header.tsx b/app/src/components/layout/sidebarRight/Header.tsx
index 0377e3f..630cc72 100644
--- a/app/src/components/layout/sidebarRight/Header.tsx
+++ b/app/src/components/layout/sidebarRight/Header.tsx
@@ -1,7 +1,6 @@
import React, { useState } from "react";
import orgImg from "../../../assets/image/orgTemp.png";
-import { useActiveUsers, useCamMode } from "../../../store/builder/store";
-import { ActiveUser } from "../../../types/users";
+import { useCamMode } from "../../../store/builder/store";
import CollaborationPopup from "../../templates/CollaborationPopup";
import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor";
import { useSelectedUserStore } from "../../../store/collaboration/useCollabStore";
@@ -9,120 +8,110 @@ import { useToggleStore } from "../../../store/ui/useUIToggleStore";
import { ToggleSidebarIcon } from "../../icons/HeaderIcons";
import useModuleStore from "../../../store/ui/useModuleStore";
import { getUserData } from "../../../functions/getUserData";
+import { useSceneContext } from "../../../modules/scene/sceneContext";
const Header: React.FC = () => {
- const { activeUsers } = useActiveUsers();
- const { userName } = getUserData();
- const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
- const { activeModule } = useModuleStore();
+ const { collabUsersStore } = useSceneContext();
+ const { collabUsers } = collabUsersStore();
+ const { userId, userName } = getUserData();
+ const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
+ const { activeModule } = useModuleStore();
- const guestUsers: ActiveUser[] = activeUsers.filter(
- (user: ActiveUser) => user.userName !== userName
- );
+ const guestUsers = collabUsers.filter((user) => user.userId !== userId);
- const [userManagement, setUserManagement] = useState(false);
- const { setSelectedUser } = useSelectedUserStore();
- const { setCamMode } = useCamMode();
+ const [userManagement, setUserManagement] = useState(false);
+ const { setSelectedUser } = useSelectedUserStore();
+ const { setCamMode } = useCamMode();
- function handleUserFollow(user: any, index: number) {
- const position = {
- x: user.position?.x!,
- y: user.position?.y!,
- z: user.position?.z!,
- };
- const target = {
- x: user.target?.x!,
- y: user.target?.y!,
- z: user.target?.z!,
- };
- const rotation = {
- x: user.rotation?.x!,
- y: user.rotation?.y!,
- z: user.rotation?.z!,
- };
+ function handleUserFollow(user: any, index: number) {
+ const position = {
+ x: user.position?.x!,
+ y: user.position?.y!,
+ z: user.position?.z!,
+ };
+ const target = {
+ x: user.target?.x!,
+ y: user.target?.y!,
+ z: user.target?.z!,
+ };
+ const rotation = {
+ x: user.rotation?.x!,
+ y: user.rotation?.y!,
+ z: user.rotation?.z!,
+ };
- // retun on no data
- if (!position || !target || !rotation) return;
+ // retun on no data
+ if (!position || !target || !rotation) return;
- // Set the selected user in the store
- setSelectedUser({
- color: getAvatarColor(index, user.userName),
- name: user.userName,
- id: user.id,
- location: { position, rotation, target },
- });
- setCamMode("FollowPerson");
- }
+ // Set the selected user in the store
+ setSelectedUser({
+ color: getAvatarColor(index, user.userName),
+ name: user.userName,
+ id: user.id,
+ location: { position, rotation, target },
+ });
+ setCamMode("FollowPerson");
+ }
- return (
- <>
- {userManagement && (
-
- )}
-
-
-
-
- {/*
+ return (
+ <>
+ {userManagement &&
}
+
+
+
+
+ {/*
*/}
-
-
-
-
- {guestUsers.length > 3 && (
-
+{guestUsers.length - 3}
- )}
- {guestUsers.slice(0, 3).map((user, index) => (
-
- ))}
-
-
-
{userName?.charAt(0).toUpperCase()}
-
-

+
+
+
+
+ {guestUsers.length > 3 &&
+{guestUsers.length - 3}
}
+ {guestUsers.slice(0, 3).map((user, index) => (
+
+ ))}
+
+
+
{userName?.charAt(0).toUpperCase()}
+
+

+
+
+
-
-
-
- >
- );
+ >
+ );
};
export default Header;
diff --git a/app/src/components/templates/CollaborationPopup.tsx b/app/src/components/templates/CollaborationPopup.tsx
index cd246fc..b336829 100644
--- a/app/src/components/templates/CollaborationPopup.tsx
+++ b/app/src/components/templates/CollaborationPopup.tsx
@@ -1,11 +1,9 @@
import React, { useEffect, useState } from "react";
import RenderOverlay from "./Overlay";
-import { ArrowIcon, CloseIcon } from "../icons/ExportCommonIcons";
+import { CloseIcon } from "../icons/ExportCommonIcons";
import { AccessOption, User } from "../../types/users";
import RegularDropDown from "../ui/inputs/RegularDropDown";
-import { access } from "fs";
import MultiEmailInvite from "../ui/inputs/MultiEmailInvite";
-import { useActiveUsers } from "../../store/builder/store";
import { getUserData } from "../../functions/getUserData";
import { getProjectSharedList } from "../../services/factoryBuilder/collab/project/getProjectSharedList";
import { useParams } from "react-router-dom";
@@ -13,147 +11,124 @@ import { shareAccess } from "../../services/factoryBuilder/collab/project/shareA
import { getAvatarColor } from "../../modules/collaboration/functions/getAvatarColor";
interface UserListTemplateProps {
- user: User;
+ user: User;
}
const UserListTemplate: React.FC
= ({ user }) => {
- const [accessSelection, setAccessSelection] = useState(user?.Access);
- const { projectId } = useParams();
+ const [accessSelection, setAccessSelection] = useState(user?.Access);
+ const { projectId } = useParams();
- const accessUpdate = async ({ option }: AccessOption) => {
- if (!projectId) return
- const accessSelection = await shareAccess(projectId, user.userId, option)
- setAccessSelection(option);
- }
+ const accessUpdate = async ({ option }: AccessOption) => {
+ if (!projectId) return;
+ const accessSelection = await shareAccess(projectId, user.userId, option);
+ setAccessSelection(option);
+ };
- return (
-
-
-
- {user.profileImage ? (
-

- ) : (
-
- {user.
- userName.charAt(0).toUpperCase()}
+ return (
+
+
+
+ {user.profileImage ? (
+

+ ) : (
+
+ {user.userName.charAt(0).toUpperCase()}
+
+ )}
+
+
{user.userName.charAt(0).toUpperCase() + user.userName.slice(1).toLowerCase()}
+
+
+
accessUpdate({ option })} search={false} />
+ {/* */}
- )}
-
{user.
- userName.charAt(0).toUpperCase() + user.
- userName.slice(1).toLowerCase()}
-
-
-
accessUpdate({ option })}
- search={false}
- />
- {/* */}
-
-
- );
+ );
};
interface CollaborateProps {
- setUserManagement: (value: boolean) => void;
+ setUserManagement: (value: boolean) => void;
}
-const CollaborationPopup: React.FC
= ({
- setUserManagement,
-}) => {
- const { activeUsers } = useActiveUsers();
- const { userName } = getUserData();
- const [users, setUsers] = useState([])
- const { projectId } = useParams();
+const CollaborationPopup: React.FC = ({ setUserManagement }) => {
+ const { userName } = getUserData();
+ const [users, setUsers] = useState([]);
+ const { projectId } = useParams();
- function getData() {
- if (!projectId) return;
- getProjectSharedList(projectId).then((allUser) => {
- const accesMail = allUser?.datas || []
- setUsers(accesMail)
- }).catch((err) => {
+ function getData() {
+ if (!projectId) return;
+ getProjectSharedList(projectId)
+ .then((allUser) => {
+ const accesMail = allUser?.datas || [];
+ setUsers(accesMail);
+ })
+ .catch((err) => {});
+ }
- })
- }
+ useEffect(() => {
+ getData();
+ }, []);
- useEffect(() => {
- getData();
- }, [])
-
- useEffect(() => {
- //
- }, [activeUsers]);
- return (
-
- {
- setUserManagement(false);
- }}
- >
-
{
- e.preventDefault();
- e.stopPropagation();
- }}
- >
-
-
Share this file
-
- {/*
copy link
*/}
-
+
{
- setUserManagement(false);
+ setUserManagement(false);
}}
- >
-
-
-
-
-
-
-
-
-
-
-
Who has access
-
-
-
Untitled
-
- {users.length} persons
-
+ >
+
{
+ e.preventDefault();
+ e.stopPropagation();
+ }}
+ >
+
+
Share this file
+
+ {/*
copy link
*/}
+
{
+ setUserManagement(false);
+ }}
+ >
+
+
+
+
+
+
+
+
+
+
+
Who has access
+
+
+
Untitled
+
{users.length} persons
+
+
+
+
+
+
{userName && userName[0].toUpperCase()}
+ {userName && userName.charAt(0).toUpperCase() + userName.slice(1).toLowerCase()}
+
+
you
+
+ {users.map((user, index) => (
+
+ ))}
+
+
+
-
-
-
-
-
{userName && userName[0].toUpperCase()}
- {userName && userName.charAt(0).toUpperCase() + userName.slice(1).toLowerCase()}
-
-
you
-
- {users.map((user, index) => (
-
- ))}
-
-
-
-
-
- );
+
+ );
};
export default CollaborationPopup;
diff --git a/app/src/components/ui/FileMenu.tsx b/app/src/components/ui/FileMenu.tsx
index 33a85fc..9e41929 100644
--- a/app/src/components/ui/FileMenu.tsx
+++ b/app/src/components/ui/FileMenu.tsx
@@ -14,7 +14,6 @@ const FileMenu: React.FC = () => {
const containerRef = useRef
(null);
let clickTimeout: NodeJS.Timeout | null = null;
const { projectName, setProjectName } = useProjectName();
- // const { dashBoardSocket } = useSocketStore();
const { projectId } = useParams();
const { userId, organization, email } = getUserData();
@@ -58,16 +57,6 @@ const FileMenu: React.FC = () => {
projectName,
thumbnail: undefined,
};
-
- // if (dashBoardSocket) {
- // const handleResponse = (data: any) => {
- // console.log('Project update response:', data);
- // dashBoardSocket.off("v1-project:response:update", handleResponse); // Clean up
- // };
- // dashBoardSocket.on("v1-project:response:update", handleResponse);
- // dashBoardSocket.emit("v1:project:update", updateProjects);
- // }
-
//API for projects rename
const updatedProjectName = await updateProjectApi(projectId, undefined, projectName);
diff --git a/app/src/components/ui/collaboration/threads/Messages.tsx b/app/src/components/ui/collaboration/threads/Messages.tsx
index 7f48114..11af2a8 100644
--- a/app/src/components/ui/collaboration/threads/Messages.tsx
+++ b/app/src/components/ui/collaboration/threads/Messages.tsx
@@ -34,7 +34,7 @@ const Messages: React.FC = ({ val, i, setMessages, mode, setIsEdit
const [isEditComment, setIsEditComment] = useState(false);
const { selectedComment, setCommentPositionState } = useSelectedComment();
const { versionStore, threadStore } = useSceneContext();
- const { updateComment, removeReply, updateReply } = threadStore();
+ const { updateThread, removeReply, updateReply } = threadStore();
const { selectedVersion } = versionStore();
const [value, setValue] = useState("comment" in val ? val.comment : val.threadTitle);
@@ -71,7 +71,7 @@ const Messages: React.FC = ({ val, i, setMessages, mode, setIsEdit
rotation: [0, 0, 0],
comments: [],
};
- updateComment((val as ThreadSchema).threadId, editedThread);
+ updateThread((val as ThreadSchema).threadId, editedThread);
}
});
} else {
diff --git a/app/src/components/ui/collaboration/threads/ThreadChat.tsx b/app/src/components/ui/collaboration/threads/ThreadChat.tsx
index 1cfc08f..a7e8c50 100644
--- a/app/src/components/ui/collaboration/threads/ThreadChat.tsx
+++ b/app/src/components/ui/collaboration/threads/ThreadChat.tsx
@@ -36,7 +36,7 @@ const ThreadChat: React.FC = () => {
const messagesRef = useRef(null);
const { versionStore, threadStore } = useSceneContext();
const { selectedVersion } = versionStore();
- const { addComment, removeComment, addReply, threads } = threadStore();
+ const { addThread, removeThread, addReply, threads } = threadStore();
useEffect(() => {
modeRef.current = mode;
@@ -157,7 +157,7 @@ const ThreadChat: React.FC = () => {
} else if (threadSocket?.connected && mode === "create") {
// SOCKET
- const addComment = {
+ const addThread = {
versionId: selectedVersion?.versionId || "",
projectId,
userId,
@@ -166,7 +166,7 @@ const ThreadChat: React.FC = () => {
threadId: selectedComment?.threadId,
};
- threadSocket.emit("v1-Comment:add", addComment);
+ threadSocket.emit("v1-Comment:add", addThread);
}
setInputActive(false);
};
@@ -179,7 +179,7 @@ const ThreadChat: React.FC = () => {
deleteThreadApi(projectId, selectedComment?.threadId, selectedVersion?.versionId || "").then((deleteThread) => {
if (deleteThread.message === "Thread deleted Successfully") {
- removeComment(selectedComment?.threadId);
+ removeThread(selectedComment?.threadId);
setSelectedComment(null);
}
});
@@ -194,7 +194,7 @@ const ThreadChat: React.FC = () => {
versionId: selectedVersion?.versionId || "",
};
setSelectedComment(null);
- removeComment(selectedComment?.threadId);
+ removeThread(selectedComment?.threadId);
threadSocket.emit("v1:thread:delete", deleteThread);
}
};
@@ -219,7 +219,7 @@ const ThreadChat: React.FC = () => {
rotation: [0, 0, 0],
comments: [],
};
- addComment(comment);
+ addThread(comment);
setCommentPositionState(null);
setInputActive(false);
setSelectedComment(null);
diff --git a/app/src/components/ui/log/LoggerContext.tsx b/app/src/components/ui/log/LoggerContext.tsx
index 37eaf6c..8f7a949 100644
--- a/app/src/components/ui/log/LoggerContext.tsx
+++ b/app/src/components/ui/log/LoggerContext.tsx
@@ -1,112 +1,89 @@
// LoggerProvider.tsx
-import React, {
- createContext,
- useContext,
- useState,
- useCallback,
- useMemo,
- useEffect,
-} from "react";
+import React, { createContext, useContext, useState, useCallback, useMemo, useEffect } from "react";
import { MathUtils } from "three";
export type LogType = "log" | "info" | "warning" | "error" | "success";
export interface LogEntry {
- id: string;
- type: LogType;
- message: string;
- timestamp: Date;
+ id: string;
+ type: LogType;
+ message: string;
+ timestamp: Date;
}
interface LoggerContextValue {
- logs: LogEntry[];
- setLogs: React.Dispatch>;
- isLogListVisible: boolean;
- setIsLogListVisible: React.Dispatch>;
- selectedTab: LogType | "all";
- setSelectedTab: React.Dispatch>;
- log: (message: string) => void;
- info: (message: string) => void;
- warn: (message: string) => void;
- error: (message: string) => void;
- success: (message: string) => void;
- clear: () => void;
+ logs: LogEntry[];
+ setLogs: React.Dispatch>;
+ isLogListVisible: boolean;
+ setIsLogListVisible: React.Dispatch>;
+ selectedTab: LogType | "all";
+ setSelectedTab: React.Dispatch>;
+ log: (message: string) => void;
+ info: (message: string) => void;
+ warn: (message: string) => void;
+ error: (message: string) => void;
+ success: (message: string) => void;
+ clear: () => void;
}
const LoggerContext = createContext(undefined);
-export const LoggerProvider: React.FC<{ children: React.ReactNode }> = ({
- children,
-}) => {
- const [logs, setLogs] = useState([]);
- const [isLogListVisible, setIsLogListVisible] = useState(false);
- const [selectedTab, setSelectedTab] = useState("all");
+export const LoggerProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
+ const [logs, setLogs] = useState([]);
+ const [isLogListVisible, setIsLogListVisible] = useState(false);
+ const [selectedTab, setSelectedTab] = useState("all");
- const addLog = useCallback((type: LogType, message: string) => {
- const newLog: LogEntry = {
- id: MathUtils.generateUUID(),
- type,
- message,
- timestamp: new Date(),
- };
- setLogs((prevLogs) => [...prevLogs, newLog]);
- }, []);
+ const addLog = useCallback((type: LogType, message: string) => {
+ const newLog: LogEntry = {
+ id: MathUtils.generateUUID(),
+ type,
+ message,
+ timestamp: new Date(),
+ };
+ setLogs((prevLogs) => [...prevLogs, newLog]);
+ }, []);
- const loggerMethods: LoggerContextValue = useMemo(
- () => ({
- logs,
- setLogs,
- isLogListVisible,
- setIsLogListVisible,
- selectedTab,
- setSelectedTab,
- log: (message: string) => addLog("log", message),
- info: (message: string) => addLog("info", message),
- warn: (message: string) => addLog("warning", message),
- error: (message: string) => addLog("error", message),
- success: (message: string) => addLog("success", message),
- clear: () => {
- if (selectedTab !== "all") {
- setLogs((prevLogs) =>
- prevLogs.filter((log) => log.type !== selectedTab)
- );
- } else {
- setLogs([]);
- }
- },
- }),
- [
- logs,
- setLogs,
- isLogListVisible,
- setIsLogListVisible,
- selectedTab,
- setSelectedTab,
- addLog,
- ]
- );
- useEffect(() => {
- (window as any).echo = {
- log: loggerMethods.log,
- info: loggerMethods.info,
- warn: loggerMethods.warn,
- error: loggerMethods.error,
- success: loggerMethods.success,
- clear: loggerMethods.clear,
- };
- }, [loggerMethods]);
+ const loggerMethods: LoggerContextValue = useMemo(
+ () => ({
+ logs,
+ setLogs,
+ isLogListVisible,
+ setIsLogListVisible,
+ selectedTab,
+ setSelectedTab,
+ log: (message: string) => addLog("log", message),
+ info: (message: string) => addLog("info", message),
+ warn: (message: string) => addLog("warning", message),
+ error: (message: string) => addLog("error", message),
+ success: (message: string) => addLog("success", message),
+ clear: () => {
+ if (selectedTab !== "all") {
+ setLogs((prevLogs) => prevLogs.filter((log) => log.type !== selectedTab));
+ } else {
+ setLogs([]);
+ }
+ },
+ }),
+ [logs, setLogs, isLogListVisible, setIsLogListVisible, selectedTab, setSelectedTab, addLog]
+ );
+ useEffect(() => {
+ (window as any).echo = {
+ log: loggerMethods.log,
+ info: loggerMethods.info,
+ warn: loggerMethods.warn,
+ error: loggerMethods.error,
+ success: loggerMethods.success,
+ clear: loggerMethods.clear,
+ };
+ }, [loggerMethods]);
- return (
-
- {children}
-
- );
+ return {children};
};
export const useLogger = () => {
- const context = useContext(LoggerContext);
- if (!context) {
- throw new Error("useLogger must be used within a LoggerProvider");
- }
- return context;
+ const context = useContext(LoggerContext);
+ if (!context) {
+ throw new Error("useLogger must be used within a LoggerProvider");
+ }
+ return context;
};
diff --git a/app/src/global.d.ts b/app/src/global.d.ts
index 804fae0..c6fe18c 100644
--- a/app/src/global.d.ts
+++ b/app/src/global.d.ts
@@ -2,12 +2,12 @@
import { LogType } from "../components/ui/log/LoggerContext";
declare global {
- const echo: {
- log: (message: string) => void;
- info: (message: string) => void;
- warn: (message: string) => void;
- error: (message: string) => void;
- success: (message: string) => void;
- clear: () => void;
- };
+ const echo: {
+ log: (message: string) => void;
+ info: (message: string) => void;
+ warn: (message: string) => void;
+ error: (message: string) => void;
+ success: (message: string) => void;
+ clear: () => void;
+ };
}
diff --git a/app/src/modules/collaboration/camera/collabCams.tsx b/app/src/modules/collaboration/camera/collabCams.tsx
index 4356820..429d3a5 100644
--- a/app/src/modules/collaboration/camera/collabCams.tsx
+++ b/app/src/modules/collaboration/camera/collabCams.tsx
@@ -1,18 +1,8 @@
import * as THREE from "three";
-import { Html } from "@react-three/drei";
-import { useNavigate } from "react-router-dom";
-import { useEffect, useRef, useState } from "react";
-import { useFrame, useThree } from "@react-three/fiber";
-import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
-import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
-import { useActiveUsers, useCamMode } from "../../../store/builder/store";
-import { useSocketStore } from "../../../store/socket/useSocketStore";
-import useModuleStore from "../../../store/ui/useModuleStore";
-import { useSelectedUserStore } from "../../../store/collaboration/useCollabStore";
-import { usePlayButtonStore } from "../../../store/ui/usePlayButtonStore";
-
-import setCameraView from "../functions/setCameraView";
-import getActiveUsersData from "../../../services/factoryBuilder/collab/users/getActiveUsers";
+import { Html, useGLTF } from "@react-three/drei";
+import { useRef } from "react";
+import { useFrame } from "@react-three/fiber";
+import { useSceneContext } from "../../scene/sceneContext";
import { getUserData } from "../../../functions/getUserData";
import { getAvatarColor } from "../functions/getAvatarColor";
@@ -20,222 +10,65 @@ import CollabUserIcon from "./collabUserIcon";
import camModel from "../../../assets/gltf-glb/camera face 2.gltf";
const CamModelsGroup = () => {
- const navigate = useNavigate();
- const groupRef = useRef(null);
- const { organization, email } = getUserData();
- const { setActiveUsers } = useActiveUsers();
- const { builderSocket } = useSocketStore();
- const { activeModule } = useModuleStore();
- const { selectedUser, setSelectedUser } = useSelectedUserStore();
- const { isPlaying } = usePlayButtonStore();
- // eslint-disable-next-line react-hooks/exhaustive-deps
- const loader = new GLTFLoader();
- const dracoLoader = new DRACOLoader();
- dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/");
- loader.setDRACOLoader(dracoLoader);
-
- const { camMode } = useCamMode();
- const { camera, controls } = useThree();
-
- useEffect(() => {
- if (camMode !== "FollowPerson") return;
- if (selectedUser?.location) {
- const { position, rotation, target } = selectedUser.location;
- if (rotation && target)
- setCameraView({
- controls,
- camera,
- position,
- rotation,
- target,
- username: selectedUser.name,
- });
- }
- }, [selectedUser, camera, controls, camMode]);
-
- const [cams, setCams] = useState([]);
- const [models, setModels] = useState<
- Record<
- string,
- {
- targetPosition: THREE.Vector3;
- targetRotation: THREE.Euler;
- target: THREE.Vector3;
- }
- >
- >({});
-
- 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 dedupeUsers = (users: any[]) => {
- const seen = new Set();
- return users.filter((user) => {
- if (seen.has(user._id)) return false;
- seen.add(user._id);
- return true;
- });
- };
-
- useEffect(() => {
- if (!email) navigate("/");
-
- if (!builderSocket) return;
-
- builderSocket.on("userConnectResponse", (data: any) => {
- if (!groupRef.current) return;
- if (data.data.userData.email === email) return;
- if (builderSocket.id === data.socketId || organization !== data.organization) return;
-
- 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;
- newModel.userData.target = new THREE.Vector3(data.data.target.x, data.data.target.y, data.data.target.z);
-
- setCams((prev) => dedupeCams([...prev, newModel]));
- setActiveUsers((prev: any) => dedupeUsers([...prev, data.data.userData]));
- });
- });
-
- builderSocket.on("userDisConnectResponse", (data: any) => {
- if (!groupRef.current) return;
- if (builderSocket.id === data.socketId || organization !== data.organization) return;
-
- setCams((prev) => prev.filter((cam) => cam.uuid !== data.data.userData._id));
- setActiveUsers((prev: any) => prev.filter((user: any) => user._id !== data.data.userData._id));
- });
-
- builderSocket.on("v1:camera:Response:update", (data: any) => {
- if (!groupRef.current || builderSocket.id === data.socketId || organization !== data.organization) return;
-
- if (selectedUser && selectedUser?.id === data.data.userId) {
- setSelectedUser({
- color: selectedUser.color,
- name: selectedUser.name,
- id: selectedUser.id,
- location: {
- position: data.data.position,
- rotation: data.data.rotation,
- target: data.data.target,
- },
- });
- }
- 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),
- target: new THREE.Vector3(data.data.target.x, data.data.target.y, data.data.target.z),
- },
- }));
- });
-
- return () => {
- builderSocket.off("userConnectResponse");
- builderSocket.off("userDisConnectResponse");
- builderSocket.off("v1:camera:Response:update");
- };
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [email, loader, navigate, setActiveUsers, builderSocket]);
-
- useFrame(() => {
- if (!groupRef.current) return;
- Object.keys(models).forEach((uuid) => {
- const model = groupRef.current!.getObjectByProperty("uuid", uuid);
- if (!model) return;
-
- 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;
-
- 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;
- cam.userData.position = newModel.position;
- cam.userData.rotation = newModel.rotation;
- newModel.userData.target = cam.target;
-
- return newModel;
- });
-
- const users = filteredData.map((cam: any) => cam.userData);
- setActiveUsers((prev: any) => dedupeUsers([...prev, ...users]));
- setCams((prev) => dedupeCams([...prev, ...newCams]));
- });
- }
- })
- .catch(() => {
- console.log("Error fetching active users data");
- });
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ const { collabUsersStore } = useSceneContext();
+ const { collabUsers } = collabUsersStore();
+ const model: any = useGLTF(camModel);
+ const { userId: currentUserId } = getUserData();
return (
-
- {cams.map((cam, index) => (
-
-
-
-
-
- ))}
+
+ {collabUsers
+ .filter((user) => user.userId !== currentUserId)
+ .map((user, index) => (
+
+ ))}
+
+ );
+};
+
+const CamModel = ({ user, model, index }: { user: CollabUsersScheme; model: THREE.Object3D; index: number }) => {
+ const ref = useRef(null);
+
+ const targetPos = new THREE.Vector3();
+ const targetQuat = new THREE.Quaternion();
+
+ useFrame((_, delta) => {
+ if (ref.current) {
+ targetPos.set(user.camData.position.x, user.camData.position.y, user.camData.position.z);
+
+ targetQuat.setFromEuler(new THREE.Euler(user.camData.rotation.x, user.camData.rotation.y, user.camData.rotation.z));
+
+ ref.current.position.lerp(targetPos, 5 * delta);
+ ref.current.quaternion.slerp(targetQuat, 5 * delta);
+ }
+ });
+
+ return (
+
+
+
+
+
);
};
diff --git a/app/src/modules/collaboration/socket/threadSocketResponses.dev.tsx b/app/src/modules/collaboration/socket/threadSocketResponses.dev.tsx
index d4fb12f..abdb38f 100644
--- a/app/src/modules/collaboration/socket/threadSocketResponses.dev.tsx
+++ b/app/src/modules/collaboration/socket/threadSocketResponses.dev.tsx
@@ -16,7 +16,7 @@ const ThreadSocketResponsesDev = ({ setMessages, modeRef, messages }: ThreadSock
const { threadSocket } = useSocketStore();
const { selectedComment, setSelectedComment, setCommentPositionState, commentPositionState } = useSelectedComment();
const { threadStore } = useSceneContext();
- const { threads, removeReply, addComment, addReply, updateComment, updateReply } = threadStore();
+ const { threads, removeReply, addThread, addReply, updateThread, updateReply } = threadStore();
const { userId } = getUserData();
useEffect(() => {
@@ -98,7 +98,7 @@ const ThreadSocketResponsesDev = ({ setMessages, modeRef, messages }: ThreadSock
comments: [],
};
setSelectedComment(comment);
- addComment(comment);
+ addThread(comment);
setCommentPositionState(null);
// setSelectedComment(null);
};
@@ -128,7 +128,7 @@ const ThreadSocketResponsesDev = ({ setMessages, modeRef, messages }: ThreadSock
};
//
- updateComment(data.data?._id, editedThread);
+ updateThread(data.data?._id, editedThread);
setSelectedComment(editedThread);
// setSelectedComment(null);
diff --git a/app/src/modules/collaboration/socket/userResponses.tsx b/app/src/modules/collaboration/socket/userResponses.tsx
index 1135903..cd0b24b 100644
--- a/app/src/modules/collaboration/socket/userResponses.tsx
+++ b/app/src/modules/collaboration/socket/userResponses.tsx
@@ -1,8 +1,29 @@
import { useEffect } from "react";
import { useSocketStore } from "../../../store/socket/useSocketStore";
+import { useSceneContext } from "../../scene/sceneContext";
function UserResponses() {
const { builderSocket } = useSocketStore();
+ const { collabUsersStore } = useSceneContext();
+ const { setCollabUsers } = collabUsersStore();
+
+ //#region Users
+ useEffect(() => {
+ if (!builderSocket) return;
+
+ builderSocket.on("v1:room:userDatas", (data: any) => {
+ if (!data?.data?.UsersDetails || data.data.UsersDetails.length === 0) return;
+ console.log("data: ", data.data.UsersDetails);
+ setCollabUsers(data.data.UsersDetails);
+ });
+
+ return () => {
+ if (builderSocket) {
+ builderSocket.off("v1:room:userDatas");
+ }
+ };
+ }, [builderSocket]);
+ //#endregion
//#region Camera
useEffect(() => {
@@ -10,9 +31,6 @@ function UserResponses() {
builderSocket.on("v1:camera:Response:update", (data: any) => {
if (!data.message) return;
- if (data.message === "Model created successfully") {
- } else if (data.message === "Updated successfully") {
- }
});
return () => {
diff --git a/app/src/modules/collaboration/threads/threadInstances/threadInstances.tsx b/app/src/modules/collaboration/threads/threadInstances/threadInstances.tsx
index 92771dc..131c098 100644
--- a/app/src/modules/collaboration/threads/threadInstances/threadInstances.tsx
+++ b/app/src/modules/collaboration/threads/threadInstances/threadInstances.tsx
@@ -10,7 +10,7 @@ function ThreadInstances() {
const { projectId } = useParams();
const { userId } = getUserData();
const { versionStore, threadStore } = useSceneContext();
- const { threads, setComments } = threadStore();
+ const { threads, setThreads } = threadStore();
const { selectedVersion } = versionStore();
useEffect(() => {
@@ -36,7 +36,7 @@ function ThreadInstances() {
: [],
}))
: [];
- setComments(formattedThreads);
+ setThreads(formattedThreads);
})
.catch((err) => {
console.error("Failed to fetch threads:", err);
diff --git a/app/src/modules/scene/controls/controls.tsx b/app/src/modules/scene/controls/controls.tsx
index c1c52cb..7389bd6 100644
--- a/app/src/modules/scene/controls/controls.tsx
+++ b/app/src/modules/scene/controls/controls.tsx
@@ -82,7 +82,7 @@ export default function Controls() {
setResetCamera(false);
}
- }, [resetCamera]);
+ }, [resetCamera, builderSocket, projectId]);
useEffect(() => {
controlsRef.current?.setBoundary(new THREE.Box3(new THREE.Vector3(...CONSTANTS.threeDimension.boundaryBottom), new THREE.Vector3(...CONSTANTS.threeDimension.boundaryTop)));
diff --git a/app/src/modules/scene/sceneContext.tsx b/app/src/modules/scene/sceneContext.tsx
index dd2b6fe..34d1ca2 100644
--- a/app/src/modules/scene/sceneContext.tsx
+++ b/app/src/modules/scene/sceneContext.tsx
@@ -24,7 +24,9 @@ import { createStorageUnitStore, StorageUnitStoreType } from "../../store/simula
import { createHumanStore, HumanStoreType } from "../../store/simulation/useHumanStore";
import { createCraneStore, CraneStoreType } from "../../store/simulation/useCraneStore";
-import { createThreadsStore, ThreadStoreType } from "../../store/collaboration/useCommentStore";
+import { createThreadsStore, ThreadStoreType } from "../../store/collaboration/useThreadStore";
+
+import { createCollabusersStore, CollabUsersStoreType } from "../../store/collaboration/useCollabUsersStore";
type SceneContextValue = {
versionStore: VersionStoreType;
@@ -53,6 +55,8 @@ type SceneContextValue = {
threadStore: ThreadStoreType;
+ collabUsersStore: CollabUsersStoreType;
+
humanEventManagerRef: React.RefObject;
craneEventManagerRef: React.RefObject;
@@ -90,6 +94,8 @@ export function SceneProvider({ children, layout }: { readonly children: React.R
const threadStore = useMemo(() => createThreadsStore(), []);
+ const collabUsersStore = useMemo(() => createCollabusersStore(), []);
+
const humanEventManagerRef = useRef({ humanStates: [] });
const craneEventManagerRef = useRef({ craneStates: [] });
@@ -114,7 +120,8 @@ export function SceneProvider({ children, layout }: { readonly children: React.R
storageUnitStore.getState().clearStorageUnits();
humanStore.getState().clearHumans();
craneStore.getState().clearCranes();
- threadStore.getState().clearComments();
+ threadStore.getState().clearThreads();
+ collabUsersStore.getState().clearCollabUsers();
humanEventManagerRef.current.humanStates = [];
craneEventManagerRef.current.craneStates = [];
},
@@ -139,6 +146,7 @@ export function SceneProvider({ children, layout }: { readonly children: React.R
humanStore,
craneStore,
threadStore,
+ collabUsersStore,
]
);
@@ -164,6 +172,7 @@ export function SceneProvider({ children, layout }: { readonly children: React.R
humanStore,
craneStore,
threadStore,
+ collabUsersStore,
humanEventManagerRef,
craneEventManagerRef,
clearStores,
@@ -190,6 +199,7 @@ export function SceneProvider({ children, layout }: { readonly children: React.R
humanStore,
craneStore,
threadStore,
+ collabUsersStore,
clearStores,
layout,
]
diff --git a/app/src/pages/Dashboard.tsx b/app/src/pages/Dashboard.tsx
index f5c6a5f..bf587f5 100644
--- a/app/src/pages/Dashboard.tsx
+++ b/app/src/pages/Dashboard.tsx
@@ -13,7 +13,7 @@ const Dashboard: React.FC = () => {
const token = localStorage.getItem("token");
const refreshToken = localStorage.getItem("refreshToken");
if (token && refreshToken) {
- useSocketStore.getState().initializeDashBoardSocket(token, refreshToken);
+ useSocketStore.getState().initializeProjectSocket(token, refreshToken);
}
}, [email, organization]);
diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx
index 0126105..a1550ee 100644
--- a/app/src/pages/Project.tsx
+++ b/app/src/pages/Project.tsx
@@ -24,7 +24,17 @@ const Project: React.FC = () => {
let navigate = useNavigate();
const echo = useLogger();
const { setActiveModule } = useModuleStore();
- const { initializeBuilderSocket, initializeVisualizationSocket, initializeThreadSocket, disconnectBuilderSocket, disconnectVisualizationSocket, disconnectThreadSocket } = useSocketStore();
+ const {
+ builderSocket,
+ visualizationSocket,
+ threadSocket,
+ initializeBuilderSocket,
+ initializeVisualizationSocket,
+ initializeThreadSocket,
+ disconnectBuilderSocket,
+ disconnectVisualizationSocket,
+ disconnectThreadSocket,
+ } = useSocketStore();
const { projectId } = useParams();
const { setProjectName } = useProjectName();
const { userId, email } = getUserData();
@@ -33,6 +43,7 @@ const Project: React.FC = () => {
const { activeTool } = useActiveTool();
useEffect(() => {
+ setActiveModule("builder");
if (!email || !userId) {
console.error("User data not found in localStorage");
navigate("/page-not-found");
@@ -64,30 +75,65 @@ const Project: React.FC = () => {
}, [projectId]);
useEffect(() => {
- setActiveModule("builder");
- if (email) {
- const token = localStorage.getItem("token");
- const refreshToken = localStorage.getItem("refreshToken");
+ const token = localStorage.getItem("token");
+ const refreshToken = localStorage.getItem("refreshToken");
+
+ if (token && refreshToken && projectId) {
echo.warn("Validating token");
- if (token && refreshToken && projectId) {
- initializeBuilderSocket(token, refreshToken, projectId);
- initializeVisualizationSocket(token, refreshToken, projectId);
- initializeThreadSocket(token, refreshToken, projectId);
- }
- echo.success("Project initialized and loaded successfully");
+ initializeBuilderSocket(token, refreshToken, projectId);
+ echo.success("Builder socket initialized");
} else {
navigate("/");
+ return;
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
return () => {
- if (projectId) {
+ if (projectId && builderSocket) {
disconnectBuilderSocket(projectId);
+ }
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [projectId, builderSocket]);
+
+ useEffect(() => {
+ const token = localStorage.getItem("token");
+ const refreshToken = localStorage.getItem("refreshToken");
+
+ if (token && refreshToken && projectId) {
+ initializeVisualizationSocket(token, refreshToken, projectId);
+ echo.success("Visualization socket initialized");
+ } else {
+ navigate("/");
+ return;
+ }
+
+ return () => {
+ if (projectId && visualizationSocket) {
disconnectVisualizationSocket(projectId);
+ }
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [projectId, visualizationSocket]);
+
+ useEffect(() => {
+ const token = localStorage.getItem("token");
+ const refreshToken = localStorage.getItem("refreshToken");
+
+ if (token && refreshToken && projectId) {
+ initializeThreadSocket(token, refreshToken, projectId);
+ echo.success("Thread socket initialized");
+ } else {
+ navigate("/");
+ return;
+ }
+
+ return () => {
+ if (projectId && threadSocket) {
disconnectThreadSocket(projectId);
}
};
- }, [projectId]);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [projectId, threadSocket]);
useEffect(() => {
handleCanvasCursors(activeTool);
diff --git a/app/src/services/factoryBuilder/collab/comments/addCommentApi.ts b/app/src/services/factoryBuilder/collab/comments/addCommentApi.ts
index b44506c..db3e2ef 100644
--- a/app/src/services/factoryBuilder/collab/comments/addCommentApi.ts
+++ b/app/src/services/factoryBuilder/collab/comments/addCommentApi.ts
@@ -2,7 +2,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR
export const addCommentsApi = async (projectId: any, comment: string, threadId: string, versionId: string) => {
try {
- const response = await fetch(`${url_Backend_dwinzo}/api/V1/Thread/addComment`, {
+ const response = await fetch(`${url_Backend_dwinzo}/api/V1/Thread/addThread`, {
method: "POST",
headers: {
Authorization: "Bearer ",
diff --git a/app/src/services/factoryBuilder/collab/comments/editCommentApi.ts b/app/src/services/factoryBuilder/collab/comments/editCommentApi.ts
index 3166356..f3c2527 100644
--- a/app/src/services/factoryBuilder/collab/comments/editCommentApi.ts
+++ b/app/src/services/factoryBuilder/collab/comments/editCommentApi.ts
@@ -2,7 +2,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR
export const editCommentsApi = async (projectId: any, comment: string, commentId: string, threadId: string, versionId: string) => {
try {
- const response = await fetch(`${url_Backend_dwinzo}/api/V1/Thread/addComment`, {
+ const response = await fetch(`${url_Backend_dwinzo}/api/V1/Thread/addThread`, {
method: "POST",
headers: {
Authorization: "Bearer ",
diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts
index 7030d51..e051768 100644
--- a/app/src/store/builder/store.ts
+++ b/app/src/store/builder/store.ts
@@ -145,14 +145,6 @@ export const useDrieTemp = create((set: any) => ({
setDrieTemp: (x: any) => set({ drieTemp: x }),
}));
-export const useActiveUsers = create((set: any) => ({
- activeUsers: [],
- setActiveUsers: (callback: (prev: any[]) => any[] | any[]) =>
- set((state: { activeUsers: any[] }) => ({
- activeUsers: typeof callback === "function" ? callback(state.activeUsers) : callback,
- })),
-}));
-
export const useDrieUIValue = create((set: any) => ({
drieUIValue: { touch: null, temperature: null, humidity: null },
diff --git a/app/src/store/collaboration/useCollabUsersStore.ts b/app/src/store/collaboration/useCollabUsersStore.ts
new file mode 100644
index 0000000..987dd83
--- /dev/null
+++ b/app/src/store/collaboration/useCollabUsersStore.ts
@@ -0,0 +1,50 @@
+import { create } from "zustand";
+import { immer } from "zustand/middleware/immer";
+
+interface CollabUsersStore {
+ collabUsers: CollabUsersScheme[];
+
+ addCollabUser: (user: CollabUsersScheme) => void;
+ updateCollabUser: (userId: string, updates: Partial) => void;
+ setCollabUsers: (users: CollabUsersScheme[]) => void;
+ removeCollabUser: (userId: string) => void;
+ clearCollabUsers: () => void;
+}
+
+export const createCollabusersStore = () => {
+ return create()(
+ immer((set) => ({
+ collabUsers: [],
+
+ addCollabUser: (user) =>
+ set((state) => {
+ state.collabUsers.push(user);
+ }),
+
+ updateCollabUser: (userId, updates) =>
+ set((state) => {
+ const idx = state.collabUsers.findIndex((u) => u.userId === userId);
+ if (idx !== -1) {
+ Object.assign(state.collabUsers[idx], updates);
+ }
+ }),
+
+ setCollabUsers: (users) =>
+ set((state) => {
+ state.collabUsers = users;
+ }),
+
+ removeCollabUser: (userId) =>
+ set((state) => {
+ state.collabUsers = state.collabUsers.filter((u) => u.userId !== userId);
+ }),
+
+ clearCollabUsers: () =>
+ set((state) => {
+ state.collabUsers = [];
+ }),
+ }))
+ );
+};
+
+export type CollabUsersStoreType = ReturnType;
diff --git a/app/src/store/collaboration/useCommentStore.ts b/app/src/store/collaboration/useThreadStore.ts
similarity index 82%
rename from app/src/store/collaboration/useCommentStore.ts
rename to app/src/store/collaboration/useThreadStore.ts
index a8c068a..ed29e2f 100644
--- a/app/src/store/collaboration/useCommentStore.ts
+++ b/app/src/store/collaboration/useThreadStore.ts
@@ -4,17 +4,17 @@ import { immer } from "zustand/middleware/immer";
interface ThreadStore {
threads: ThreadsSchema;
- addComment: (thread: ThreadSchema) => void;
- setComments: (threads: ThreadsSchema) => void;
- updateComment: (threadId: string, updates: Partial) => void;
- removeComment: (threadId: string) => void;
- clearComments: () => void;
+ addThread: (thread: ThreadSchema) => void;
+ setThreads: (threads: ThreadsSchema) => void;
+ updateThread: (threadId: string, updates: Partial) => void;
+ removeThread: (threadId: string) => void;
+ clearThreads: () => void;
addReply: (threadId: string, reply: Reply) => void;
updateReply: (threadId: string, replyId: string, updates: Partial) => void;
removeReply: (threadId: string, _id: string) => void;
- getCommentById: (threadId: string) => ThreadSchema | undefined;
+ getThreadById: (threadId: string) => ThreadSchema | undefined;
}
export const createThreadsStore = () => {
@@ -22,7 +22,7 @@ export const createThreadsStore = () => {
immer((set, get) => ({
threads: [],
- addComment: (thread) => {
+ addThread: (thread) => {
set((state) => {
if (!state.threads.find((c) => c.threadId === thread.threadId)) {
state.threads.push(JSON.parse(JSON.stringify(thread)));
@@ -30,13 +30,13 @@ export const createThreadsStore = () => {
});
},
- setComments: (threads) => {
+ setThreads: (threads) => {
set((state) => {
state.threads = threads;
});
},
- updateComment: (threadId, updates) => {
+ updateThread: (threadId, updates) => {
set((state) => {
const thread = state.threads.find((c) => c.threadId === threadId);
if (thread) {
@@ -45,13 +45,13 @@ export const createThreadsStore = () => {
});
},
- removeComment: (threadId) => {
+ removeThread: (threadId) => {
set((state) => {
state.threads = state.threads.filter((c) => c.threadId !== threadId);
});
},
- clearComments: () => {
+ clearThreads: () => {
set((state) => {
state.threads = [];
});
@@ -87,7 +87,7 @@ export const createThreadsStore = () => {
});
},
- getCommentById: (threadId) => {
+ getThreadById: (threadId) => {
return get().threads.find((c) => c.threadId === threadId);
},
}))
diff --git a/app/src/store/socket/useSocketStore.ts b/app/src/store/socket/useSocketStore.ts
index 53dd34b..333f252 100644
--- a/app/src/store/socket/useSocketStore.ts
+++ b/app/src/store/socket/useSocketStore.ts
@@ -4,98 +4,104 @@ import { io, Socket } from "socket.io-client";
interface SocketStore {
builderSocket: Socket | null;
visualizationSocket: Socket | null;
- dashBoardSocket: Socket | null;
projectSocket: Socket | null;
threadSocket: Socket | null;
initializeBuilderSocket: (token: string, refreshToken: string, projectId: string) => void;
initializeVisualizationSocket: (token: string, refreshToken: string, projectId: string) => void;
initializeThreadSocket: (token: string, refreshToken: string, projectId: string) => void;
- initializeDashBoardSocket: (token: string, refreshToken: string) => void;
initializeProjectSocket: (token: string, refreshToken: string) => void;
disconnectBuilderSocket: (projectId: string) => void;
disconnectVisualizationSocket: (projectId: string) => void;
disconnectThreadSocket: (projectId: string) => void;
- disconnectDashBoardSocket: () => void;
disconnectProjectSocket: () => void;
disconnectAll: (projectId?: string) => void;
}
+const socketOptions = (auth: any) => ({
+ reconnection: true,
+ reconnectionAttempts: Infinity,
+ reconnectionDelay: 2000,
+ timeout: 10000,
+ auth,
+});
+
+const attachLogs = (name: string, socket: Socket) => {
+ socket.on("connect", () => {
+ // console.log(`${name} socket connected:`, socket.id);
+ });
+
+ socket.on("disconnect", (reason) => {
+ // console.warn(`${name} socket disconnected:`, reason);
+ });
+
+ socket.on("error", (err) => {
+ // console.error(`${name} socket error:`, err);
+ });
+
+ socket.on("connect_error", (err) => {
+ console.warn(`${name} socket connection failed:`, err.message);
+ });
+};
+
export const useSocketStore = create((set, get) => ({
builderSocket: null,
visualizationSocket: null,
- dashBoardSocket: null,
projectSocket: null,
threadSocket: null,
initializeBuilderSocket: (token, refreshToken, projectId) => {
if (get().builderSocket) return;
- const builderSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder_v1`, {
- reconnection: true,
- auth: { token, refreshToken, projectId },
- });
+ const builderSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder_v1`, socketOptions({ token, refreshToken, projectId }));
+ attachLogs("Builder", builderSocket);
set({ builderSocket });
},
initializeVisualizationSocket: (token, refreshToken, projectId) => {
if (get().visualizationSocket) return;
- const visualizationSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization_v1`, {
- reconnection: true,
- auth: { token, refreshToken, projectId },
- });
+ const visualizationSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization_v1`, socketOptions({ token, refreshToken, projectId }));
+ attachLogs("Visualization", visualizationSocket);
set({ visualizationSocket });
},
initializeThreadSocket: (token, refreshToken, projectId) => {
if (get().threadSocket) return;
- const threadSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/thread`, {
- reconnection: true,
- auth: { token, refreshToken, projectId },
- });
+ const threadSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/thread`, socketOptions({ token, refreshToken, projectId }));
+ attachLogs("Thread", threadSocket);
set({ threadSocket });
},
- initializeDashBoardSocket: (token, refreshToken) => {
- if (get().dashBoardSocket) return;
- const dashBoardSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`, {
- reconnection: true,
- auth: { token, refreshToken },
- });
- set({ dashBoardSocket });
- },
-
initializeProjectSocket: (token, refreshToken) => {
if (get().projectSocket) return;
- const projectSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`, {
- reconnection: true,
- auth: { token, refreshToken },
- });
+ const projectSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`, socketOptions({ token, refreshToken }));
+ attachLogs("Project", projectSocket);
set({ projectSocket });
},
disconnectBuilderSocket: (projectId) => {
get().builderSocket?.emit("leaveRoom", { projectId });
- get().builderSocket?.disconnect();
- set({ builderSocket: null });
+ setTimeout(() => {
+ get().builderSocket?.disconnect();
+ set({ builderSocket: null });
+ }, 1000);
},
disconnectVisualizationSocket: (projectId) => {
get().visualizationSocket?.emit("leaveRoom", { projectId });
- get().visualizationSocket?.disconnect();
- set({ visualizationSocket: null });
+ setTimeout(() => {
+ get().visualizationSocket?.disconnect();
+ set({ visualizationSocket: null });
+ }, 1000);
},
disconnectThreadSocket: (projectId) => {
get().threadSocket?.emit("leaveRoom", { projectId });
- get().threadSocket?.disconnect();
- set({ threadSocket: null });
- },
-
- disconnectDashBoardSocket: () => {
- get().dashBoardSocket?.disconnect();
- set({ dashBoardSocket: null });
+ setTimeout(() => {
+ get().threadSocket?.disconnect();
+ set({ threadSocket: null });
+ }, 1000);
},
disconnectProjectSocket: () => {
@@ -108,16 +114,16 @@ export const useSocketStore = create((set, get) => ({
get().visualizationSocket?.emit("leaveRoom", { projectId });
get().threadSocket?.emit("leaveRoom", { projectId });
- get().builderSocket?.disconnect();
- get().visualizationSocket?.disconnect();
- get().dashBoardSocket?.disconnect();
- get().projectSocket?.disconnect();
- get().threadSocket?.disconnect();
+ setTimeout(() => {
+ get().builderSocket?.disconnect();
+ get().visualizationSocket?.disconnect();
+ get().projectSocket?.disconnect();
+ get().threadSocket?.disconnect();
+ }, 1000);
set({
builderSocket: null,
visualizationSocket: null,
- dashBoardSocket: null,
projectSocket: null,
threadSocket: null,
});
diff --git a/app/src/types/collaborationTypes.d.ts b/app/src/types/collaborationTypes.d.ts
index 8de989d..10315bc 100644
--- a/app/src/types/collaborationTypes.d.ts
+++ b/app/src/types/collaborationTypes.d.ts
@@ -1,3 +1,18 @@
+//#region CollllabUsersData
+interface CollabUsersScheme {
+ userId: string;
+ userName: string;
+ projectId: string;
+ versionId: string;
+ camData: {
+ position: { x: number; y: number; z: number };
+ rotation: { x: number; y: number; z: number };
+ target: { x: number; y: number; z: number };
+ };
+}
+//#endregion
+
+//#region Thread
interface ThreadSchema {
state: "active" | "inactive";
threadId: string;
@@ -19,3 +34,4 @@ interface Reply {
}
type ThreadsSchema = ThreadSchema[];
+//#endregion