diff --git a/app/package-lock.json b/app/package-lock.json index d3aa21e..f627d25 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -4133,25 +4133,6 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@testing-library/dom": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", - "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@testing-library/jest-dom": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", diff --git a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx index 1f1e61c..ef710f7 100644 --- a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx @@ -5,7 +5,6 @@ const Templates = () => { const { templates, removeTemplate } = useTemplateStore(); const { setSelectedZone } = useSelectedZoneStore(); - console.log("templates: ", templates); const handleDeleteTemplate = (id: string) => { removeTemplate(id); }; diff --git a/app/src/components/layout/sidebarRight/Header.tsx b/app/src/components/layout/sidebarRight/Header.tsx index b80fd53..b4983c6 100644 --- a/app/src/components/layout/sidebarRight/Header.tsx +++ b/app/src/components/layout/sidebarRight/Header.tsx @@ -1,14 +1,17 @@ -import React from "react"; +import React, { useEffect } from "react"; import { AppDockIcon } from "../../icons/HeaderIcons"; -import orgImg from "../../../assets/orgTemp.png" +import orgImg from "../../../assets/orgTemp.png"; +import { useActiveUsers } from "../../../store/store"; +import { getAvatarColor } from "../../../modules/collaboration/users/functions/getAvatarColor"; +import { ActiveUser } from "../../../types/users"; const Header: React.FC = () => { - const guestUsers = [ - { value: "Nazria", color: "#43C06D" }, - { value: "Name1", color: "#0050EB" }, - { value: "Abigail", color: "#FF6600" }, - { value: "Jack", color: "#488EF6" }, - ]; // Example guest users array + const { activeUsers } = useActiveUsers(); + const userName = localStorage.getItem("userName") || "Anonymous"; + + const guestUsers: ActiveUser[] = activeUsers.filter( + (user: ActiveUser) => user.userName !== userName + ); return (
@@ -25,18 +28,23 @@ const Header: React.FC = () => {
+{guestUsers.length - 3}
)} {guestUsers.slice(0, 3).map((user, index) => ( -
- {user.value[0]} -
+ <> +
+ {user.userName[0]} +
+ ))}
-
- V +
+ {userName[0]}
diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index f2f6695..4821772 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -14,7 +14,10 @@ import ConveyorMechanics from "./mechanics/ConveyorMechanics"; import Visualization from "./visualization/Visualization"; import Analysis from "./analysis/Analysis"; import Simulations from "./simulation/Simulations"; -import { useSelectedActionSphere } from "../../../store/store"; +import { + useSelectedActionSphere, + useselectedFloorItem, +} from "../../../store/store"; import GlobalProperties from "./properties/GlobalProperties"; import AsstePropertiies from "./properties/AssetProperties"; import ZoneProperties from "./properties/ZoneProperties"; @@ -25,6 +28,7 @@ const SideBarRight: React.FC = () => { const { toggleUI } = useToggleStore(); const { selectedActionSphere } = useSelectedActionSphere(); const { subModule, setSubModule } = useSubModuleStore(); + const { selectedFloorItem } = useselectedFloorItem(); // Reset activeList whenever activeModule changes useEffect(() => { if (activeModule !== "simulation") setSubModule("properties"); @@ -38,8 +42,9 @@ const SideBarRight: React.FC = () => {
{/* {activeModule === "builder" && ( */}
setSubModule("properties")} > @@ -48,22 +53,25 @@ const SideBarRight: React.FC = () => { {activeModule === "simulation" && ( <>
setSubModule("mechanics")} >
setSubModule("simulations")} >
setSubModule("analysis")} > @@ -75,12 +83,21 @@ const SideBarRight: React.FC = () => { {/* process builder */} {toggleUI && subModule === "properties" && - activeModule !== "visualization" && ( + activeModule !== "visualization" && + !selectedFloorItem && (
- {/* */} - {/* */} +
+
+ )} + {toggleUI && + subModule === "properties" && + activeModule !== "visualization" && + selectedFloorItem && ( +
+
+
)} @@ -89,9 +106,7 @@ const SideBarRight: React.FC = () => { activeModule === "builder" && (
- {/* */} - {/* */}
)} @@ -99,20 +114,24 @@ const SideBarRight: React.FC = () => { {toggleUI && activeModule === "simulation" && ( <> - {subModule === "mechanics" && selectedActionSphere && selectedActionSphere.path.type === "Conveyor" && ( -
-
- + {subModule === "mechanics" && + selectedActionSphere && + selectedActionSphere.path.type === "Conveyor" && ( +
+
+ +
-
- )} - {subModule === "mechanics" && selectedActionSphere && selectedActionSphere.path.type === "Vehicle" && ( -
-
- + )} + {subModule === "mechanics" && + selectedActionSphere && + selectedActionSphere.path.type === "Vehicle" && ( +
+
+ +
-
- )} + )} {subModule === "mechanics" && !selectedActionSphere && (
diff --git a/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx b/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx index b65d782..881e225 100644 --- a/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx +++ b/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx @@ -4,12 +4,16 @@ interface PositionInputProps { onChange: (value: string) => void; // Callback for value change placeholder?: string; // Optional placeholder type?: string; // Input type (e.g., text, number, email) + value1?: number; + value2?: number; } const PositionInput: React.FC = ({ onChange, placeholder = "Enter value", // Default placeholder type = "number", // Default type + value1 = "number", + value2 = "number", }) => { return (
@@ -22,6 +26,7 @@ const PositionInput: React.FC = ({ type={type} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} + value={value2} />
@@ -31,6 +36,7 @@ const PositionInput: React.FC = ({ type={type} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} + value={value1} />
diff --git a/app/src/components/layout/sidebarRight/customInput/RotationInput.tsx b/app/src/components/layout/sidebarRight/customInput/RotationInput.tsx index 3ab01a4..962e967 100644 --- a/app/src/components/layout/sidebarRight/customInput/RotationInput.tsx +++ b/app/src/components/layout/sidebarRight/customInput/RotationInput.tsx @@ -4,17 +4,19 @@ interface RotationInputProps { onChange: (value: string) => void; // Callback for value change placeholder?: string; // Optional placeholder type?: string; // Input type (e.g., text, number, email) + value?: number; } const RotationInput: React.FC = ({ onChange, placeholder = "Enter value", // Default placeholder type = "number", // Default type + value = "number", }) => { return (
Rotation
-
+
Rotate :
= ({ type={type} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} + value={value} />
diff --git a/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx b/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx index 8309024..c47fd81 100644 --- a/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx @@ -1,9 +1,11 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import InputToggle from "../../../ui/inputs/InputToggle"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; import { RemoveIcon } from "../../../icons/ExportCommonIcons"; import PositionInput from "../customInput/PositionInputs"; import RotationInput from "../customInput/RotationInput"; +import { useselectedFloorItem } from "../../../../store/store"; +import * as THREE from "three"; interface UserData { id: number; // Unique identifier for the user data @@ -14,7 +16,13 @@ interface UserData { const AssetProperties: React.FC = () => { const [userData, setUserData] = useState([]); // State to track user data const [nextId, setNextId] = useState(1); // Unique ID for new entries + const { selectedFloorItem } = useselectedFloorItem(); + let xValue = selectedFloorItem.position.x; + let zValue = selectedFloorItem.position.z; + let rotationRad = selectedFloorItem.rotation.y; + let rotationDeg = THREE.MathUtils.radToDeg(rotationRad); + // useEffect(() => {}, [selectedFloorItem]); // Function to handle adding new user data const handleAddUserData = () => { const newUserData: UserData = { @@ -45,12 +53,16 @@ const AssetProperties: React.FC = () => { return (
{/* Name */} -
Selected Object
+
{selectedFloorItem.userData.name}
- { }} /> - { }} /> + {}} + value1={xValue.toFixed(5)} + value2={zValue.toFixed(5)} + /> + {}} value={rotationDeg} />
diff --git a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx index 672d847..633b144 100644 --- a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx @@ -3,8 +3,31 @@ import InputRange from "../../../ui/inputs/InputRange"; import InputToggle from "../../../ui/inputs/InputToggle"; import { AI_Icon } from "../../../icons/ExportCommonIcons"; import LabeledButton from "../../../ui/inputs/LabledButton"; +import { + useAzimuth, + useElevation, + useRenderDistance, + useResetCamera, + useRoofVisibility, + useSelectedWallItem, + useShadows, + useSocketStore, + useToggleView, + useWallVisibility, +} from "../../../../store/store"; +import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment"; const GlobalProperties: React.FC = () => { + const { toggleView, setToggleView } = useToggleView(); + const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); + const { roofVisibility, setRoofVisibility } = useRoofVisibility(); + const { wallVisibility, setWallVisibility } = useWallVisibility(); + const { shadows, setShadows } = useShadows(); + const { resetCamera, setResetCamera } = useResetCamera(); + const { elevation, setElevation } = useElevation(); + const { azimuth, setAzimuth } = useAzimuth(); + const { renderDistance, setRenderDistance } = useRenderDistance(); + const { socket } = useSocketStore(); const [limitDistance, setLimitDistance] = useState(false); const [distance, setDistance] = useState(5); @@ -23,6 +46,93 @@ const GlobalProperties: React.FC = () => { function updateGridDistance(value: number) { setGridDistance(value); } + // Function to toggle roof visibility + const changeRoofVisibility = async () => { + const email = localStorage.getItem("email"); + const organization = email!.split("@")[1].split(".")[0]; + + //using REST + const data = await setEnvironment( + organization, + localStorage.getItem("userId")!, + wallVisibility, + !roofVisibility, + shadows + ); + // console.log('data: ', data); + + //using Socket + // const visData = { + // organization: organization, + // userId: localStorage.getItem('userId')!, + // wallVisibility: wallVisibility, + // roofVisibility: !roofVisibility, + // shadowVisibility: shadows, + // socketId: socket.id + // }; + // socket.emit('v1:Environment:set', visData) + + setRoofVisibility(!roofVisibility); // Toggle roof visibility + }; + // Function to toggle wall visibility + const changeWallVisibility = async () => { + const email = localStorage.getItem("email"); + const organization = email!.split("@")[1].split(".")[0]; + //using REST + const data = await setEnvironment( + organization, + localStorage.getItem("userId")!, + !wallVisibility, + roofVisibility, + shadows + ); + // console.log('data: ', data); + + //using Socket + // const visData = { + // organization: organization, + // userId: localStorage.getItem('userId')!, + // wallVisibility: !wallVisibility, + // roofVisibility: roofVisibility, + // shadowVisibility: shadows, + // socketId: socket.id + // }; + // socket.emit('v1:Environment:set', visData) + + setWallVisibility(!wallVisibility); // Toggle wall visibility + }; + + const shadowVisibility = async () => { + const email = localStorage.getItem("email"); + const organization = email!.split("@")[1].split(".")[0]; + //using REST + const data = await setEnvironment( + organization, + localStorage.getItem("userId")!, + wallVisibility, + roofVisibility, + !shadows + ); + // console.log('data: ', data); + + //using Socket + // const visData = { + // organization: organization, + // userId: localStorage.getItem('userId')!, + // wallVisibility: wallVisibility, + // roofVisibility: roofVisibility, + // shadowVisibility: !shadows, + // socketId: socket.id + // }; + // socket.emit('v1:Environment:set', visData) + + setShadows(!shadows); + }; + const toggleResetCamera = () => { + if (!toggleView) { + setResetCamera(true); // Trigger reset camera action + } + }; return (
@@ -34,10 +144,29 @@ const GlobalProperties: React.FC = () => {
- - - - {}} value="Reset"/> + + + +
diff --git a/app/src/components/ui/componets/DisplayZone.tsx b/app/src/components/ui/componets/DisplayZone.tsx index dafddba..a321836 100644 --- a/app/src/components/ui/componets/DisplayZone.tsx +++ b/app/src/components/ui/componets/DisplayZone.tsx @@ -166,8 +166,10 @@ const DisplayZone: React.FC = ({ return (
{/* Left Arrow */} {showLeftArrow && ( diff --git a/app/src/modules/collaboration/collabCams.tsx b/app/src/modules/collaboration/collabCams.tsx index 9d5475e..af135a7 100644 --- a/app/src/modules/collaboration/collabCams.tsx +++ b/app/src/modules/collaboration/collabCams.tsx @@ -1,112 +1,169 @@ -import * as THREE from 'three'; -import { useEffect, useRef, useState } from 'react'; -import { useFrame } from '@react-three/fiber'; -import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; -import camModel from '../../assets/gltf-glb/camera face 2.gltf'; -import getActiveUsersData from '../../services/factoryBuilder/collab/getActiveUsers'; -import { useActiveUsers, useSocketStore } from '../../store/store'; -import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; -import { useNavigate } from 'react-router-dom'; -import { Text, Html } from '@react-three/drei'; -import CollabUserIcon from './collabUserIcon'; -import image from '../../assets/image/userImage.png'; - +import * as THREE from "three"; +import { useEffect, useRef, useState } from "react"; +import { useFrame } from "@react-three/fiber"; +import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; +import camModel from "../../assets/gltf-glb/camera face 2.gltf"; +import getActiveUsersData from "../../services/factoryBuilder/collab/getActiveUsers"; +import { useActiveUsers, useSocketStore } from "../../store/store"; +import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; +import { useNavigate } from "react-router-dom"; +import { Html } from "@react-three/drei"; +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 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 [models, setModels] = useState< + Record< + string, + { targetPosition: THREE.Vector3; targetRotation: THREE.Euler } + > + >({}); - dracoLoader.setDecoderPath('three/examples/jsm/libs/draco/gltf/'); + dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/"); loader.setDRACOLoader(dracoLoader); useEffect(() => { if (!email) { - navigate('/'); + navigate("/"); } if (!socket) return; - const organization = email!.split('@')[1].split('.')[0]; + const organization = email!.split("@")[1].split(".")[0]; - socket.on('userConnectRespones', (data: any) => { + socket.on("userConnectRespones", (data: any) => { if (!groupRef.current) return; - if (data.data.userData.email === email) return - if (socket.id === data.socketId || organization !== data.organization) return; + if (data.data.userData.email === email) return; + if (socket.id === data.socketId || organization !== data.organization) + return; - const model = groupRef.current.getObjectByProperty('uuid', data.data.userData._id); + 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.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]); }); }); - socket.on('userDisConnectRespones', (data: any) => { + socket.on("userDisConnectRespones", (data: any) => { if (!groupRef.current) return; - if (socket.id === data.socketId || organization !== data.organization) return; + if (socket.id === data.socketId || organization !== data.organization) + return; - setCams((prev) => prev.filter((cam) => cam.uuid !== data.data.userData._id)); - setActiveUsers(activeUsers.filter((user: any) => user._id !== data.data.userData._id)); + setCams((prev) => + prev.filter((cam) => cam.uuid !== data.data.userData._id) + ); + setActiveUsers( + activeUsers.filter((user: any) => user._id !== data.data.userData._id) + ); }); - socket.on('cameraUpdateResponse', (data: any) => { - if (!groupRef.current || socket.id === data.socketId || organization !== data.organization) return; + socket.on("cameraUpdateResponse", (data: any) => { + if ( + !groupRef.current || + socket.id === data.socketId || + organization !== data.organization + ) + 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), + 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 + ), }, })); }); return () => { - socket.off('userConnectRespones'); - socket.off('userDisConnectRespones'); - socket.off('cameraUpdateResponse'); + socket.off("userConnectRespones"); + socket.off("userDisConnectRespones"); + socket.off("cameraUpdateResponse"); }; }, [socket, activeUsers]); useFrame(() => { if (!groupRef.current) return; Object.keys(models).forEach((uuid) => { - const model = groupRef.current!.getObjectByProperty('uuid', 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); + 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]; + const organization = email!.split("@")[1].split(".")[0]; getActiveUsersData(organization).then((data) => { - const filteredData = data.cameraDatas.filter((camera: any) => camera.userData.email !== email); + 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.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; + console.log('cam.userData: ', cam.userData); setActiveUsers([...activeUsers, cam.userData]); return newModel; }); @@ -119,7 +176,7 @@ const CamModelsGroup = () => { return ( {cams.map((cam, index) => ( - + { textAlign: "center", fontFamily: "Arial, sans-serif", }} - position={[-0.015, 0, 0.7]}> - + position={[-0.015, 0, 0.7]} + > + ))} diff --git a/app/src/modules/collaboration/collabUserIcon.tsx b/app/src/modules/collaboration/collabUserIcon.tsx index a6c22c0..acc3fa0 100644 --- a/app/src/modules/collaboration/collabUserIcon.tsx +++ b/app/src/modules/collaboration/collabUserIcon.tsx @@ -1,53 +1,33 @@ import React from "react"; +import CustomAvatar from "./users/Avatar"; interface CollabUserIconProps { - color: string; - userImage: string; - userName: string; + userName: string; + userImage?: string; + index?: number; + color: string; } const CollabUserIcon: React.FC = ({ - color, - userImage, - userName, + userImage, + userName, + index = 0, + color, }) => { - return ( -
- {userName} -
- {userName} -
-
- ); + return ( +
+
+ {userImage ? ( + {userName} + ) : ( + + )} +
+
+ {userName} +
+
+ ); }; export default CollabUserIcon; diff --git a/app/src/modules/collaboration/users/Avatar.tsx b/app/src/modules/collaboration/users/Avatar.tsx new file mode 100644 index 0000000..93d45c3 --- /dev/null +++ b/app/src/modules/collaboration/users/Avatar.tsx @@ -0,0 +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 = ({ + name, + size = 100, + index = 0, + textColor = "#ffffff", +}) => { + const [imageSrc, setImageSrc] = useState(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 ( + User Avatar + ); +}; + +export default CustomAvatar; diff --git a/app/src/modules/collaboration/users/functions/getAvatarColor.ts b/app/src/modules/collaboration/users/functions/getAvatarColor.ts new file mode 100644 index 0000000..d3186d2 --- /dev/null +++ b/app/src/modules/collaboration/users/functions/getAvatarColor.ts @@ -0,0 +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]; +} diff --git a/app/src/modules/collaboration/users/functions/getInitials.ts b/app/src/modules/collaboration/users/functions/getInitials.ts new file mode 100644 index 0000000..5ebaa19 --- /dev/null +++ b/app/src/modules/collaboration/users/functions/getInitials.ts @@ -0,0 +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; +}; \ No newline at end of file diff --git a/app/src/modules/market/FilterSearch.tsx b/app/src/modules/market/FilterSearch.tsx index 08103ba..84074b8 100644 --- a/app/src/modules/market/FilterSearch.tsx +++ b/app/src/modules/market/FilterSearch.tsx @@ -29,11 +29,10 @@ const FilterSearch: React.FC = ({ filteredModels, }) => { const [activeOption, setActiveOption] = useState("Sort by"); // State for active option - console.log("filteredModels: ", filteredModels); const handleSelect = (option: string) => { setActiveOption(option); - console.log("option: ", option); + // Alphabet ascending // Alphabet descending // All diff --git a/app/src/styles/components/marketPlace/marketPlace.scss b/app/src/styles/components/marketPlace/marketPlace.scss index 71f5897..620d934 100644 --- a/app/src/styles/components/marketPlace/marketPlace.scss +++ b/app/src/styles/components/marketPlace/marketPlace.scss @@ -47,10 +47,9 @@ border-radius: $border-radius-large; .search-container { - border: none !important; - box-shadow: $box-shadow-medium; border-radius: $border-radius-large; - + outline: 1px solid var(--border-color); + border: none; input { border: none !important; outline: none; @@ -60,6 +59,12 @@ .regularDropdown-container { max-width: 159px; + height: 100%; + border-radius: #{$border-radius-large}; + border: 1px solid var(--border-color); + .dropdown-header { + align-items: center; + } } .button { @@ -128,7 +133,7 @@ justify-content: center; border-radius: #{$border-radius-medium}; overflow: hidden; - img{ + img { height: inherit; width: 100%; object-fit: cover; @@ -143,7 +148,7 @@ display: flex; flex-direction: column; gap: 3px; - .assets-name{ + .assets-name { text-transform: capitalize; } diff --git a/app/src/styles/layout/popup.scss b/app/src/styles/layout/popup.scss index a086cf4..20ea3f2 100644 --- a/app/src/styles/layout/popup.scss +++ b/app/src/styles/layout/popup.scss @@ -110,3 +110,29 @@ } } } + +.collab-user-live-container{ + @include flex-center; + flex-direction: column; + gap: 6px; + .user-image-container{ + height: 30px; + width: 30px; + border-radius: #{$border-radius-circle}; + overflow: hidden; + .user-image{ + height: 100%; + width: 100%; + object-fit: cover; + vertical-align: top; + } + } + .user-name{ + padding: 4px 6px; + border-radius: #{$border-radius-small}; + color: white; + font-size: var(--font-size-regulaar); + font-weight: var(--font-size-regulaar); + text-transform: capitalize; + } +} diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index d595b92..b248ad2 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -225,11 +225,13 @@ border-radius: 50%; font-weight: var(--font-weight-bold); color: white; + text-transform: capitalize; } .guest-users-container { display: flex; - + width: 100%; + justify-content: flex-end; .other-guest { @include flex-center; height: 26px; @@ -249,7 +251,8 @@ display: flex; .user-organization { - height: 100%; + height: 26px; + width: 52px; max-width: 52px; border-radius: 20px; overflow: hidden; diff --git a/app/src/types/users.d.ts b/app/src/types/users.d.ts index 9e8c35a..55d5361 100644 --- a/app/src/types/users.d.ts +++ b/app/src/types/users.d.ts @@ -8,4 +8,11 @@ export interface User { type AccessOption = { option: string; +}; + +export type ActiveUser = { + _id: string; + userName: string; + email: string; + activeStatus?: string; // Optional property }; \ No newline at end of file