From e00bccb357985a5698b4ec4f0b99e42880c9c1aa Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Mon, 13 Oct 2025 10:44:17 +0530 Subject: [PATCH] created new window --- app/package-lock.json | 48 +- .../layout/scenes/ComparisonScene.tsx | 95 +++- .../components/templates/CreateNewWindow.tsx | 492 ++++++++++++------ app/src/components/templates/LoadingPage.tsx | 6 +- .../components/ui/compareVersion/Button.tsx | 47 ++ .../ui/compareVersion/CompareLayOut.tsx | 132 +++-- .../ui/compareVersion/NewWindowScene.tsx | 44 ++ app/src/components/ui/log/LogList.tsx | 297 +++++------ .../builder/asset/models/model/model.tsx | 43 +- .../modules/builder/asset/models/models.tsx | 76 ++- app/src/modules/scene/camera/syncCam.tsx | 46 +- app/src/modules/scene/scene.tsx | 29 +- app/src/pages/Project.tsx | 1 + app/src/store/builder/store.ts | 14 +- 14 files changed, 944 insertions(+), 426 deletions(-) create mode 100644 app/src/components/ui/compareVersion/Button.tsx create mode 100644 app/src/components/ui/compareVersion/NewWindowScene.tsx diff --git a/app/package-lock.json b/app/package-lock.json index b2ba539..04f7c7c 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -2029,7 +2029,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2041,7 +2041,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -4192,6 +4192,26 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "license": "MIT", + "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", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "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", @@ -4303,25 +4323,25 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "devOptional": true }, "node_modules/@turf/along": { "version": "7.2.0", @@ -9093,7 +9113,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "devOptional": true }, "node_modules/cross-env": { "version": "7.0.3", @@ -9970,7 +9990,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.3.1" } @@ -15354,7 +15374,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "devOptional": true }, "node_modules/makeerror": { "version": "1.0.12", @@ -20908,7 +20928,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "devOptional": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -20951,7 +20971,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, + "devOptional": true, "dependencies": { "acorn": "^8.11.0" }, @@ -20963,7 +20983,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "devOptional": true }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -21459,7 +21479,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "devOptional": true }, "node_modules/v8-to-istanbul": { "version": "8.1.1", @@ -22518,7 +22538,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } diff --git a/app/src/components/layout/scenes/ComparisonScene.tsx b/app/src/components/layout/scenes/ComparisonScene.tsx index 3756b08..4cbb543 100644 --- a/app/src/components/layout/scenes/ComparisonScene.tsx +++ b/app/src/components/layout/scenes/ComparisonScene.tsx @@ -1,4 +1,9 @@ -import { useCompareProductDataStore, useLoadingProgress, useIsComparing } from "../../../store/builder/store"; +import { + useCompareProductDataStore, + useLoadingProgress, + useIsComparing, + useCreateNewWindow, +} from "../../../store/builder/store"; import { useSimulationState } from "../../../store/simulation/useSimulationStore"; import { usePlayButtonStore } from "../../../store/ui/usePlayButtonStore"; import { useEffect, useState } from "react"; @@ -11,7 +16,8 @@ import { useSimulationManager } from "../../../store/rough/useSimulationManagerS import { useParams } from "react-router-dom"; import { validateSimulationDataApi } from "../../../services/simulation/comparison/validateSimulationDataApi"; import { calculateSimulationData } from "./functions/calculateSimulationData"; - +import NewWindowScene from "../../ui/compareVersion/NewWindowScene"; +import Button from "../../ui/compareVersion/Button"; type AssetData = { activeTime: number; idleTime: number; @@ -41,7 +47,11 @@ export interface CompareProduct { //shiftsPerDay: number; }; } -export const createCompareProduct = (productUuid: string, productName: string, assets: AssetData[]): CompareProduct => ({ +export const createCompareProduct = ( + productUuid: string, + productName: string, + assets: AssetData[] +): CompareProduct => ({ productUuid, productName, simulationData: calculateSimulationData(assets), @@ -61,8 +71,10 @@ function ComparisonScene() { const { setCompareProductsData } = useCompareProductDataStore(); const [shouldShowComparisonResult, setShouldShowComparisonResult] = useState(false); const { addSimulationRecord } = useSimulationManager(); - - useEffect(() => {}); + const { createNewWindow } = useCreateNewWindow(); + useEffect(() => { + console.log("comparisonScene: ", comparisonScene); + }, [comparisonScene]); const handleSelectVersion = (option: string) => { const version = versionHistory.find((version) => version.versionName === option); @@ -77,12 +89,22 @@ function ComparisonScene() { echo.log(getData.message); const getSimulate = getData?.data?.existingSimulatedData; if (!getSimulate) return; - if (!selectedVersion?.versionId || !projectId || getSimulate === undefined || !selectedProduct.productUuid) { + if ( + !selectedVersion?.versionId || + !projectId || + getSimulate === undefined || + !selectedProduct.productUuid + ) { echo.warn("No prebacked Data found"); alert("Please run the simulation before comparing."); return; } - addSimulationRecord(projectId, selectedVersion?.versionId || "", selectedProduct.productUuid || "", getSimulate.data); + addSimulationRecord( + projectId, + selectedVersion?.versionId || "", + selectedProduct.productUuid || "", + getSimulate.data + ); }); } }; @@ -105,7 +127,12 @@ function ComparisonScene() { echo.warn(getData.message); const getSimulate = getData?.data?.existingSimulatedData; if (!getSimulate) return; - addSimulationRecord(projectId, selectedVersion?.versionId || "", product.productUuid || "", getSimulate.data); + addSimulationRecord( + projectId, + selectedVersion?.versionId || "", + product.productUuid || "", + getSimulate.data + ); }); setComparisonState(data); } @@ -113,12 +140,32 @@ function ComparisonScene() { useEffect(() => { if (mainScene && comparisonScene && selectedVersion) { - const mainVersion = useSimulationManager.getState().getProductById(projectId, mainScene.version.versionUuid, mainScene.product.productUuid); + const mainVersion = useSimulationManager + .getState() + .getProductById( + projectId, + mainScene.version.versionUuid, + mainScene.product.productUuid + ); - const compareVersion = useSimulationManager.getState().getProductById(projectId, comparisonScene.version.versionUuid, comparisonScene.product.productUuid); + const compareVersion = useSimulationManager + .getState() + .getProductById( + projectId, + comparisonScene.version.versionUuid, + comparisonScene.product.productUuid + ); - const mainVompareversion = createCompareProduct(mainVersion?.productId ?? "", mainScene.product.productName, mainVersion?.simulateData || []); - const compareProduct2 = createCompareProduct(compareVersion?.productId ?? "", comparisonScene.product.productName, compareVersion?.simulateData || []); + const mainVompareversion = createCompareProduct( + mainVersion?.productId ?? "", + mainScene.product.productName, + mainVersion?.simulateData || [] + ); + const compareProduct2 = createCompareProduct( + compareVersion?.productId ?? "", + comparisonScene.product.productName, + compareVersion?.simulateData || [] + ); const comparedArray = [mainVompareversion, compareProduct2]; @@ -131,7 +178,14 @@ function ComparisonScene() { } else { setShouldShowComparisonResult(false); } - }, [mainScene, comparisonScene, selectedVersion, projectId, setCompareProductsData, simulationRecords]); + }, [ + mainScene, + comparisonScene, + selectedVersion, + projectId, + setCompareProductsData, + simulationRecords, + ]); return ( <> @@ -154,7 +208,20 @@ function ComparisonScene() { /> )} - + {selectedVersion?.versionId && ( +
+
+ )} + {} + {createNewWindow && } {shouldShowComparisonResult && !loadingProgress && } )} diff --git a/app/src/components/templates/CreateNewWindow.tsx b/app/src/components/templates/CreateNewWindow.tsx index bddc2ba..6794b3b 100644 --- a/app/src/components/templates/CreateNewWindow.tsx +++ b/app/src/components/templates/CreateNewWindow.tsx @@ -2,182 +2,382 @@ import React, { ReactNode, useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; type NewWindowProps = { - children: ReactNode; - title?: string; - width?: number; - height?: number; - left?: number; - top?: number; - center?: boolean; - features?: Partial<{ - toolbar: boolean; - menubar: boolean; - scrollbars: boolean; - resizable: boolean; - location: boolean; - status: boolean; - }>; - onClose?: () => void; - copyStyles?: boolean; - noopener?: boolean; - className?: string; - theme?: string | null; + children: ReactNode; + title?: string; + width?: number; + height?: number; + left?: number; + top?: number; + center?: boolean; + features?: Partial<{ + toolbar: boolean; + menubar: boolean; + scrollbars: boolean; + resizable: boolean; + location: boolean; + status: boolean; + }>; + onClose?: () => void; + copyStyles?: boolean; + noopener?: boolean; + className?: string; + theme?: string | null; }; +// export const RenderInNewWindow: React.FC = ({ +// children, +// title = "New Window", +// width = 900, +// height = 700, +// left, +// top, +// center = true, +// features, +// onClose, +// copyStyles = true, +// noopener = true, +// className, +// theme = localStorage.getItem("theme") ?? "light", +// }) => { +// const [mounted, setMounted] = useState(false); +// const childWindowRef = useRef(null); +// const containerElRef = useRef(null); + +// useEffect(() => { +// if (typeof window === "undefined") return; + +// const screenLeft = window.screenLeft ?? window.screenX ?? 0; +// const screenTop = window.screenTop ?? window.screenY ?? 0; +// const availWidth = window.outerWidth ?? window.innerWidth; +// const availHeight = window.outerHeight ?? window.innerHeight; + +// const finalLeft = +// center && availWidth ? Math.max(0, screenLeft + (availWidth - width) / 2) : left ?? 100; + +// const finalTop = +// center && availHeight +// ? Math.max(0, screenTop + (availHeight - height) / 2) +// : top ?? 100; + +// const baseFeatures = [ +// `width=${Math.floor(width)}`, +// `height=${Math.floor(height)}`, +// `left=${Math.floor(finalLeft)}`, +// `top=${Math.floor(finalTop)}`, +// ]; + +// const featureFlags = features ?? { +// toolbar: false, +// menubar: false, +// scrollbars: true, +// resizable: true, +// location: false, +// status: false, +// }; + +// Object.entries(featureFlags).forEach(([k, v]) => +// baseFeatures.push(`${k}=${v ? "yes" : "no"}`) +// ); + +// const newWin = window.open("", "_blank", baseFeatures.join(",")); +// if (!newWin) { +// console.warn("Popup blocked or failed to open window."); +// onClose?.(); +// return; +// } + +// if (noopener) { +// try { +// newWin.opener = null; +// } catch {} +// } + +// newWin.document.open(); +// newWin.document.write(` +// +// +// +// ${title} +// +// +// +// `); +// newWin.document.close(); + +// if (copyStyles) { +// const head = newWin.document.head; +// Array.from(document.styleSheets).forEach((styleSheet) => { +// try { +// if ((styleSheet as CSSStyleSheet).cssRules) { +// const newStyleEl = newWin.document.createElement("style"); +// const rules = Array.from((styleSheet as CSSStyleSheet).cssRules).map( +// (r) => r.cssText +// ); +// newStyleEl.appendChild(newWin.document.createTextNode(rules.join("\n"))); +// head.appendChild(newStyleEl); +// } +// } catch { +// const ownerNode = styleSheet.ownerNode as HTMLElement | null; +// if (ownerNode && ownerNode.tagName === "LINK") { +// const link = ownerNode as HTMLLinkElement; +// const newLink = newWin.document.createElement("link"); +// newLink.rel = link.rel; +// newLink.href = link.href; +// newLink.media = link.media; +// head.appendChild(newLink); +// } +// } +// }); +// } + +// const container = newWin.document.createElement("div"); +// if (className) container.className = className; +// newWin.document.body.appendChild(container); + +// newWin.document.title = title; + +// // Handle child window close +// const handleChildUnload = () => { +// onClose?.(); +// }; +// newWin.addEventListener("beforeunload", handleChildUnload); + +// // ๐Ÿ‘‡ Handle parent refresh/close โ†’ auto close child +// const handleParentUnload = () => { +// try { +// newWin.close(); +// } catch {} +// }; +// window.addEventListener("beforeunload", handleParentUnload); + +// childWindowRef.current = newWin; +// containerElRef.current = container; +// setMounted(true); + +// return () => { +// newWin.removeEventListener("beforeunload", handleChildUnload); +// window.removeEventListener("beforeunload", handleParentUnload); +// try { +// newWin.close(); +// } catch {} +// childWindowRef.current = null; +// containerElRef.current = null; +// }; +// // eslint-disable-next-line react-hooks/exhaustive-deps +// }, []); + +// useEffect(() => { +// const w = childWindowRef.current; +// if (w && !w.closed) { +// w.document.title = title; +// } +// }, [title]); + +// if (!mounted || !containerElRef.current) return null; + +// return createPortal(children, containerElRef.current); +// }; export const RenderInNewWindow: React.FC = ({ - children, - title = "New Window", - width = 900, - height = 700, - left, - top, - center = true, - features, - onClose, - copyStyles = true, - noopener = true, - className, - theme = localStorage.getItem('theme') ?? 'light', + children, + title = "3D Viewer", + width = 900, + height = 700, + left, + top, + center = true, + features, + onClose, + copyStyles = true, + noopener = true, + className, + theme = localStorage.getItem("theme") ?? "light", }) => { - const [mounted, setMounted] = useState(false); - const childWindowRef = useRef(null); - const containerElRef = useRef(null); + const [mounted, setMounted] = useState(false); + const childWindowRef = useRef(null); + const containerElRef = useRef(null); - useEffect(() => { - if (typeof window === "undefined") return; + useEffect(() => { + if (typeof window === "undefined") return; - const screenLeft = window.screenLeft ?? window.screenX ?? 0; - const screenTop = window.screenTop ?? window.screenY ?? 0; - const availWidth = window.outerWidth ?? window.innerWidth; - const availHeight = window.outerHeight ?? window.innerHeight; + const screenLeft = window.screenLeft ?? window.screenX ?? 0; + const screenTop = window.screenTop ?? window.screenY ?? 0; + const availWidth = window.outerWidth ?? window.innerWidth; + const availHeight = window.outerHeight ?? window.innerHeight; - const finalLeft = - center && availWidth - ? Math.max(0, screenLeft + (availWidth - width) / 2) - : left ?? 100; + const finalLeft = + center && availWidth ? Math.max(0, screenLeft + (availWidth - width) / 2) : left ?? 100; - const finalTop = - center && availHeight - ? Math.max(0, screenTop + (availHeight - height) / 2) - : top ?? 100; + const finalTop = + center && availHeight + ? Math.max(0, screenTop + (availHeight - height) / 2) + : top ?? 100; - const baseFeatures = [ - `width=${Math.floor(width)}`, - `height=${Math.floor(height)}`, - `left=${Math.floor(finalLeft)}`, - `top=${Math.floor(finalTop)}`, - ]; + const baseFeatures = [ + `width=${Math.floor(width)}`, + `height=${Math.floor(height)}`, + `left=${Math.floor(finalLeft)}`, + `top=${Math.floor(finalTop)}`, + ]; - const featureFlags = features ?? { - toolbar: false, - menubar: false, - scrollbars: true, - resizable: true, - location: false, - status: false, - }; + const featureFlags = features ?? { + toolbar: false, + menubar: false, + scrollbars: true, + resizable: true, + location: false, + status: false, + }; - Object.entries(featureFlags).forEach(([k, v]) => - baseFeatures.push(`${k}=${v ? "yes" : "no"}`) - ); + Object.entries(featureFlags).forEach(([k, v]) => + baseFeatures.push(`${k}=${v ? "yes" : "no"}`) + ); - const newWin = window.open("", "_blank", baseFeatures.join(",")); - if (!newWin) { - console.warn("Popup blocked or failed to open window."); - onClose?.(); - return; - } + const newWin = window.open("", "_blank", baseFeatures.join(",")); + if (!newWin) { + console.warn("Popup blocked or failed to open window."); + onClose?.(); + return; + } - if (noopener) { - try { - newWin.opener = null; - } catch {} - } + if (noopener) { + try { + newWin.opener = null; + } catch {} + } - newWin.document.open(); - newWin.document.write(` + newWin.document.open(); + newWin.document.write(` ${title} + - + +
+ `); - newWin.document.close(); + newWin.document.close(); - if (copyStyles) { - const head = newWin.document.head; - Array.from(document.styleSheets).forEach((styleSheet) => { - try { - if ((styleSheet as CSSStyleSheet).cssRules) { - const newStyleEl = newWin.document.createElement("style"); - const rules = Array.from( - (styleSheet as CSSStyleSheet).cssRules - ).map((r) => r.cssText); - newStyleEl.appendChild( - newWin.document.createTextNode(rules.join("\n")) - ); - head.appendChild(newStyleEl); - } - } catch { - const ownerNode = styleSheet.ownerNode as HTMLElement | null; - if (ownerNode && ownerNode.tagName === "LINK") { - const link = ownerNode as HTMLLinkElement; - const newLink = newWin.document.createElement("link"); - newLink.rel = link.rel; - newLink.href = link.href; - newLink.media = link.media; - head.appendChild(newLink); - } + if (copyStyles) { + const head = newWin.document.head; + Array.from(document.styleSheets).forEach((styleSheet) => { + try { + if ((styleSheet as CSSStyleSheet).cssRules) { + const newStyleEl = newWin.document.createElement("style"); + const rules = Array.from((styleSheet as CSSStyleSheet).cssRules).map( + (r) => r.cssText + ); + newStyleEl.appendChild(newWin.document.createTextNode(rules.join("\n"))); + head.appendChild(newStyleEl); + } + } catch { + const ownerNode = styleSheet.ownerNode as HTMLElement | null; + if (ownerNode && ownerNode.tagName === "LINK") { + const link = ownerNode as HTMLLinkElement; + const newLink = newWin.document.createElement("link"); + newLink.rel = link.rel; + newLink.href = link.href; + newLink.media = link.media; + head.appendChild(newLink); + } + } + }); } - }); - } - const container = newWin.document.createElement("div"); - if (className) container.className = className; - newWin.document.body.appendChild(container); + const container = newWin.document.getElementById( + "three-container" + ) as HTMLDivElement | null; + if (!container) return; - newWin.document.title = title; + if (className) container.className = className; - // Handle child window close - const handleChildUnload = () => { - onClose?.(); - }; - newWin.addEventListener("beforeunload", handleChildUnload); + newWin.document.title = title; - // ๐Ÿ‘‡ Handle parent refresh/close โ†’ auto close child - const handleParentUnload = () => { - try { - newWin.close(); - } catch {} - }; - window.addEventListener("beforeunload", handleParentUnload); + // โœ… CRITICAL FIX: Wait for window to be fully ready then trigger resize + const initializeWindow = () => { + // Force maximize handling + setTimeout(() => { + // Get actual window dimensions (might be maximized) + const actualWidth = newWin.innerWidth; + const actualHeight = newWin.innerHeight; - childWindowRef.current = newWin; - containerElRef.current = container; - setMounted(true); + console.log("Window dimensions:", actualWidth, actualHeight); - return () => { - newWin.removeEventListener("beforeunload", handleChildUnload); - window.removeEventListener("beforeunload", handleParentUnload); - try { - newWin.close(); - } catch {} - childWindowRef.current = null; - containerElRef.current = null; - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + // Trigger resize event for Three.js + newWin.dispatchEvent(new Event("resize")); - useEffect(() => { - const w = childWindowRef.current; - if (w && !w.closed) { - w.document.title = title; - } - }, [title]); + // Additional safety: trigger again after a short delay + setTimeout(() => { + newWin.dispatchEvent(new Event("resize")); + }, 200); + }, 100); + }; - if (!mounted || !containerElRef.current) return null; + // Handle both load and focus events + newWin.addEventListener("load", initializeWindow); + newWin.addEventListener("focus", initializeWindow); - return createPortal(children, containerElRef.current); + // Also initialize immediately if window is already loaded + if (newWin.document.readyState === "complete") { + initializeWindow(); + } else { + newWin.addEventListener("DOMContentLoaded", initializeWindow); + } + + // Handle child window close + const handleChildUnload = () => { + onClose?.(); + }; + newWin.addEventListener("beforeunload", handleChildUnload); + + // Handle parent refresh/close โ†’ auto close child + const handleParentUnload = () => { + try { + newWin.close(); + } catch {} + }; + window.addEventListener("beforeunload", handleParentUnload); + + childWindowRef.current = newWin; + containerElRef.current = container; + setMounted(true); + + return () => { + newWin.removeEventListener("load", initializeWindow); + newWin.removeEventListener("focus", initializeWindow); + newWin.removeEventListener("DOMContentLoaded", initializeWindow); + newWin.removeEventListener("beforeunload", handleChildUnload); + window.removeEventListener("beforeunload", handleParentUnload); + try { + newWin.close(); + } catch {} + childWindowRef.current = null; + containerElRef.current = null; + }; + }, []); + + useEffect(() => { + const w = childWindowRef.current; + if (w && !w.closed) { + w.document.title = title; + } + }, [title]); + + if (!mounted || !containerElRef.current) return null; + + return createPortal(children, containerElRef.current); }; diff --git a/app/src/components/templates/LoadingPage.tsx b/app/src/components/templates/LoadingPage.tsx index 7e06262..d93ecba 100644 --- a/app/src/components/templates/LoadingPage.tsx +++ b/app/src/components/templates/LoadingPage.tsx @@ -9,14 +9,18 @@ interface LoadingPageProps { } const LoadingPage: React.FC = ({ progress }) => { + console.log('progress: ', progress); const { projectName } = useProjectName(); const { comparisonScene } = useSimulationState(); const validatedProgress = Math.min(100, Math.max(0, progress)); + console.log("comparisonScene: ", comparisonScene); return ( -
+
{projectName}
diff --git a/app/src/components/ui/compareVersion/Button.tsx b/app/src/components/ui/compareVersion/Button.tsx new file mode 100644 index 0000000..66e4124 --- /dev/null +++ b/app/src/components/ui/compareVersion/Button.tsx @@ -0,0 +1,47 @@ +import React from "react"; +import { + useCreateNewWindow, + useIsComparing, + useLoadingProgress, +} from "../../../store/builder/store"; +import { useSimulationState } from "../../../store/simulation/useSimulationStore"; + +const Button = () => { + const { isComparing, setIsComparing } = useIsComparing(); + const { createNewWindow, setCreateNewWindow } = useCreateNewWindow(); + const { setLoadingProgress } = useLoadingProgress(); + const { clearComparisonState } = useSimulationState(); + + const handleExit = () => { + setIsComparing(false); + setCreateNewWindow(false); + setLoadingProgress(0); + clearComparisonState(); + }; + + const handleOpenInNewWindow = () => { + // ๐Ÿงน Immediately reset any loading or scene state + setLoadingProgress(0); + setCreateNewWindow(true); + }; + + return ( +
+ {isComparing && } + {isComparing && !createNewWindow && ( + + )} +
+ ); +}; + +export default Button; diff --git a/app/src/components/ui/compareVersion/CompareLayOut.tsx b/app/src/components/ui/compareVersion/CompareLayOut.tsx index 23c6313..3b123f7 100644 --- a/app/src/components/ui/compareVersion/CompareLayOut.tsx +++ b/app/src/components/ui/compareVersion/CompareLayOut.tsx @@ -1,7 +1,11 @@ import { useParams } from "react-router-dom"; import React, { useState, useRef, useEffect, Suspense } from "react"; import { CompareLayoutIcon, LayoutIcon, ResizerIcon } from "../../icons/SimulationIcons"; -import { useLoadingProgress, useIsComparing } from "../../../store/builder/store"; +import { + useLoadingProgress, + useIsComparing, + useCreateNewWindow, +} from "../../../store/builder/store"; import { useSimulationState } from "../../../store/simulation/useSimulationStore"; import { usePlayButtonStore } from "../../../store/ui/usePlayButtonStore"; import { useSceneContext } from "../../../modules/scene/sceneContext"; @@ -13,11 +17,18 @@ import useRestStates from "../../../hooks/useResetStates"; import { getVersionHistoryApi } from "../../../services/factoryBuilder/versionControl/getVersionHistoryApi"; import { validateSimulationDataApi } from "../../../services/simulation/comparison/validateSimulationDataApi"; +import Button from "./Button"; const CompareLayOut = () => { const { clearComparisonState, comparisonScene, setComparisonState } = useSimulationState(); const { versionStore } = useSceneContext(); - const { versionHistory, selectedVersion, setSelectedVersion, clearSelectedVersion, setVersions } = versionStore(); + const { + versionHistory, + selectedVersion, + setSelectedVersion, + clearSelectedVersion, + setVersions, + } = versionStore(); const { setLoadingProgress } = useLoadingProgress(); const [width, setWidth] = useState("50vw"); const [isResizing, setIsResizing] = useState(false); @@ -30,6 +41,7 @@ const CompareLayOut = () => { const { setIsPlaying } = usePlayButtonStore(); const { projectId } = useParams(); const { resetStates } = useRestStates(); + const { createNewWindow } = useCreateNewWindow(); useEffect(() => { return () => { resetStates(); @@ -162,8 +174,8 @@ const CompareLayOut = () => { setLoadingProgress(1); const singleData = { projectId: projectId, - versionId: version.versionId, - productUuid: data[0].productUuid, + versionId: version.versionId, + productUuid: data[0].productUuid, }; validateSimulationDataApi(singleData).then((getData) => { @@ -178,59 +190,77 @@ const CompareLayOut = () => { }; return ( -
- {loadingProgress === 0 && selectedVersion?.versionId && ( - - )} -
- {selectedVersion?.versionId && ( -
- - - -
- )} - - {width !== "0px" && - !selectedVersion?.versionId && ( // Show only if no layout selected -
-
- + <> + {!createNewWindow && ( +
+ {loadingProgress === 0 && selectedVersion?.versionId && ( + + )} +
+ {selectedVersion?.versionId && ( +
+ + +
-
Choose Version to compare
- + )} - {showLayoutDropdown && ( -
-
Versions
- {}} /> -
- {versionHistory.map((version) => ( - - ))} + {width !== "0px" && + !selectedVersion?.versionId && ( // Show only if no layout selected +
+
+
+
Choose Version to compare
+ + + {showLayoutDropdown && ( +
+
Versions
+ {}} /> +
+ {versionHistory.map((version) => ( + + ))} +
+
+ )}
)} -
- )} - {/* Always show after layout is selected */} -
-
+ {/* Always show after layout is selected */} +
+
+ )} + ); }; diff --git a/app/src/components/ui/compareVersion/NewWindowScene.tsx b/app/src/components/ui/compareVersion/NewWindowScene.tsx new file mode 100644 index 0000000..8e09060 --- /dev/null +++ b/app/src/components/ui/compareVersion/NewWindowScene.tsx @@ -0,0 +1,44 @@ +import React, { Suspense, useEffect, useState } from "react"; +import { RenderInNewWindow } from "../../templates/CreateNewWindow"; +import { useSceneContext } from "../../../modules/scene/sceneContext"; +import { useCreateNewWindow, useLoadingProgress } from "../../../store/builder/store"; +import Scene from "../../../modules/scene/scene"; +import ComparisonResult from "./ComparisonResult"; +import Button from "./Button"; + +const NewWindowScene = () => { + const { versionStore } = useSceneContext(); + const { selectedVersion } = versionStore(); + const { setCreateNewWindow } = useCreateNewWindow(); + const { loadingProgress } = useLoadingProgress(); + + return ( + <> + {selectedVersion?.versionId && ( +
+ + setCreateNewWindow(false)} + > +
+
+ + {!loadingProgress && } +
+
+
+ )} + + ); +}; + +export default NewWindowScene; diff --git a/app/src/components/ui/log/LogList.tsx b/app/src/components/ui/log/LogList.tsx index b7b39dc..8f420d6 100644 --- a/app/src/components/ui/log/LogList.tsx +++ b/app/src/components/ui/log/LogList.tsx @@ -1,185 +1,164 @@ import React, { useEffect, useState } from "react"; -import { - LogListIcon, - CloseIcon, - ExpandIcon2, -} from "../../icons/ExportCommonIcons"; // Adjust path as needed +import { LogListIcon, CloseIcon, ExpandIcon2 } from "../../icons/ExportCommonIcons"; // Adjust path as needed import { LogEntry, useLogger } from "./LoggerContext"; import { GetLogIcon } from "../../footer/getLogIcons"; import { RenderInNewWindow } from "../../templates/CreateNewWindow"; // --- Logs Component --- type LogsProps = { - selectedTab: "all" | "info" | "warning" | "error"; - setSelectedTab: (tab: "all" | "info" | "warning" | "error") => void; - clear: () => void; - filteredLogs: LogEntry[]; - formatTimestamp: (date: Date) => string; + selectedTab: "all" | "info" | "warning" | "error"; + setSelectedTab: (tab: "all" | "info" | "warning" | "error") => void; + clear: () => void; + filteredLogs: LogEntry[]; + formatTimestamp: (date: Date) => string; }; const Logs: React.FC = ({ - selectedTab, - setSelectedTab, - clear, - filteredLogs, - formatTimestamp, + selectedTab, + setSelectedTab, + clear, + filteredLogs, + formatTimestamp, }) => { - return ( - <> -
-
- {["all", "info", "warning", "error"].map((type) => ( - - ))} -
- -
- - {/* Log Entries */} -
- {filteredLogs.length > 0 ? ( - filteredLogs.map((log) => ( -
-
{GetLogIcon(log.type)}
-
-
{log.message}
-
- {formatTimestamp(log.timestamp)} + return ( + <> +
+
+ {["all", "info", "warning", "error"].map((type) => ( + + ))}
-
+
- )) - ) : ( -
- There are no logs to display at the moment. -
- )} -
- - ); + + {/* Log Entries */} +
+ {filteredLogs.length > 0 ? ( + filteredLogs.map((log) => ( +
+
{GetLogIcon(log.type)}
+
+
{log.message}
+
{formatTimestamp(log.timestamp)}
+
+
+ )) + ) : ( +
There are no logs to display at the moment.
+ )} +
+ + ); }; // --- LogList Component --- const LogList: React.FC = () => { - const { - logs, - clear, - setIsLogListVisible, - isLogListVisible, - selectedTab, - setSelectedTab, - } = useLogger(); + const { logs, clear, setIsLogListVisible, isLogListVisible, selectedTab, setSelectedTab } = + useLogger(); - const formatTimestamp = (date: Date) => new Date(date).toLocaleTimeString(); - const [open, setOpen] = useState(false); + const formatTimestamp = (date: Date) => new Date(date).toLocaleTimeString(); + const [open, setOpen] = useState(false); + console.log('open: ', open); + const filteredLogs = + selectedTab === "all" + ? [...logs].reverse() + : [...logs].filter((log) => log.type === selectedTab).reverse(); - const filteredLogs = - selectedTab === "all" - ? [...logs].reverse() - : [...logs].filter((log) => log.type === selectedTab).reverse(); + useEffect(() => { + if (isLogListVisible && logs.length > 0) { + const lastLog = logs[logs.length - 1]; + const validTypes = ["all", "info", "warning", "error"]; + if (validTypes.includes(lastLog.type)) { + setSelectedTab(lastLog.type as any); + } else { + setSelectedTab("all"); + } + } + // eslint-disable-next-line + }, [isLogListVisible]); - useEffect(() => { - if (isLogListVisible && logs.length > 0) { - const lastLog = logs[logs.length - 1]; - const validTypes = ["all", "info", "warning", "error"]; - if (validTypes.includes(lastLog.type)) { - setSelectedTab(lastLog.type as any); - } else { - setSelectedTab("all"); - } - } - // eslint-disable-next-line - }, [isLogListVisible]); + return ( + <> + {!open ? ( +
setIsLogListVisible(false)}> + {/* eslint-disable-next-line */} +
{ + e.stopPropagation(); + }} + > +
+
+
+ +
+
Log List
+
+
+ + +
+
- return ( - <> - {!open ? ( -
setIsLogListVisible(false)} - > - {/* eslint-disable-next-line */} -
{ - e.stopPropagation(); - }} - > -
-
-
- + {/* Logs Section */} + +
-
Log List
-
-
- - -
-
- - {/* Logs Section */} - -
-
- ) : ( - { - setOpen(false); - setIsLogListVisible(false); - }} - > -
- -
-
- )} - - ); +
+ +
+ + )} + + ); }; export default LogList; + \ No newline at end of file diff --git a/app/src/modules/builder/asset/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx index 6fadd18..2a4834c 100644 --- a/app/src/modules/builder/asset/models/model/model.tsx +++ b/app/src/modules/builder/asset/models/model/model.tsx @@ -13,13 +13,17 @@ import { getAssetFieldApi } from "../../../../../services/factoryBuilder/asset/f import { ModelAnimator } from "./animator/modelAnimator"; import { useModelEventHandlers } from "./eventHandlers/useModelEventHandlers"; -function Model({ asset, isRendered, loader }: Readonly<{ asset: Asset; isRendered: boolean; loader: GLTFLoader }>) { +function Model({ + asset, + isRendered, + loader, +}: Readonly<{ asset: Asset; isRendered: boolean; loader: GLTFLoader }>) { const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; const savedTheme: string = localStorage.getItem("theme") || "light"; const { toolMode } = useToolMode(); const { toggleView } = useToggleView(); const { activeModule } = useModuleStore(); - const { assetStore } = useSceneContext(); + const { assetStore, layout } = useSceneContext(); const { resetAnimation, hasSelectedAsset, updateSelectedAsset, selectedAssets } = assetStore(); const { setDeletableFloorAsset } = useBuilderStore(); const [gltfScene, setGltfScene] = useState(null); @@ -52,7 +56,12 @@ function Model({ asset, isRendered, loader }: Readonly<{ asset: Asset; isRendere }, [activeModule, toolMode, selectedAssets]); useEffect(() => { - if (groupRef.current && selectedAssets.length === 1 && selectedAssets[0].userData.modelUuid === asset.modelUuid && hasSelectedAsset(asset.modelUuid)) { + if ( + groupRef.current && + selectedAssets.length === 1 && + selectedAssets[0].userData.modelUuid === asset.modelUuid && + hasSelectedAsset(asset.modelUuid) + ) { updateSelectedAsset(groupRef.current); } }, [isRendered, selectedAssets, asset]); @@ -130,7 +139,10 @@ function Model({ asset, isRendered, loader }: Readonly<{ asset: Asset; isRendere logModelStatus(assetId, "backend-loaded"); }) .catch((error) => { - console.error(`[Backend] Error storing/loading ${asset.modelName}:`, error); + console.error( + `[Backend] Error storing/loading ${asset.modelName}:`, + error + ); }); }, undefined, @@ -144,7 +156,8 @@ function Model({ asset, isRendered, loader }: Readonly<{ asset: Asset; isRendere }); }, []); - const { handleDblClick, handleClick, handlePointerOver, handlePointerOut, handleContextMenu } = useModelEventHandlers({ boundingBox, groupRef, asset }); + const { handleDblClick, handleClick, handlePointerOver, handlePointerOut, handleContextMenu } = + useModelEventHandlers({ boundingBox, groupRef, asset }); return ( ) : ( - <>{!hasSelectedAsset(asset.modelUuid) && } + <> + {!hasSelectedAsset(asset.modelUuid) && ( + + )} + + )} + {hasSelectedAsset(asset.modelUuid) && ( + )} - {hasSelectedAsset(asset.modelUuid) && } )} diff --git a/app/src/modules/builder/asset/models/models.tsx b/app/src/modules/builder/asset/models/models.tsx index 588a617..2291aba 100644 --- a/app/src/modules/builder/asset/models/models.tsx +++ b/app/src/modules/builder/asset/models/models.tsx @@ -3,7 +3,11 @@ import { Group, Vector3 } from "three"; import { CameraControls } from "@react-three/drei"; import { GLTFLoader } from "three/examples/jsm/Addons"; import { useThree, useFrame } from "@react-three/fiber"; -import { useContextActionStore, useLimitDistance, useRenderDistance } from "../../../../store/builder/store"; +import { + useContextActionStore, + useLimitDistance, + useRenderDistance, +} from "../../../../store/builder/store"; import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore"; import { useSceneContext } from "../../../scene/sceneContext"; import useZoomMesh from "../../hooks/useZoomMesh"; @@ -11,12 +15,14 @@ import useCallBackOnKey from "../../../../utils/hooks/useCallBackOnKey"; import Model from "./model/model"; -const distanceWorker = new Worker(new URL("../../../../services/factoryBuilder/webWorkers/distanceWorker.js", import.meta.url)); +const distanceWorker = new Worker( + new URL("../../../../services/factoryBuilder/webWorkers/distanceWorker.js", import.meta.url) +); function Models({ loader }: { readonly loader: GLTFLoader }) { const { controls, camera } = useThree(); const assetGroupRef = useRef(null); - const { assetStore } = useSceneContext(); + const { assetStore, layout } = useSceneContext(); const { assets, selectedAssets, getSelectedAssetUuids } = assetStore(); const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); const { contextAction, setContextAction } = useContextActionStore(); @@ -30,6 +36,14 @@ function Models({ loader }: { readonly loader: GLTFLoader }) { // console.log(assets); }, [assets]); + useEffect(() => { + const initialRenderMap: Record = {}; + assets.forEach((asset) => { + initialRenderMap[asset.modelUuid] = true; + }); + setRenderMap(initialRenderMap); + }, [assets.length]); + useEffect(() => { if (contextAction === "focusAsset") { zoomMeshes(getSelectedAssetUuids()); @@ -55,20 +69,51 @@ function Models({ loader }: { readonly loader: GLTFLoader }) { return { ...prev, [modelUuid]: shouldRender }; }); }; - }, []); + + return () => { + distanceWorker.terminate(); + }; + }, [distanceWorker, layout]); useFrame(() => { camera.getWorldPosition(cameraPos.current); for (const asset of assets) { const isRendered = renderMap[asset.modelUuid] ?? false; - distanceWorker.postMessage({ - modelUuid: asset.modelUuid, - assetPosition: { x: asset.position[0], y: asset.position[1], z: asset.position[2] }, - cameraPosition: cameraPos.current, - limitDistance, - renderDistance, - isRendered, - }); + // distanceWorker.postMessage({ + // modelUuid: asset.modelUuid, + // assetPosition: { x: asset.position[0], y: asset.position[1], z: asset.position[2] }, + // cameraPosition: cameraPos.current, + // limitDistance, + // renderDistance, + // isRendered, + // }); + + const assetVec = new Vector3(...asset.position); + const cameraVec = new Vector3( + cameraPos.current.x, + cameraPos.current.y, + cameraPos.current.z + ); + const distance = assetVec.distanceTo(cameraVec); + + if (limitDistance) { + if (!isRendered && distance <= renderDistance) { + setRenderMap((prev) => { + if (prev[asset.modelUuid] === true) return prev; + return { ...prev, [asset.modelUuid]: true }; + }); + } else if (isRendered && distance > renderDistance) { + setRenderMap((prev) => { + if (prev[asset.modelUuid] === false) return prev; + return { ...prev, [asset.modelUuid]: false }; + }); + } + } else if (!isRendered) { + setRenderMap((prev) => { + if (prev[asset.modelUuid] === true) return prev; + return { ...prev, [asset.modelUuid]: true }; + }); + } } }); @@ -88,7 +133,12 @@ function Models({ loader }: { readonly loader: GLTFLoader }) { }} > {assets.map((asset) => ( - + ))} ); diff --git a/app/src/modules/scene/camera/syncCam.tsx b/app/src/modules/scene/camera/syncCam.tsx index 2d4026b..dd2ebd3 100644 --- a/app/src/modules/scene/camera/syncCam.tsx +++ b/app/src/modules/scene/camera/syncCam.tsx @@ -2,13 +2,11 @@ import { Vector3 } from "three"; import { useFrame, useThree } from "@react-three/fiber"; import { CameraControls } from "@react-three/drei"; import { useSceneContext } from "../sceneContext"; -import { useIsComparing } from "../../../store/builder/store"; +import { useCreateNewWindow, useIsComparing } from "../../../store/builder/store"; import { useSceneStore } from "../../../store/scene/useSceneStore"; import { useSimulationState } from "../../../store/simulation/useSimulationStore"; import useModuleStore from "../../../store/ui/useModuleStore"; -import * as CONSTANTS from "../../../types/world/worldConstants"; - function SyncCam() { const { layout } = useSceneContext(); const { controls } = useThree(); @@ -16,19 +14,39 @@ function SyncCam() { const { activeModule } = useModuleStore(); const { comparisonScene } = useSimulationState(); const { setCamera, camState } = useSceneStore(); + const { windowRendered } = useCreateNewWindow(); + + function getControls() { + const position = (controls as CameraControls).getPosition(new Vector3()); + const target = (controls as CameraControls).getTarget(new Vector3()); + setCamera(position, target); + } + + function setControls() { + (controls as CameraControls).setLookAt( + camState.position.x, + camState.position.y, + camState.position.z, + camState.target.x, + camState.target.y, + camState.target.z, + true + ); + } useFrame(() => { - if (layout === "Comparison Layout" && controls && camState) { - (controls as any).mouseButtons.left = CONSTANTS.controlsTransition.leftMouse; - (controls as any).mouseButtons.right = CONSTANTS.controlsTransition.rightMouse; - (controls as any).mouseButtons.wheel = CONSTANTS.controlsTransition.wheelMouse; - (controls as any).mouseButtons.middle = CONSTANTS.controlsTransition.middleMouse; - (controls as CameraControls).setLookAt(camState.position.x, camState.position.y, camState.position.z, camState.target.x, camState.target.y, camState.target.z, true); - } - if (layout === "Main Layout" && controls && isComparing && activeModule === "simulation" && comparisonScene) { - const position = (controls as CameraControls).getPosition(new Vector3()); - const target = (controls as CameraControls).getTarget(new Vector3()); - setCamera(position, target); + if ( + controls && + isComparing && + activeModule === "simulation" && + comparisonScene && + camState + ) { + if (layout === windowRendered) { + getControls(); + } else { + setControls(); + } } }); diff --git a/app/src/modules/scene/scene.tsx b/app/src/modules/scene/scene.tsx index fe59f21..c4939be 100644 --- a/app/src/modules/scene/scene.tsx +++ b/app/src/modules/scene/scene.tsx @@ -1,5 +1,5 @@ import { useEffect, useMemo } from "react"; -import { Canvas } from "@react-three/fiber"; +import { Canvas, useThree } from "@react-three/fiber"; import { KeyboardControls } from "@react-three/drei"; import { useSceneContext } from "./sceneContext"; @@ -11,13 +11,17 @@ import Collaboration from "../collaboration/collaboration"; import useModuleStore from "../../store/ui/useModuleStore"; import { useParams } from "react-router-dom"; import { getUserData } from "../../functions/getUserData"; -import { useLoadingProgress } from "../../store/builder/store"; +import { useCreateNewWindow, useLoadingProgress } from "../../store/builder/store"; import { useSocketStore } from "../../store/socket/useSocketStore"; import { Color, SRGBColorSpace } from "three"; import { compressImage } from "../../utils/compressImage"; import { ALPHA_ORG } from "../../pages/Dashboard"; -export default function Scene({ layout }: { readonly layout: "Main Layout" | "Comparison Layout" }) { +export default function Scene({ + layout, +}: { + readonly layout: "Main Layout" | "Comparison Layout"; +}) { const map = useMemo( () => [ { name: "forward", keys: ["ArrowUp", "w", "W"] }, @@ -35,11 +39,16 @@ export default function Scene({ layout }: { readonly layout: "Main Layout" | "Co const { projectSocket } = useSocketStore(); const { activeModule } = useModuleStore(); const { loadingProgress } = useLoadingProgress(); + const { setWindowRendered } = useCreateNewWindow(); useEffect(() => { if (!projectId || loadingProgress !== 0) return; const canvas = document.getElementById("sceneCanvas")?.getElementsByTagName("canvas")[0]; - if (!canvas || !(layoutType === "default" || (layoutType === "useCase" && organization === ALPHA_ORG))) return; + if ( + !canvas || + !(layoutType === "default" || (layoutType === "useCase" && organization === ALPHA_ORG)) + ) + return; compressImage(canvas.toDataURL("image/png")).then((screenshotDataUrl) => { const updateProjects = { projectId, @@ -64,11 +73,21 @@ export default function Scene({ layout }: { readonly layout: "Main Layout" | "Co onContextMenu={(e) => { e.preventDefault(); }} + resize={{ polyfill: ResizeObserver }} + style={{ width: "100vw", height: "100vh", background: "#202020" }} performance={{ min: 0.9, max: 1.0 }} onCreated={(e) => { e.scene.background = layout === "Main Layout" ? null : new Color(0x19191d); }} - gl={{ outputColorSpace: SRGBColorSpace, powerPreference: "high-performance", antialias: true, preserveDrawingBuffer: true }} + gl={{ + outputColorSpace: SRGBColorSpace, + powerPreference: "high-performance", + antialias: true, + preserveDrawingBuffer: true, + }} + onPointerEnter={() => { + setWindowRendered(layout); + }} > diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 4665702..162b6ad 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -171,6 +171,7 @@ const Project: React.FC = () => { + {selectedUser && } diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index bb913c1..bda5a2b 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -138,7 +138,8 @@ export const useDrieTemp = create((set: any) => ({ export const useDrieUIValue = create((set: any) => ({ drieUIValue: { touch: null, temperature: null, humidity: null }, - setDrieUIValue: (x: any) => set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })), + setDrieUIValue: (x: any) => + set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })), setTouch: (value: any) => set((state: any) => ({ @@ -462,9 +463,18 @@ interface DecalStore { // Create the Zustand store with types export const useDecalStore = create((set) => ({ selectedSubCategory: "Safety", - setSelectedSubCategory: (subCategory: string | null) => set({ selectedSubCategory: subCategory }), + setSelectedSubCategory: (subCategory: string | null) => + set({ selectedSubCategory: subCategory }), })); + export const comparsionMaterialData = create((set: any) => ({ materialData: [], setMaterialData: (x: any) => set({ materialData: x }), })); + +export const useCreateNewWindow = create((set: any) => ({ + createNewWindow: false, + setCreateNewWindow: (x: any) => set({ createNewWindow: x }), + windowRendered: "", + setWindowRendered: (x: any) => set({ windowRendered: x }), +}));