Merge remote-tracking branch 'origin/main' into v2-ui

This commit is contained in:
2025-05-13 16:36:17 +05:30
43 changed files with 484 additions and 542 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 850 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -230,7 +230,7 @@ const Assets: React.FC = () => {
(asset) => asset.category === category
);
return (
<button
<div
key={`${index}-${category}`}
className="category"
id={category}
@@ -243,7 +243,7 @@ const Assets: React.FC = () => {
draggable={false}
/>
<div className="category-name">{category}</div>
</button>
</div>
);
})}
</div>

View File

@@ -1,5 +1,5 @@
import React, { useState } from "react";
import orgImg from "../../../assets/orgTemp.png";
import orgImg from "../../../assets/image/orgTemp.png";
import { useActiveUsers, useCamMode } from "../../../store/store";
import { ActiveUser } from "../../../types/users";
import CollaborationPopup from "../../templates/CollaborationPopup";

View File

@@ -38,450 +38,360 @@ import {
useFloatingWidget,
} from "../../store/visualization/useDroppedObjectsStore";
const Tools: React.FC = () => {
const { templates } = useTemplateStore();
const { activeSubTool, setActiveSubTool } = useActiveSubTool();
const { toggleThreeD, setToggleThreeD } = useThreeDStore();
const { setToggleUI } = useToggleStore();
// Utility component
const ToolButton = ({ icon: Icon, active, onClick, tooltip }: any) => (
<button className={`tool-button ${active ? "active" : ""}`} onClick={onClick}>
<div className="tooltip">{tooltip}</div>
<Icon isActive={active} />
</button>
);
const dropdownRef = useRef<HTMLDivElement>(null);
const [openDrop, setOpenDrop] = useState(false);
const { visualizationSocket } = useSocketStore();
const Tools: React.FC = () => {
const { activeModule } = useModuleStore();
const { toggleThreeD, setToggleThreeD } = useThreeDStore();
const { isPlaying, setIsPlaying } = usePlayButtonStore();
const { addTemplate } = useTemplateStore();
const {
activeTool,
setActiveTool,
setToolMode,
setAddAction,
setDeleteTool,
setDeletePointOrLine,
setTransformMode,
} = useStoreHooks();
const { setActiveSubTool, activeSubTool } = useActiveSubTool();
const { setSelectedWallItem } = useSelectedWallItem();
const { setRefTextUpdate } = useRefTextUpdate();
const { setToggleUI } = useToggleStore();
const { setToggleView, toggleView } = useToggleView();
const { addTemplate, templates } = useTemplateStore();
const { selectedZone } = useSelectedZoneStore();
const { floatingWidget } = useFloatingWidget();
const { widgets3D } = use3DWidget();
const { visualizationSocket } = useSocketStore();
// wall options
const { toggleView, setToggleView } = useToggleView();
const { setDeleteTool } = useDeleteTool();
const { setAddAction } = useAddAction();
const { setSelectedWallItem } = useSelectedWallItem();
const dropdownRef = useRef<HTMLButtonElement>(null);
const [openDrop, setOpenDrop] = useState(false);
const { setTransformMode } = useTransformMode();
const { setDeletePointOrLine } = useDeletePointOrLine();
const { setToolMode } = useToolMode();
const { activeTool, setActiveTool } = useActiveTool();
const { setRefTextUpdate } = useRefTextUpdate();
// Reset activeTool whenever activeModule changes
// 1. Set UI toggles on initial render
useEffect(() => {
setToggleUI(
localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUiLeft") === "true"
: true,
localStorage.getItem("navBarUiRight")
? localStorage.getItem("navBarUiRight") === "true"
: true
localStorage.getItem("navBarUiLeft") !== "false",
localStorage.getItem("navBarUiRight") !== "false"
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// 2. Update tool based on subtool and module
useEffect(() => {
setActiveTool(activeSubTool);
setActiveSubTool(activeSubTool);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeModule]);
const toggleSwitch = () => {
if (toggleThreeD) {
setSelectedWallItem(null);
setDeleteTool(false);
setAddAction(null);
setToggleView(true);
// localStorage.setItem("navBarUi", JSON.stringify(!toggleThreeD));
} else {
setToggleView(false);
}
setToggleUI(
localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUiLeft") === "true"
: true,
localStorage.getItem("navBarUiRight")
? localStorage.getItem("navBarUiRight") === "true"
: true
);
setToggleThreeD(!toggleThreeD);
setActiveSubTool("cursor");
setActiveTool("cursor");
};
// 3. Update tools behavior based on selected tool and view mode
useEffect(() => {
const handleOutsideClick = (event: MouseEvent) => {
resetTools();
updateToolBehavior(activeTool, toggleView);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeTool, toggleView]);
// 4. Dropdown auto-close
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node)
!dropdownRef.current.contains(e.target as Node)
) {
setOpenDrop(false); // Close the dropdown
setOpenDrop(false);
}
};
document.addEventListener("mousedown", handleOutsideClick);
return () => {
document.removeEventListener("mousedown", handleOutsideClick);
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
useEffect(() => {
if (!toggleThreeD) {
setToggleUI(false, false);
}
}, [toggleThreeD]);
useEffect(() => {
const resetTools = () => {
setToolMode(null);
setDeleteTool(false);
setAddAction(null);
setTransformMode(null);
setDeletePointOrLine(false);
setRefTextUpdate((prevUpdate) => prevUpdate - 1);
setRefTextUpdate((prev) => prev - 1);
};
switch (activeTool) {
const updateToolBehavior = (tool: string, is2D: boolean) => {
switch (tool) {
case "cursor":
if (toggleView) {
setToolMode("move");
} else {
setTransformMode("translate");
}
is2D ? setToolMode("move") : setTransformMode("translate");
break;
case "Rotate":
if (!toggleView) {
setTransformMode("rotate");
}
if (!is2D) setTransformMode("rotate");
break;
case "Scale":
if (!toggleView) {
setTransformMode("scale");
}
if (!is2D) setTransformMode("scale");
break;
case "draw-wall":
if (toggleView) {
setToolMode("Wall");
}
is2D && setToolMode("Wall");
break;
case "draw-aisle":
if (toggleView) {
setToolMode("Aisle");
}
is2D && setToolMode("Aisle");
break;
case "draw-zone":
if (toggleView) {
setToolMode("Zone");
}
is2D && setToolMode("Zone");
break;
case "draw-floor":
if (toggleView) {
setToolMode("Floor");
}
is2D && setToolMode("Floor");
break;
case "measure":
setToolMode("MeasurementScale");
break;
case "Add pillar":
if (!toggleView) {
setAddAction("pillar");
}
if (!is2D) setAddAction("pillar");
break;
case "delete":
if (toggleView) {
setDeletePointOrLine(true);
} else {
setDeleteTool(true);
}
break;
default:
is2D ? setDeletePointOrLine(true) : setDeleteTool(true);
break;
}
};
setActiveTool(activeTool);
}, [activeTool, toggleView]);
const toggle2D3D = () => {
setToggleThreeD(!toggleThreeD);
setToggleUI(
localStorage.getItem("navBarUiLeft") !== "false",
localStorage.getItem("navBarUiRight") !== "false"
);
setSelectedWallItem(null);
setActiveSubTool("cursor");
setActiveTool("cursor");
setToggleView(!toggleThreeD);
};
if (isPlaying && activeModule !== "simulation") {
return (
<button className="exitPlay" onClick={() => setIsPlaying(false)}>
X
</button>
);
}
const renderBuilderTools = () => (
<>
{!toggleThreeD && (
<div className="draw-tools">
<ToolButton
icon={WallIcon}
tooltip="draw wall (q)"
active={activeTool === "draw-wall"}
onClick={() => setActiveTool("draw-wall")}
/>
<ToolButton
icon={ZoneIcon}
tooltip="draw zone (e)"
active={activeTool === "draw-zone"}
onClick={() => setActiveTool("draw-zone")}
/>
<ToolButton
icon={AsileIcon}
tooltip="draw aisle (r)"
active={activeTool === "draw-aisle"}
onClick={() => setActiveTool("draw-aisle")}
/>
<ToolButton
icon={FloorIcon}
tooltip="draw floor (t)"
active={activeTool === "draw-floor"}
onClick={() => setActiveTool("draw-floor")}
/>
</div>
)}
<div className="draw-tools">
<ToolButton
icon={MeasureToolIcon}
tooltip="measure scale (m)"
active={activeTool === "measure"}
onClick={() => setActiveTool("measure")}
/>
</div>
</>
);
const renderSimulationTools = () => (
<div className="draw-tools">
<ToolButton
icon={PenIcon}
tooltip="pen"
active={activeTool === "pen"}
onClick={() => setActiveTool("pen")}
/>
</div>
);
const renderVisualizationTools = () => (
<div className="draw-tools">
<ToolButton
icon={SaveTemplateIcon}
tooltip="save template"
active={false}
onClick={() =>
handleSaveTemplate({
addTemplate,
floatingWidget,
widgets3D,
selectedZone,
templates,
visualizationSocket,
})
}
/>
</div>
);
const renderModeSwitcher = () => (
<button
className={`toggle-threed-button${toggleThreeD ? " toggled" : ""}`}
onClick={toggle2D3D}
>
<div className="tooltip">toggle view (tab)</div>
<div className={`toggle-option${!toggleThreeD ? " active" : ""}`}>2d</div>
<div className={`toggle-option${toggleThreeD ? " active" : ""}`}>3d</div>
</button>
);
const getIconByTool = (tool: string) => {
switch (tool) {
case "cursor":
return CursorIcon;
case "free-hand":
return FreeMoveIcon;
case "delete":
return DeleteIcon;
default:
return CursorIcon;
}
};
const getTooltipShortcut = (tool: string) => {
switch (tool) {
case "cursor":
return "v";
case "free-hand":
return "h";
case "delete":
return "x";
default:
return "";
}
};
const getIconComponent = (option: string) => {
switch (option) {
case "cursor":
return <CursorIcon isActive={false} />;
case "free-hand":
return <FreeMoveIcon isActive={false} />;
case "delete":
return <DeleteIcon isActive={false} />;
default:
return null;
}
};
return (
<>
{!isPlaying ? (
<div className="tools-container">
<div className="drop-down-icons">
<div className="activeDropicon">
{activeSubTool == "cursor" && (
<div
className={`tool-button ${
activeTool === "cursor" ? "active" : ""
}`}
onClick={() => {
setActiveTool("cursor");
}}
>
<div className="tooltip">cursor (v)</div>
<CursorIcon isActive={activeTool === "cursor"} />
</div>
)}
{activeSubTool == "free-hand" && (
<div
className={`tool-button ${
activeTool === "free-hand" ? "active" : ""
}`}
onClick={() => {
setActiveTool("free-hand");
}}
>
<div className="tooltip">free hand (h)</div>
<FreeMoveIcon isActive={activeTool === "free-hand"} />
</div>
)}
{activeSubTool == "delete" && (
<div
className={`tool-button ${
activeTool === "delete" ? "active" : ""
}`}
onClick={() => {
setActiveTool("delete");
}}
>
<div className="tooltip">delete (x)</div>
<DeleteIcon isActive={activeTool === "delete"} />
</div>
)}
{activeModule !== "visualization" && (
<div
className="drop-down-option-button"
ref={dropdownRef}
onClick={() => {
setOpenDrop(!openDrop);
}}
>
<ArrowIcon />
{openDrop && (
<div className="drop-down-container">
<div
className="option-list"
onClick={() => {
setOpenDrop(false);
setActiveTool("cursor");
setActiveSubTool("cursor");
}}
>
<div className="active-option">
{activeSubTool === "cursor" && <TickIcon />}
</div>
<CursorIcon isActive={false} />
<div className="option">Cursor</div>
</div>
<div
className="option-list"
onClick={() => {
setOpenDrop(false);
setActiveTool("free-hand");
setActiveSubTool("free-hand");
}}
>
<div className="active-option">
{activeSubTool === "free-hand" && <TickIcon />}
</div>
<FreeMoveIcon isActive={false} />
<div className="option">Free Hand</div>
</div>
<div
className="option-list"
onClick={() => {
setOpenDrop(false);
setActiveTool("delete");
setActiveSubTool("delete");
}}
>
<div className="active-option">
{activeSubTool === "delete" && <TickIcon />}
</div>
<DeleteIcon isActive={false} />
<div className="option">Delete</div>
</div>
<div className="tools-container">
<div className="activeDropicon">
{/* Tool Picker (cursor, delete, etc.) */}
{["cursor", "free-hand", "delete"].map(
(tool) =>
activeSubTool === tool && (
<ToolButton
key={tool}
icon={getIconByTool(tool)}
tooltip={`${tool} (${getTooltipShortcut(tool)})`}
active={activeTool === tool}
onClick={() => setActiveTool(tool)}
/>
)
)}
{/* Dropdown Menu */}
{activeModule !== "visualization" && (
<button
className="drop-down-option-button"
ref={dropdownRef}
onClick={() => setOpenDrop(!openDrop)}
>
<ArrowIcon />
{openDrop && (
<div className="drop-down-container">
{["cursor", "free-hand", "delete"].map((option) => (
<button
key={option}
className="option-list"
onClick={() => {
setActiveTool(option);
setActiveSubTool(option);
setOpenDrop(false);
}}
>
<div className="active-option">
{activeSubTool === option && <TickIcon />}
</div>
)}
</div>
)}
</div>
</div>
{!toggleThreeD && activeModule === "builder" && (
<>
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${
activeTool === "draw-wall" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-wall");
}}
>
<div className="tooltip">draw wall (q)</div>
<WallIcon isActive={activeTool === "draw-wall"} />
</div>
<div
className={`tool-button ${
activeTool === "draw-zone" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-zone");
}}
>
<div className="tooltip">draw zone (e)</div>
<ZoneIcon isActive={activeTool === "draw-zone"} />
</div>
<div
className={`tool-button ${
activeTool === "draw-aisle" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-aisle");
}}
>
<div className="tooltip">draw asile (r)</div>
<AsileIcon isActive={activeTool === "draw-aisle"} />
</div>
<div
className={`tool-button ${
activeTool === "draw-floor" ? "active" : ""
}`}
onClick={() => {
setActiveTool("draw-floor");
}}
>
<div className="tooltip">draw floor (t)</div>
<FloorIcon isActive={activeTool === "draw-floor"} />
</div>
</div>
</>
)}
{activeModule === "builder" && (
<>
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${
activeTool === "measure" ? "active" : ""
}`}
onClick={() => {
setActiveTool("measure");
}}
>
<div className="tooltip">measure scale (m)</div>
<MeasureToolIcon isActive={activeTool === "measure"} />
</div>
</div>
</>
)}
{activeModule === "simulation" && (
<>
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button ${
activeTool === "pen" ? "active" : ""
}`}
onClick={() => {
setActiveTool("pen");
}}
>
<div className="tooltip">pen</div>
<PenIcon isActive={activeTool === "pen"} />
</div>
</div>
</>
)}
{activeModule === "visualization" && (
<>
<div className="split"></div>
<div className="draw-tools">
<div
className={`tool-button`}
onClick={() => {
handleSaveTemplate({
addTemplate,
floatingWidget,
widgets3D,
selectedZone,
templates,
visualizationSocket,
});
}}
>
<div className="tooltip">save template</div>
<SaveTemplateIcon isActive={false} />
</div>
</div>
</>
)}
<div className="split"></div>
<div className="general-options">
<div
className={`tool-button ${
activeTool === "comment" ? "active" : ""
}`}
onClick={() => {
setActiveTool("comment");
}}
>
<div className="tooltip">comment</div>
<CommentIcon isActive={activeTool === "comment"} />
</div>
{toggleThreeD && (
<div
className={`tool-button ${
activeTool === "play" ? "active" : ""
}`}
onClick={() => {
setIsPlaying(!isPlaying);
}}
>
<div className="tooltip">play (ctrl + p)</div>
<PlayIcon isActive={activeTool === "play"} />
{getIconComponent(option)}
<div className="option">{option}</div>
</button>
))}
</div>
)}
</div>
{activeModule === "builder" && (
<>
<div className="split"></div>
<div
className={`toggle-threed-button${
toggleThreeD ? " toggled" : ""
}`}
onClick={toggleSwitch}
>
<div className="tooltip">toggle view (tab)</div>
<div
className={`toggle-option${!toggleThreeD ? " active" : ""}`}
>
2d
</div>
<div
className={`toggle-option${toggleThreeD ? " active" : ""}`}
>
3d
</div>
</div>
</>
)}
</div>
) : (
</button>
)}
</div>
<div className="split"></div>
{activeModule === "builder" && renderBuilderTools()}
{activeModule === "simulation" && renderSimulationTools()}
{activeModule === "visualization" && renderVisualizationTools()}
<div className="split"></div>
<div className="general-options">
<ToolButton
icon={CommentIcon}
tooltip="comment"
active={activeTool === "comment"}
onClick={() => setActiveTool("comment")}
/>
{toggleThreeD && (
<ToolButton
icon={PlayIcon}
tooltip="play (ctrl + p)"
active={activeTool === "play"}
onClick={() => setIsPlaying(!isPlaying)}
/>
)}
</div>
{activeModule === "builder" && (
<>
{activeModule !== "simulation" && (
<button className="exitPlay" onClick={() => setIsPlaying(false)}>
X
</button>
)}
<div className="split"></div>
{renderModeSwitcher()}
</>
)}
</>
</div>
);
};
// Extracted common store logic
const useStoreHooks = () => {
return {
...useActiveTool(),
...useToolMode(),
...useDeleteTool(),
...useAddAction(),
...useTransformMode(),
...useDeletePointOrLine(),
...useRefTextUpdate(),
};
};
export default Tools;

View File

@@ -11,9 +11,9 @@ import ReferenceDistanceText from "./geomentries/lines/distanceText/referenceDis
////////// Assests Imports //////////
import arch from "../../assets/gltf-glb/arch.glb";
import door from "../../assets/gltf-glb/door.glb";
import Window from "../../assets/gltf-glb/window.glb";
// import arch from "../../assets/gltf-glb/arch.glb";
// import door from "../../assets/gltf-glb/door.glb";
// import Window from "../../assets/gltf-glb/window.glb";
////////// Zustand State Imports //////////
@@ -129,30 +129,30 @@ export default function Builder() {
////////// Assest Configuration Values //////////
const AssetConfigurations: Types.AssetConfigurations = {
arch: {
modelUrl: arch,
scale: [0.75, 0.75, 0.75],
csgscale: [2, 4, 0.5],
csgposition: [0, 2, 0],
positionY: () => 0,
type: "Fixed-Move",
},
door: {
modelUrl: door,
scale: [0.75, 0.75, 0.75],
csgscale: [2, 4, 0.5],
csgposition: [0, 2, 0],
positionY: () => 0,
type: "Fixed-Move",
},
window: {
modelUrl: Window,
scale: [0.75, 0.75, 0.75],
csgscale: [5, 3, 0.5],
csgposition: [0, 1.5, 0],
positionY: (intersectionPoint) => intersectionPoint.point.y,
type: "Free-Move",
},
// arch: {
// modelUrl: arch,
// scale: [0.75, 0.75, 0.75],
// csgscale: [2, 4, 0.5],
// csgposition: [0, 2, 0],
// positionY: () => 0,
// type: "Fixed-Move",
// },
// door: {
// modelUrl: door,
// scale: [0.75, 0.75, 0.75],
// csgscale: [2, 4, 0.5],
// csgposition: [0, 2, 0],
// positionY: () => 0,
// type: "Fixed-Move",
// },
// window: {
// modelUrl: Window,
// scale: [0.75, 0.75, 0.75],
// csgscale: [5, 3, 0.5],
// csgposition: [0, 1.5, 0],
// positionY: (intersectionPoint) => intersectionPoint.point.y,
// type: "Free-Move",
// },
};
////////// All Toggle's //////////

View File

@@ -1,7 +1,6 @@
import React, { Suspense, useEffect } from "react";
import assetImage from "../../assets/image/image.png";
import React, { Suspense } from "react";
import { FilledStarsIconSmall } from "../../components/icons/marketPlaceIcons";
import { Canvas, useThree } from "@react-three/fiber";
import { Canvas } from "@react-three/fiber";
import { ContactShadows, OrbitControls, Text } from "@react-three/drei";
import GltfLoader from "./GltfLoader";
import * as THREE from "three";
@@ -14,17 +13,26 @@ interface SelectedCard {
rating: number;
views: number;
description: string;
AssetID: string;
}
// Define the props type for AssetPreview
interface AssetPreviewProps {
selectedCard: SelectedCard;
modelUrl: string;
setSelectedCard: React.Dispatch<React.SetStateAction<SelectedCard | null>>; // Type for setter function
}
const savedTheme: string | null = localStorage.getItem("theme");
function Ui() {
return (
<Text color="#6f42c1" anchorX="center" anchorY="middle" scale={0.3}>
<Text
color={savedTheme === "dark" ? "#d2baff" : "#6f42c1"}
anchorX="center"
anchorY="middle"
scale={0.3}
>
Loading preview...
</Text>
);
@@ -33,16 +41,8 @@ function Ui() {
const AssetPreview: React.FC<AssetPreviewProps> = ({
selectedCard,
setSelectedCard,
modelUrl,
}) => {
// Ensure rating is a valid number between 0 and 5
const rating = Math.max(
0,
Math.min(5, isNaN(selectedCard.rating) ? 0 : selectedCard.rating)
);
// Ensure that the rating is a valid positive integer for array length
const starsArray = Array.from({ length: rating }, (_, index) => index);
return (
<div className="assetPreview-wrapper">
<div className="assetPreview">
@@ -53,18 +53,19 @@ const AssetPreview: React.FC<AssetPreviewProps> = ({
<Canvas
flat
shadows
color="#FFFFFF"
camera={{ fov: 75 }}
gl={{
preserveDrawingBuffer: true,
}}
onCreated={({ scene }) => {
scene.background = new THREE.Color(0xffffff);
scene.background = new THREE.Color(
savedTheme === "dark" ? 0x19191d : 0xfcfdfd
);
}}
>
<Suspense fallback={<Ui />}>
{selectedCard.assetName && (
<GltfLoader fromServer={selectedCard.assetName} />
{selectedCard.assetName && modelUrl && (
<GltfLoader fromServer={modelUrl} />
)}
<OrbitControls minPolarAngle={0} maxPolarAngle={Math.PI / 2} />
<ContactShadows
@@ -113,9 +114,9 @@ const AssetPreview: React.FC<AssetPreviewProps> = ({
</div>
{/* close button */}
<div className="closeButton" onClick={() => setSelectedCard(null)}>
<button className="closeButton" onClick={() => setSelectedCard(null)}>
{`<-back`}
</div>
</button>
</div>
</div>
</div>

View File

@@ -1,15 +1,12 @@
import React, { useEffect } from "react";
import React from "react";
import {
CommentsIcon,
DownloadIcon,
EyeIconBig,
FilledStarsIconSmall,
StarsIconSmall,
VerifiedIcon,
} from "../../components/icons/marketPlaceIcons";
import assetImage from "../../assets/image/image.png";
import { getAssetDownload } from "../../services/marketplace/getAssetDownload";
interface CardProps {
assetName: string;
@@ -19,6 +16,7 @@ interface CardProps {
views: number;
image: string;
description: string;
AssetID: string;
onSelectCard: (cardData: {
assetName: string;
uploadedOn: number;
@@ -26,6 +24,7 @@ interface CardProps {
rating: number;
views: number;
description: string;
AssetID: string;
}) => void;
}
@@ -38,9 +37,18 @@ const Card: React.FC<CardProps> = ({
image,
description,
onSelectCard,
AssetID,
}) => {
const handleCardSelect = () => {
onSelectCard({ assetName, uploadedOn, price, rating, views, description });
onSelectCard({
assetName,
uploadedOn,
price,
rating,
views,
description,
AssetID,
});
};
return (
@@ -81,22 +89,22 @@ const Card: React.FC<CardProps> = ({
<div className="stars-container">
<div className="stars-wrapper">
{[...Array(5)].map((_, index) => (
<>
<React.Fragment key={index} >
{index < 3 ? (
<FilledStarsIconSmall key={index} />
<FilledStarsIconSmall />
) : (
<StarsIconSmall key={index} />
<StarsIconSmall />
)}
</>
</React.Fragment>
))}
</div>
<div className="units">
{price}/<span>unit</span>
</div>
</div>
<div className="buy-now-button" onClick={handleCardSelect}>
<button className="buy-now-button" onClick={handleCardSelect}>
Buy now
</div>
</button>
</div>
);
};

View File

@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import Card from "./Card";
import AssetPreview from "./AssetPreview";
import { fetchGltfUrl } from "../../services/marketplace/fetchGltfUrl";
interface ModelData {
CreatedBy: string;
@@ -15,12 +16,14 @@ interface ModelData {
uploadDate: number;
_id: string;
price: number;
AssetID: string;
}
interface ModelsProps {
models: ModelData[];
}
const CardsContainer: React.FC<ModelsProps> = ({ models }) => {
const [modelUrl, setModelUrl] = useState<string>("");
const [selectedCard, setSelectedCard] = useState<{
assetName: string;
uploadedOn: number;
@@ -28,19 +31,23 @@ const CardsContainer: React.FC<ModelsProps> = ({ models }) => {
rating: number;
views: number;
description: string;
AssetID: string;
} | null>(null);
const handleCardSelect = (cardData: {
const handleCardSelect = async (cardData: {
assetName: string;
uploadedOn: number;
price: number;
rating: number;
views: number;
description: string;
AssetID: string;
}) => {
setSelectedCard(cardData);
const res = await fetchGltfUrl(cardData.assetName, cardData.AssetID);
console.log("res: ", res);
setModelUrl(res.url);
};
return (
<div className="cards-container-wrapper">
<div className="cards-container-container">
@@ -48,23 +55,26 @@ const CardsContainer: React.FC<ModelsProps> = ({ models }) => {
<div className="cards-wrapper-container">
{models.length > 0 &&
models.map((assetDetail) => (
<Card
key={assetDetail._id}
assetName={assetDetail?.filename}
uploadedOn={assetDetail.uploadDate}
price={assetDetail?.price}
rating={4.5}
views={800}
onSelectCard={handleCardSelect}
image={assetDetail.thumbnail}
description={assetDetail.description}
/>
<React.Fragment key={assetDetail._id}>
<Card
assetName={assetDetail?.filename}
uploadedOn={assetDetail.uploadDate}
price={assetDetail?.price}
rating={4.5}
views={800}
onSelectCard={handleCardSelect}
AssetID={assetDetail.AssetID}
image={assetDetail.thumbnail}
description={assetDetail.description}
/>
</React.Fragment>
))}
{/* <RenderOverlay> */}
{selectedCard && (
<AssetPreview
selectedCard={selectedCard}
setSelectedCard={setSelectedCard}
modelUrl={modelUrl}
/>
)}
{/* </RenderOverlay> */}

View File

@@ -16,6 +16,7 @@ interface ModelData {
uploadDate: number;
_id: string;
price: number;
AssetID: string;
}
interface ModelsProps {
@@ -44,7 +45,7 @@ const FilterSearch: React.FC<ModelsProps> = ({
const descending = [...models].sort((a, b) => b.filename.localeCompare(a.filename));
setModels(descending);
}
}, [activeOption]);
}, [activeOption, models, setModels]);
const handleSearch = (val: string) => {
const filteredModel = filteredModels.filter((model) =>
@@ -73,13 +74,13 @@ const FilterSearch: React.FC<ModelsProps> = ({
<div className="label">Rating</div>
<div className="stars">
{[0, 1, 2, 3, 4].map((i) => (
<div
<button
key={i}
onClick={() => handleStarClick(i)}
className={`star-wrapper ${i < rating ? "filled" : "empty"}`}
>
<StarsIcon />
</div>
</button>
))}
</div>
</div>

View File

@@ -3,7 +3,6 @@ import { useFrame } from "@react-three/fiber";
import { Stage, useGLTF } from "@react-three/drei";
import { AnimationMixer, AnimationAction, Object3D } from "three";
import * as THREE from "three";
import { fetchGltfUrl } from "../../services/marketplace/fetchGltfUrl";
interface GltfLoaderProps {
glbdata?: boolean;
@@ -13,7 +12,6 @@ interface GltfLoaderProps {
setSelectedAnimation?: (animation: string) => void;
}
// const getGLTFUrl = (url: string) => url; // Placeholder for your actual function
const GltfLoader: React.FC<GltfLoaderProps> = ({
glbdata,
@@ -21,12 +19,10 @@ const GltfLoader: React.FC<GltfLoaderProps> = ({
setAnimations,
selectedAnimation,
}) => {
const modelUrl: any = fromServer ? fetchGltfUrl(fromServer) : glbdata;
const { scene, animations } = useGLTF(modelUrl ?? "") as {
const { scene, animations } = useGLTF(fromServer ?? "") as {
scene: Object3D;
animations: THREE.AnimationClip[];
};
const mixer = useRef<AnimationMixer | null>(
scene ? new AnimationMixer(scene) : null
);

View File

@@ -1,7 +1,6 @@
import React, { useEffect, useState } from "react";
import FilterSearch from "./FilterSearch";
import CardsContainer from "./CardsContainer";
import { fetchAssets } from "../../services/marketplace/fetchAssets";
import { getAssetImages } from "../../services/factoryBuilder/assest/assets/getAssetImages";
import SkeletonUI from "../../components/templates/SkeletonUI";
interface ModelData {
@@ -17,6 +16,7 @@ interface ModelData {
uploadDate: number;
_id: string;
price: number;
AssetID: string;
}
const MarketPlace = () => {
const [models, setModels] = useState<ModelData[]>([]);

View File

@@ -4,7 +4,7 @@ import PostProcessing from '../postProcessing/postProcessing'
import Controls from '../controls/controls';
import { Environment } from '@react-three/drei'
import background from "../../../assets/hdr/mudroadpuresky2k.hdr";
import background from "../../../assets/textures/hdr/mudroadpuresky2k.hdr";
function Setup() {
return (

View File

@@ -14,7 +14,7 @@ export function useDefaultHandler() {
const material = getMaterialById(materialId);
if (!material) return;
defaultLogStatus(material.materialId, `performed Default action`);
defaultLogStatus(material.materialName, `performed Default action`);
}, [getMaterialById]);

View File

@@ -16,7 +16,7 @@ export function useDespawnHandler() {
removeMaterial(material.materialId);
deSpawnLogStatus(material.materialId, `Despawned`);
deSpawnLogStatus(material.materialName, `Despawned`);
}, [getMaterialById, removeMaterial]);

View File

@@ -142,7 +142,7 @@ export function useSpawnHandler() {
if (elapsed >= adjustedInterval) {
const createdMaterial = createNewMaterial(material, action);
if (createdMaterial) {
spawnLogStatus(createdMaterial.materialId, `[${elapsed.toFixed(2)}ms] Spawned ${material} (1/${totalCount})`);
spawnLogStatus(createdMaterial.materialName, `[${elapsed.toFixed(2)}ms] Spawned ${material} (1/${totalCount})`);
}
spawn.lastSpawnTime = currentTime;
spawn.spawnCount = 1;
@@ -162,7 +162,7 @@ export function useSpawnHandler() {
const count = spawn.spawnCount + 1;
const createdMaterial = createNewMaterial(material, action);
if (createdMaterial) {
spawnLogStatus(createdMaterial.materialId, `[${timeSinceLast.toFixed(2)}ms] Spawned ${material} (${count}/${totalCount})`);
spawnLogStatus(createdMaterial.materialName, `[${timeSinceLast.toFixed(2)}ms] Spawned ${material} (${count}/${totalCount})`);
}
spawn.lastSpawnTime = currentTime;
spawn.spawnCount = count;

View File

@@ -16,7 +16,7 @@ export function useSwapHandler() {
if (!material) return;
setMaterial(material.materialId, newMaterialType);
swapLogStatus(material.materialId, `Swapped to ${newMaterialType}`);
swapLogStatus(material.materialName, `Swapped to ${newMaterialType}`);
}, [getMaterialById, setMaterial]);

View File

@@ -29,8 +29,8 @@ export function useProcessHandler() {
addCurrentAction(modelUuid, action.actionUuid, newMaterialType, material.materialId);
processLogStatus(material.materialId, `Swapped to ${newMaterialType}`);
processLogStatus(material.materialId, `starts Process action`);
processLogStatus(material.materialName, `Swapped to ${newMaterialType}`);
processLogStatus(material.materialName, `starts Process action`);
}, [getMaterialById]);

View File

@@ -31,7 +31,7 @@ export function usePickAndPlaceHandler() {
material.materialId
);
pickAndPlaceLogStatus(material.materialId, `is going to be picked by armBot ${modelUuid}`);
pickAndPlaceLogStatus(material.materialName, `is going to be picked by armBot ${modelUuid}`);
}, [getMaterialById, getModelUuidByActionUuid, selectedProduct.productId, addCurrentAction]);

View File

@@ -27,7 +27,7 @@ export function useStoreHandler() {
addCurrentMaterial(modelUuid, material.materialType, material.materialId);
updateCurrentLoad(modelUuid, 1);
storeLogStatus(material.materialId, `performed Store action`);
storeLogStatus(material.materialName, `performed Store action`);
}, [getMaterialById]);

View File

@@ -27,7 +27,7 @@ export function useTravelHandler() {
incrementVehicleLoad(modelUuid, 1);
addCurrentMaterial(modelUuid, material.materialType, material.materialId);
travelLogStatus(material.materialId, `is triggering travel from ${modelUuid}`);
travelLogStatus(material.materialName, `is triggering travel from ${modelUuid}`);
}, [addCurrentMaterial, getMaterialById, getModelUuidByActionUuid, incrementVehicleLoad, selectedProduct.productId]);

View File

@@ -2,10 +2,10 @@ import { useGLTF } from '@react-three/drei'
import { useMemo } from 'react';
import * as THREE from 'three';
import defaultMaterial from '../../../../../assets/gltf-glb/default.glb';
import material1 from '../../../../../assets/gltf-glb/material1.glb';
import material2 from '../../../../../assets/gltf-glb/material2.glb';
import material3 from '../../../../../assets/gltf-glb/material3.glb';
import defaultMaterial from '../../../../../assets/gltf-glb/materials/default.glb';
import material1 from '../../../../../assets/gltf-glb/materials/material1.glb';
import material2 from '../../../../../assets/gltf-glb/materials/material2.glb';
import material3 from '../../../../../assets/gltf-glb/materials/material3.glb';
const modelPaths: Record<string, string> = {
'Default material': defaultMaterial,

View File

@@ -8,8 +8,8 @@ import PickDropPoints from './PickDropPoints';
import useDraggableGLTF from './useDraggableGLTF';
import * as THREE from 'three';
import armPick from "../../../../assets/gltf-glb/arm_ui_pick.glb";
import armDrop from "../../../../assets/gltf-glb/arm_ui_drop.glb";
import armPick from "../../../../assets/gltf-glb/ui/arm_ui_pick.glb";
import armDrop from "../../../../assets/gltf-glb/ui/arm_ui_drop.glb";
import { upsertProductOrEventApi } from '../../../../services/simulation/UpsertProductOrEventApi';
type Positions = {

View File

@@ -1,7 +1,5 @@
import { useEffect, useRef, useState } from "react";
import * as Types from "../../../../types/world/worldTypes";
import startPoint from "../../../../assets/gltf-glb/arrow_green.glb";
import startEnd from "../../../../assets/gltf-glb/arrow_red.glb";
import { useGLTF } from "@react-three/drei";
import { useFrame, useThree } from "@react-three/fiber";
import {
@@ -15,6 +13,9 @@ import { useProductStore } from "../../../../store/simulation/useProductStore";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
import { DoubleSide, Group, Plane, Vector3 } from "three";
import startPoint from "../../../../assets/gltf-glb/ui/arrow_green.glb";
import startEnd from "../../../../assets/gltf-glb/ui/arrow_red.glb";
const VehicleUI = () => {
const { scene: startScene } = useGLTF(startPoint) as any;
const { scene: endScene } = useGLTF(startEnd) as any;

View File

@@ -1,7 +1,26 @@
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
export const fetchGltfUrl = (filename: string) => {
if (filename) {
return `${BackEnd_url}/api/v1/getAssetFile/${filename}`;
export const fetchGltfUrl = async (filename: string, AssetID: string) => {
try {
const response = await fetch(
`${BackEnd_url}/api/v2/assetDetails/${filename}/${AssetID}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
// body: JSON.stringify(assetData),
}
);
if (!response.ok) {
throw new Error("Failed to fetch asset details");
}
const result = await response.json();
return result;
} catch (error: any) {
//
throw new Error(error.message);
}
return null; // or handle the case when filename is not provided
};
}

View File

@@ -2,9 +2,6 @@
@use "../../abstracts/mixins.scss" as *;
.marketplace-wrapper {
// transform: scale(0.65);
/* Start at 90% width */
height: 100vh;
width: 100vw;
z-index: #{$z-index-marketplace};
@@ -14,7 +11,6 @@
top: 0;
padding: 10px;
padding-top: 100px;
// animation: growWidth 0.4s ease-in-out 0.5s forwards;
.marketplace-container {
position: relative;
@@ -43,8 +39,6 @@
width: 100%;
.skeleton-content {
width: calc(25% - 14px) !important;
height: 100%;
border-radius: #{$border-radius-xlarge};
@@ -79,7 +73,6 @@
}
.button {
width: 100%;
height: 35px;
border-radius: 20px;
@@ -143,8 +136,7 @@
.star-wrapper.filled {
svg {
fill: #F3A50C;
fill: #f3a50c;
}
}
}
@@ -190,10 +182,6 @@
justify-content: center;
gap: 6px;
.assets-container {
height: auto;
}
.icon {
position: absolute;
top: 12px;
@@ -208,7 +196,7 @@
.image-container {
width: 100%;
display: flex;
max-height: 180px;
height: 180px;
justify-content: center;
border-radius: #{$border-radius-medium};
overflow: hidden;
@@ -224,7 +212,7 @@
display: flex;
justify-content: space-between;
padding: 0;
height: auto;
.name-container {
display: flex;
flex-direction: column;
@@ -299,7 +287,6 @@
}
}
.assetPreview-wrapper {
width: 100%;
height: 100%;
@@ -307,15 +294,18 @@
top: 0;
left: 0;
z-index: 3;
padding: 0 10px;
.assetPreview {
width: 100%;
height: 100%;
background: var(--background-color);
backdrop-filter: blur(18px);
display: flex;
gap: 12px;
overflow: hidden;
border-radius: #{$border-radius-extra-large};
outline: 1px solid var(--border-color);
}
// Image Preview Section
@@ -352,8 +342,8 @@
min-width: 26px;
border-radius: #{$border-radius-circle};
font-weight: var(--font-weight-bold);
color: var(--background-color);
background: var(--accent-color);
color: var(--text-button-color);
background: var(--background-color-button);
}
.organization-details {
@@ -361,9 +351,7 @@
flex-direction: column;
.organization-name {
font-weight: bold;
margin-bottom: 5px;
font-weight: #{$bold-weight};
font-size: $regular;
}
@@ -380,35 +368,31 @@
margin-top: 20px;
.asset-name {
font-size: 1.5em;
font-weight: bold;
margin-bottom: 10px;
font-weight: #{$bold-weight};
font-size: $large;
font-size: var(--font-size-large);
}
.asset-description {
margin-bottom: 20px;
color: #666;
color: var(--input-text-color);
}
.asset-review {
width: fit-content;
padding: 5px 10px;
padding: 5px 14px;
display: flex;
align-items: center;
margin-bottom: 20px;
outline: 1px solid #909090cc;
border-radius: #{$border-radius-small};
outline: 1px solid var(--border-color);
border-radius: #{$border-radius-large};
.asset-rating {
display: flex;
align-items: center;
gap: 4px;
margin-right: 10px;
font-weight: bold;
position: relative;
font-weight: #{$bold-weight};
font-size: $regular;
@@ -442,25 +426,25 @@
}
.button {
color: white;
padding: 10px 20px;
border-radius: #{$border-radius-small};
color: var(--text-button-color);
padding: 8px 26px;
border-radius: #{$border-radius-extra-large};
cursor: pointer;
text-align: center;
&:first-child {
outline: 1px solid var(--accent-color);
color: var(--accent-color);
outline: 1px solid var(--background-color-button);
color: var(--highlight-text-color);
}
&:last-child {
background: var(--accent-color);
color: var(--background-color);
background: var(--background-color-button);
color: var(--text-button-color);
}
}
.closeButton {
color: var(--accent-color);
color: var(--highlight-text-color);
position: absolute;
top: 18px;
left: 18px;
@@ -468,4 +452,4 @@
cursor: pointer;
font-size: var(--font-size-large);
}
}
}

View File

@@ -305,7 +305,6 @@
.header-container {
@include flex-space-between;
padding: 10px;
padding-left: 16px;
width: 100%;
gap: 8px;
height: 52px;

View File

@@ -108,26 +108,39 @@ const KeyPressListener: React.FC = () => {
const handleSidebarShortcuts = (key: string) => {
if (activeModule !== "market") {
if (key === "Ctrl+\\") {
if (activeModule === "market") return;
const updateLocalStorage = (left: boolean, right: boolean) => {
localStorage.setItem("navBarUiLeft", JSON.stringify(left));
localStorage.setItem("navBarUiRight", JSON.stringify(right));
};
switch (key) {
case "Ctrl+\\":
if (toggleUILeft === toggleUIRight) {
setToggleUI(!toggleUILeft, !toggleUIRight);
}
else {
const newState = !toggleUILeft;
setToggleUI(newState, newState);
updateLocalStorage(newState, newState);
} else {
setToggleUI(true, true);
updateLocalStorage(true, true);
}
return;
}
if (key === "Ctrl+]") {
setToggleUI(toggleUILeft, !toggleUIRight);
return;
}
if (key === "Ctrl+[") {
setToggleUI(!toggleUILeft, toggleUIRight);
return;
}
break;
case "Ctrl+]":
setToggleUI(toggleUILeft, !toggleUIRight);
updateLocalStorage(toggleUILeft, !toggleUIRight);
break;
case "Ctrl+[":
setToggleUI(!toggleUILeft, toggleUIRight);
updateLocalStorage(!toggleUILeft, toggleUIRight);
break;
default:
break;
}
}
};
const handleKeyPress = (event: KeyboardEvent) => {