Refactor MarketPlace and Scene components; enhance drag-and-drop functionality in DraggableWidget and Panel; add WidgetPlaceHolder component; implement global echo logging interface.

This commit is contained in:
Nalvazhuthi
2025-05-08 14:21:21 +05:30
parent 8bf48bfcfe
commit 453d6efc69
8 changed files with 155 additions and 54 deletions

13
app/src/global.d.ts vendored Normal file
View File

@@ -0,0 +1,13 @@
// src/global.d.ts
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;
};
}

View File

@@ -23,6 +23,10 @@ const MarketPlace = () => {
const [filteredModels, setFilteredModels] = useState<ModelData[]>([]); const [filteredModels, setFilteredModels] = useState<ModelData[]>([]);
const [isLoading, setisLoading] = useState<boolean>(false); // Loading state const [isLoading, setisLoading] = useState<boolean>(false); // Loading state
useEffect(() => {
echo.log("opended market place");
}, []);
useEffect(() => { useEffect(() => {
const filteredAssets = async () => { const filteredAssets = async () => {
setisLoading(true); setisLoading(true);
@@ -42,18 +46,16 @@ const MarketPlace = () => {
<div className="marketplace-wrapper"> <div className="marketplace-wrapper">
<div className="marketplace-container"> <div className="marketplace-container">
<div className="marketPlace"> <div className="marketPlace">
<FilterSearch
models={models}
setModels={setModels}
filteredModels={filteredModels}
/>
{isLoading ? ( {isLoading ? (
<SkeletonUI type="assetLibrary" /> // Show loading spinner while fetching <SkeletonUI type="assetLibrary" /> // Show loading spinner while fetching
) : ( ) : (
<> <CardsContainer models={models} />
<FilterSearch )}
models={models}
setModels={setModels}
filteredModels={filteredModels}
/>
<CardsContainer models={models} />
</>
)}{" "}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -20,24 +20,24 @@ export default function Scene() {
); );
return ( return (
<KeyboardControls map={map}> <KeyboardControls map={map}>
<Canvas <Canvas
eventPrefix="client" eventPrefix="client"
gl={{ powerPreference: "high-performance", antialias: true }} gl={{ powerPreference: "high-performance", antialias: true }}
onContextMenu={(e) => { onContextMenu={(e) => {
e.preventDefault(); e.preventDefault();
}} }}
> >
<Setup /> <Setup />
<Collaboration /> <Collaboration />
<Builder /> <Builder />
<Simulation /> <Simulation />
<Visualization /> <Visualization />
</Canvas> </Canvas>
</KeyboardControls> </KeyboardControls>
); );
} }

View File

@@ -38,6 +38,11 @@ export const DraggableWidget = ({
setOpenKebabId, setOpenKebabId,
selectedZone, selectedZone,
setSelectedZone, setSelectedZone,
draggingIndex,
setDraggingIndex,
hoverIndex,
setHoverIndex,
side,
}: { }: {
selectedZone: { selectedZone: {
zoneName: string; zoneName: string;
@@ -74,6 +79,12 @@ export const DraggableWidget = ({
onReorder: (fromIndex: number, toIndex: number) => void; onReorder: (fromIndex: number, toIndex: number) => void;
openKebabId: string | null; openKebabId: string | null;
setOpenKebabId: (id: string | null) => void; setOpenKebabId: (id: string | null) => void;
draggingIndex: number | null;
setDraggingIndex: React.Dispatch<React.SetStateAction<number | null>>;
hoverIndex: number | null;
setHoverIndex: React.Dispatch<React.SetStateAction<number | null>>;
side: any;
}) => { }) => {
const { visualizationSocket } = useSocketStore(); const { visualizationSocket } = useSocketStore();
const { selectedChartId, setSelectedChartId } = useWidgetStore(); const { selectedChartId, setSelectedChartId } = useWidgetStore();
@@ -98,8 +109,6 @@ export const DraggableWidget = ({
const deleteSelectedChart = async () => { const deleteSelectedChart = async () => {
try { try {
console.log("delete");
const email = localStorage.getItem("email") || ""; const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]; const organization = email?.split("@")[1]?.split(".")[0];
let deleteWidget = { let deleteWidget = {
@@ -111,7 +120,6 @@ export const DraggableWidget = ({
if (visualizationSocket) { if (visualizationSocket) {
setSelectedChartId(null); setSelectedChartId(null);
visualizationSocket.emit("v2:viz-widget:delete", deleteWidget); visualizationSocket.emit("v2:viz-widget:delete", deleteWidget);
console.log("delete widget", selectedChartId);
} }
const updatedWidgets = selectedZone.widgets.filter( const updatedWidgets = selectedZone.widgets.filter(
(w: Widget) => w.id !== widget.id (w: Widget) => w.id !== widget.id
@@ -197,16 +205,8 @@ export const DraggableWidget = ({
...prevZone, ...prevZone,
widgets: [...prevZone.widgets, duplicatedWidget], widgets: [...prevZone.widgets, duplicatedWidget],
})); }));
// const response = await duplicateWidgetApi(selectedZone.zoneId, organization, duplicatedWidget);
// if (response?.message === "Widget created successfully") {
// setSelectedZone((prevZone: any) => ({
// ...prevZone,
// widgets: [...prevZone.widgets, duplicatedWidget],
// }));
// }
} catch (error) { } catch (error) {
} finally { } finally {
setOpenKebabId(null); setOpenKebabId(null);
} }
@@ -241,10 +241,15 @@ export const DraggableWidget = ({
}, [setOpenKebabId]); }, [setOpenKebabId]);
const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => { const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
event.dataTransfer.setData("text/plain", index.toString()); // Store the index of the dragged widget event.dataTransfer.setData("text/plain", index.toString());
// selectedZone.zoneId
setDraggingIndex(index);
}; };
const handleDragEnter = (event: React.DragEvent<HTMLDivElement>) => { const handleDragEnter = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault(); // Allow drop event.preventDefault();
setHoverIndex(index); // Set where the placeholder should show
}; };
const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => { const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
@@ -253,11 +258,20 @@ export const DraggableWidget = ({
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => { const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault(); event.preventDefault();
const fromIndex = parseInt(event.dataTransfer.getData("text/plain"), 10); // Get the dragged widget's index const fromIndex = parseInt(event.dataTransfer.getData("text/plain"), 10);
const toIndex = index; // The index of the widget where the drop occurred const toIndex = index;
if (fromIndex !== toIndex) { if (fromIndex !== toIndex) {
onReorder(fromIndex, toIndex); // Call the reorder function passed as a prop onReorder(fromIndex, toIndex);
} }
setDraggingIndex(null);
setHoverIndex(null);
};
const handleDragEnd = () => {
setDraggingIndex(null);
setHoverIndex(null);
}; };
// useClickOutside(chartWidget, () => { // useClickOutside(chartWidget, () => {
@@ -289,6 +303,22 @@ export const DraggableWidget = ({
return ( return (
<> <>
{draggingIndex !== null && hoverIndex === index && (
<div
className="widget-placeholder"
style={{
width: ["top", "bottom"].includes(widget.panel)
? `calc(${canvasDimensions.width}px / 6)`
: undefined,
height: ["left", "right"].includes(widget.panel)
? `calc(${canvasDimensions.height - 15}px / 4)`
: undefined,
}}
>
Drop Here
</div>
)}
<div <div
draggable draggable
key={widget.id} key={widget.id}
@@ -300,6 +330,7 @@ export const DraggableWidget = ({
onDragEnter={handleDragEnter} onDragEnter={handleDragEnter}
onDragOver={handleDragOver} onDragOver={handleDragOver}
onDrop={handleDrop} onDrop={handleDrop}
onDragEnd={handleDragEnd}
style={{ style={{
width: ["top", "bottom"].includes(widget.panel) width: ["top", "bottom"].includes(widget.panel)
? `calc(${canvasDimensions.width}px / 6)` ? `calc(${canvasDimensions.width}px / 6)`
@@ -311,7 +342,6 @@ export const DraggableWidget = ({
ref={chartWidget} ref={chartWidget}
onClick={() => { onClick={() => {
setSelectedChartId(widget); setSelectedChartId(widget);
console.log("click");
}} }}
> >
{/* Kebab Icon */} {/* Kebab Icon */}

View File

@@ -69,6 +69,9 @@ const Panel: React.FC<PanelProps> = ({
height: 0, height: 0,
}); });
const [draggingIndex, setDraggingIndex] = useState<number | null>(null);
const [hoverIndex, setHoverIndex] = useState<number | null>(null);
// Track canvas dimensions // Track canvas dimensions
useEffect(() => { useEffect(() => {
const canvas = document.getElementById("real-time-vis-canvas"); const canvas = document.getElementById("real-time-vis-canvas");
@@ -302,13 +305,14 @@ const Panel: React.FC<PanelProps> = ({
> >
<div <div
className={`panel-content className={`panel-content
${waitingPanels === side ? `${side}-closing` : ""} ${waitingPanels === side ? `${side}-closing` : ""}
${ ${
!hiddenPanels[selectedZone.zoneId]?.includes(side) && waitingPanels !== side !hiddenPanels[selectedZone.zoneId]?.includes(side) &&
? `${side}-opening` waitingPanels !== side
: "" ? `${side}-opening`
} : ""
${isPlaying ? "fullScreen" : ""}`} }
${isPlaying ? "fullScreen" : ""}`}
style={{ style={{
pointerEvents: pointerEvents:
selectedZone.lockedPanels.includes(side) || selectedZone.lockedPanels.includes(side) ||
@@ -319,7 +323,7 @@ const Panel: React.FC<PanelProps> = ({
}} }}
> >
{selectedZone.widgets {selectedZone.widgets
.filter((w) => w.panel === side) .filter((w) => w.panel === "top")
.map((widget, index) => ( .map((widget, index) => (
<DraggableWidget <DraggableWidget
hiddenPanels={hiddenPanels} hiddenPanels={hiddenPanels}
@@ -329,10 +333,15 @@ const Panel: React.FC<PanelProps> = ({
onReorder={(fromIndex, toIndex) => onReorder={(fromIndex, toIndex) =>
handleReorder(fromIndex, toIndex, side) handleReorder(fromIndex, toIndex, side)
} }
side={side}
openKebabId={openKebabId} openKebabId={openKebabId}
setOpenKebabId={setOpenKebabId} setOpenKebabId={setOpenKebabId}
selectedZone={selectedZone} selectedZone={selectedZone}
setSelectedZone={setSelectedZone} setSelectedZone={setSelectedZone}
draggingIndex={draggingIndex}
setDraggingIndex={setDraggingIndex}
hoverIndex={hoverIndex}
setHoverIndex={setHoverIndex}
/> />
))} ))}
</div> </div>

View File

@@ -0,0 +1,7 @@
import React from "react";
const WidgetPlaceHolder = () => {
return <div className="widget-placeholder"></div>;
};
export default WidgetPlaceHolder;

View File

@@ -34,7 +34,7 @@ import Footer from "../components/footer/Footer";
const Project: React.FC = () => { const Project: React.FC = () => {
let navigate = useNavigate(); let navigate = useNavigate();
const echo = useLogger(); // const echo = useLogger();
const { activeModule, setActiveModule } = useModuleStore(); const { activeModule, setActiveModule } = useModuleStore();
const { loadingProgress } = useLoadingProgress(); const { loadingProgress } = useLoadingProgress();
@@ -58,7 +58,7 @@ const Project: React.FC = () => {
setOrganization(Organization); setOrganization(Organization);
setUserName(name); setUserName(name);
} }
echo.warn("Log in success full"); echo.warn("Log in successful");
} else { } else {
navigate("/"); navigate("/");
} }
@@ -86,7 +86,7 @@ const Project: React.FC = () => {
{!selectedUser && ( {!selectedUser && (
<> <>
<KeyPressListener /> <KeyPressListener />
{loadingProgress > 0 && <LoadingPage progress={loadingProgress} />} {/* {loadingProgress > 0 && <LoadingPage progress={loadingProgress} />} */}
{!isPlaying && ( {!isPlaying && (
<> <>
{toggleThreeD && <ModuleToggle />} {toggleThreeD && <ModuleToggle />}
@@ -122,7 +122,7 @@ const Project: React.FC = () => {
} }
onDragOver={(event) => event.preventDefault()} onDragOver={(event) => event.preventDefault()}
> >
<Scene /> {/* <Scene /> */}
</div> </div>
{selectedUser && <FollowPerson />} {selectedUser && <FollowPerson />}
{isLogListVisible && ( {isLogListVisible && (
@@ -136,3 +136,26 @@ const Project: React.FC = () => {
}; };
export default Project; export default Project;
// src/global.d.ts
// import { LogType } from "../components/ui/log/LoggerContext";
// export 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;
// };
// }
// Project.tsx:61 Uncaught ReferenceError: echo is not defined
// at Project.tsx:61:1
// at commitHookEffectListMount (react-dom.development.js:23189:1)
// at commitPassiveMountOnFiber (react-dom.development.js:24965:1)
// at commitPassiveMountEffects_complete (react-dom.development.js:24930:1)
// at commitPassiveMountEffects_begin (react-dom.development.js:24917:1)
// at commitPassiveMountEffects (react-dom.development.js:24905:1)
// this error occurs some time's

View File

@@ -213,6 +213,7 @@
position: relative; position: relative;
padding: 0 10px; padding: 0 10px;
animation: scaleFadeIn 0.4s forwards; animation: scaleFadeIn 0.4s forwards;
.kebab { .kebab {
width: 30px; width: 30px;
height: 30px; height: 30px;
@@ -948,13 +949,29 @@
transform: scaleY(0); transform: scaleY(0);
} }
} }
@keyframes scaleFadeIn { @keyframes scaleFadeIn {
from { from {
scale: 0; scale: 0;
opacity: 0; opacity: 0;
} }
to { to {
scale: 1; scale: 1;
opacity: 1; opacity: 1;
} }
} }
.widget-placeholder {
background-color: gray;
border-radius: 6px;
display: flex;
justify-content: center;
align-items: center;
}
.dragging {
display: none;
}