Refactor components and improve loading behavior

- Simplified rendering of CompareLayOut and ComparisonScene components.
- Enhanced MainScene to log createNewWindow state and conditionally render LoadingPage.
- Updated GlobalProperties to improve environment settings handling.
- Refactored LoadingPage to support rendering as a portal and added new props for flexibility.
- Improved NewWindowScene to include LoadingPage and handle loading progress.
- Added console logs for debugging in calculateSimulationData and ComparisonResult components.
- Cleaned up unused code and improved readability across various components.
- Adjusted styles in loading.scss for better visual consistency and responsiveness.
This commit is contained in:
2025-10-13 16:16:45 +05:30
parent 97f9f9a381
commit 7693f1ea9d
12 changed files with 477 additions and 343 deletions

View File

@@ -220,7 +220,7 @@ function ComparisonScene() {
<Button />
</div>
)}
{<CompareLayOut />}
<CompareLayOut />
{createNewWindow && <NewWindowScene />}
{shouldShowComparisonResult && !loadingProgress && <ComparisonResult />}
</>

View File

@@ -1,6 +1,14 @@
import { useEffect } from "react";
import { useParams } from "react-router-dom";
import { useLoadingProgress, useRenameModeStore, useIsComparing, useSelectedComment, useWidgetSubOption, useToggleView } from "../../../store/builder/store";
import {
useLoadingProgress,
useRenameModeStore,
useIsComparing,
useSelectedComment,
useWidgetSubOption,
useToggleView,
useCreateNewWindow,
} from "../../../store/builder/store";
import useModuleStore from "../../../store/ui/useModuleStore";
import { useSocketStore } from "../../../store/socket/useSocketStore";
import { usePlayButtonStore } from "../../../store/ui/usePlayButtonStore";
@@ -55,7 +63,11 @@ function MainScene() {
const { selectedComment, commentPositionState } = useSelectedComment();
const { resetStates } = useRestStates();
const { organization, userId } = getUserData();
const { createNewWindow } = useCreateNewWindow();
useEffect(() => {
console.log("createNewWindow: ", createNewWindow);
}, [createNewWindow]);
useEffect(() => {
return () => {
resetStates();
@@ -106,9 +118,13 @@ function MainScene() {
useEffect(() => {
if (versionHistory.length > 0) {
recentlyViewedApi().then((projects) => {
const recent_opened_verisionID = (Object.values(projects?.RecentlyViewed || {})[0] as any)?.Present_version._id;
const recent_opened_verisionID = (
Object.values(projects?.RecentlyViewed || {})[0] as any
)?.Present_version._id;
if (recent_opened_verisionID && projects.RecentlyViewed[0]._id === projectId) {
const version = versionHistory.find((ver) => ver.versionId === recent_opened_verisionID);
const version = versionHistory.find(
(ver) => ver.versionId === recent_opened_verisionID
);
if (version) {
setSelectedVersion(version);
}
@@ -186,7 +202,9 @@ function MainScene() {
{!selectedUser && (
<>
<KeyPressListener />
{loadingProgress > 0 && <LoadingPage progress={loadingProgress} />}
{!createNewWindow && loadingProgress > 0 && (
<LoadingPage progress={loadingProgress} />
)}
{!isPlaying && (
<>
{!toggleView && !isComparing && <ModuleToggle />}
@@ -197,20 +215,41 @@ function MainScene() {
<RealTimeVisulization />
{activeModule === "market" && <MarketPlace />}
{activeModule !== "market" && !isPlaying && !isComparing && <Tools />}
{isPlaying && activeModule === "simulation" && loadingProgress === 0 && <SimulationPlayer />}
{isPlaying && activeModule === "simulation" && loadingProgress === 0 && (
<SimulationPlayer />
)}
{isPlaying && activeModule !== "simulation" && <ControlsPlayer />}
{isRenameMode && selectedAssets.length === 1 && <RenameTooltip name={selectedAssets[0].userData.modelName} onSubmit={handleObjectRename} />}
{isRenameMode && selectedAssets.length === 1 && (
<RenameTooltip
name={selectedAssets[0].userData.modelName}
onSubmit={handleObjectRename}
/>
)}
{activeModule === "builder" && toggleView && <SelectFloorPlan />}
{selectedProduct && selectedVersion && isComparing && !isPlaying && activeModule === "simulation" && (
<div className="selectLayout-wrapper">
<RegularDropDown header={selectedVersion.versionName} options={versionHistory.map((v) => v.versionName)} onSelect={handleSelectVersion} search={false} />
<br />
<RegularDropDown header={selectedProduct.productName} options={products.map((l) => l.productName)} onSelect={handleSelectProduct} search={false} />
</div>
)}
{selectedProduct &&
selectedVersion &&
isComparing &&
!isPlaying &&
activeModule === "simulation" && (
<div className="selectLayout-wrapper">
<RegularDropDown
header={selectedVersion.versionName}
options={versionHistory.map((v) => v.versionName)}
onSelect={handleSelectVersion}
search={false}
/>
<br />
<RegularDropDown
header={selectedProduct.productName}
options={products.map((l) => l.productName)}
onSelect={handleSelectProduct}
search={false}
/>
</div>
)}
<VersionSaved />
</>

View File

@@ -68,6 +68,7 @@ export const calculateSimulationData = (assets: AssetData[]) => {
});
const machineActiveTime = assets.filter((a) => a.type === "human").reduce((acc, a) => acc + a.activeTime, 0);
console.log('assets: ', assets);
const machineIdleTime = assets.filter((a) => a.type === "machine").reduce((acc, a) => acc + a.idleTime, 0);

View File

@@ -44,7 +44,16 @@ const GlobalProperties: React.FC = () => {
const optimizeScene = async (value: any) => {
if (!projectId) return;
setEnvironment(organization, userId, wallVisibility, roofVisibility, shadows, 30, true, projectId);
setEnvironment(
organization,
userId,
wallVisibility,
roofVisibility,
shadows,
30,
true,
projectId
);
setRenderDistance(30);
setLimitDistance(true);
};
@@ -52,10 +61,28 @@ const GlobalProperties: React.FC = () => {
const limitRenderDistance = async () => {
if (!projectId) return;
if (limitDistance) {
setEnvironment(organization, userId, wallVisibility, roofVisibility, shadows, 75, !limitDistance, projectId);
setEnvironment(
organization,
userId,
wallVisibility,
roofVisibility,
shadows,
75,
!limitDistance,
projectId
);
setRenderDistance(75);
} else {
setEnvironment(organization, userId, wallVisibility, roofVisibility, shadows, renderDistance, !limitDistance, projectId);
setEnvironment(
organization,
userId,
wallVisibility,
roofVisibility,
shadows,
renderDistance,
!limitDistance,
projectId
);
}
setLimitDistance(!limitDistance);
};
@@ -84,7 +111,16 @@ const GlobalProperties: React.FC = () => {
if (!projectId) return;
setRenderDistance(value);
// setDistance(value);
const data = await setEnvironment(organization, userId, wallVisibility, roofVisibility, shadows, value, limitDistance, projectId);
const data = await setEnvironment(
organization,
userId,
wallVisibility,
roofVisibility,
shadows,
value,
limitDistance,
projectId
);
};
// Function to toggle roof visibility
@@ -92,7 +128,16 @@ const GlobalProperties: React.FC = () => {
if (!projectId) return;
//using REST
const data = await setEnvironment(organization, userId, wallVisibility, !roofVisibility, shadows, renderDistance, limitDistance, projectId);
const data = await setEnvironment(
organization,
userId,
wallVisibility,
!roofVisibility,
shadows,
renderDistance,
limitDistance,
projectId
);
//using Socket
// const visData = {
@@ -112,7 +157,16 @@ const GlobalProperties: React.FC = () => {
if (!projectId) return;
//using REST
const data = await setEnvironment(organization, userId, !wallVisibility, roofVisibility, shadows, renderDistance, limitDistance, projectId);
const data = await setEnvironment(
organization,
userId,
!wallVisibility,
roofVisibility,
shadows,
renderDistance,
limitDistance,
projectId
);
//using Socket
// const visData = {
@@ -132,7 +186,16 @@ const GlobalProperties: React.FC = () => {
if (!projectId) return;
//using REST
const data = await setEnvironment(organization, userId, wallVisibility, roofVisibility, !shadows, renderDistance, limitDistance, projectId);
const data = await setEnvironment(
organization,
userId,
wallVisibility,
roofVisibility,
!shadows,
renderDistance,
limitDistance,
projectId
);
//using Socket
// const visData = {
@@ -165,14 +228,34 @@ const GlobalProperties: React.FC = () => {
<div className="split"></div>
<InputToggle value={roofVisibility} inputKey="1" label="Roof Visibility" onClick={changeRoofVisibility} />
<InputToggle value={wallVisibility} inputKey="2" label="Wall Visibility" onClick={changeWallVisibility} />
<InputToggle value={shadows} inputKey="3" label="Shadows Visibility" onClick={shadowVisibility} />
<InputToggle
value={roofVisibility}
inputKey="1"
label="Roof Visibility"
onClick={changeRoofVisibility}
/>
<InputToggle
value={wallVisibility}
inputKey="2"
label="Wall Visibility"
onClick={changeWallVisibility}
/>
<InputToggle
value={shadows}
inputKey="3"
label="Shadows Visibility"
onClick={shadowVisibility}
/>
<LabeledButton label="Reset Camera" onClick={toggleResetCamera} value="Reset" />
<div className="split"></div>
<InputToggle inputKey="4" label="Limit Render Distance" value={limitDistance} onClick={limitRenderDistance} />
<InputToggle
inputKey="4"
label="Limit Render Distance"
value={limitDistance}
onClick={limitRenderDistance}
/>
<InputRange
label="Distance"
disabled={!limitDistance}
@@ -186,7 +269,12 @@ const GlobalProperties: React.FC = () => {
<div className="split"></div>
<InputToggle inputKey="7" label="Limit Fps" value={limitFps} onClick={limitFpsToggle} />
<InputToggle
inputKey="7"
label="Limit Fps"
value={limitFps}
onClick={limitFpsToggle}
/>
<InputRange
label="Fps"
disabled={!limitFps}

View File

@@ -24,159 +24,6 @@ type NewWindowProps = {
theme?: string | null;
};
// export const RenderInNewWindow: React.FC<NewWindowProps> = ({
// 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<Window | null>(null);
// const containerElRef = useRef<HTMLDivElement | null>(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(`<!doctype html>
// <html data-theme=${theme}>
// <head>
// <meta charset="utf-8" />
// <title>${title}</title>
// <meta name="viewport" content="width=device-width, initial-scale=1" />
// </head>
// <body style="margin:0;"></body>
// </html>`);
// 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<NewWindowProps> = ({
children,
title = "3D Viewer",
@@ -207,10 +54,12 @@ export const RenderInNewWindow: React.FC<NewWindowProps> = ({
const finalLeft =
center && availWidth ? Math.max(0, screenLeft + (availWidth - width) / 2) : left ?? 100;
console.log("finalLeft: ", finalLeft);
const finalTop =
center && availHeight
? Math.max(0, screenTop + (availHeight - height) / 2)
: top ?? 100;
console.log("finalTop: ", finalTop);
const baseFeatures = [
`width=${Math.floor(width)}`,
@@ -370,6 +219,16 @@ export const RenderInNewWindow: React.FC<NewWindowProps> = ({
};
}, []);
useEffect(() => {
const handleResize = () => {
childWindowRef.current?.dispatchEvent(new Event("resize"));
};
childWindowRef.current?.addEventListener("resize", handleResize);
return () => {
childWindowRef.current?.removeEventListener("resize", handleResize);
};
}, []);
useEffect(() => {
const w = childWindowRef.current;
if (w && !w.closed) {

View File

@@ -1,47 +1,65 @@
import React from "react";
import RenderOverlay from "./Overlay";
import ReactDOM from "react-dom";
import { LogoIconLarge } from "../icons/Logo";
import { useProjectName } from "../../store/builder/store";
import { useSimulationState } from "../../store/simulation/useSimulationStore";
import RenderOverlay from "./Overlay";
interface LoadingPageProps {
progress: number; // Expect progress as a percentage (0-100)
progress: number;
renderOver?: boolean;
returnDefault?: boolean;
}
const LoadingPage: React.FC<LoadingPageProps> = ({ progress }) => {
console.log('progress: ', progress);
const LoadingPage: React.FC<LoadingPageProps> = ({
progress,
renderOver = true,
returnDefault = false,
}) => {
const { projectName } = useProjectName();
const { comparisonScene } = useSimulationState();
const validatedProgress = Math.min(100, Math.max(0, progress));
console.log("comparisonScene: ", comparisonScene);
return (
<RenderOverlay>
<div
className={`loading-wrapper ${comparisonScene != null ? "comparisionLoading" : ""}`}
>
<div className="loading-container">
<div className="project-name">{projectName}</div>
<div className="loading-hero-container">
<div className="logo">
<LogoIconLarge />
</div>
<div className="content">Entering A New World with your Aalai</div>
// Portal target (defaults to body)
const portalRoot = document.getElementById("root") || document.body;
const content = (
<div
className={`loading-wrapper ${
comparisonScene != null && !returnDefault ? "comparisionLoading" : ""
}`}
>
<div className="loading-container">
<div className="project-name">{projectName}</div>
<div className="loading-hero-container">
<div className="logo">
<LogoIconLarge />
</div>
<div className="progress-container">
<div className="progress-value">{validatedProgress}%</div>
<div className="progress-indicator-container">
<div
className="progress-bar"
style={{ width: `${validatedProgress}%` }} // Dynamic width
></div>
</div>
<div className="content">Entering A New World with your Aalai</div>
</div>
<div className="progress-container">
<div className="progress-value">{validatedProgress}%</div>
<div className="progress-indicator-container">
<div
className="progress-bar"
style={{ width: `${validatedProgress}%` }}
></div>
</div>
</div>
</div>
</RenderOverlay>
</div>
);
if (returnDefault) {
return content;
}
if (renderOver) {
return <RenderOverlay>{content}</RenderOverlay>;
}
// Render the loading screen as a portal
return ReactDOM.createPortal(content, portalRoot);
};
export default LoadingPage;

View File

@@ -2,26 +2,35 @@ import React from "react";
import {
useCreateNewWindow,
useIsComparing,
useLoadingProgress,
useLimitDistance,
useRenderDistance,
} from "../../../store/builder/store";
import { useSimulationState } from "../../../store/simulation/useSimulationStore";
import { useParams } from "react-router-dom";
import { findEnvironment } from "../../../services/factoryBuilder/environment/findEnvironment";
const Button = () => {
const { isComparing, setIsComparing } = useIsComparing();
const { createNewWindow, setCreateNewWindow } = useCreateNewWindow();
const { setLoadingProgress } = useLoadingProgress();
const { clearComparisonState } = useSimulationState();
const { projectId } = useParams();
const { setRenderDistance } = useRenderDistance();
const { setLimitDistance } = useLimitDistance();
const handleExit = () => {
setIsComparing(false);
setCreateNewWindow(false);
setLoadingProgress(0);
clearComparisonState();
if (!projectId) return;
findEnvironment(projectId).then((data) => {
if (!data) return;
setRenderDistance(data.renderDistance);
setLimitDistance(data.limitDistance);
});
};
const handleOpenInNewWindow = () => {
// 🧹 Immediately reset any loading or scene state
setLoadingProgress(0);
// setLoadingProgress(0);
setCreateNewWindow(true);
};

View File

@@ -5,6 +5,7 @@ import {
useLoadingProgress,
useIsComparing,
useCreateNewWindow,
useLimitDistance,
} from "../../../store/builder/store";
import { useSimulationState } from "../../../store/simulation/useSimulationStore";
import { usePlayButtonStore } from "../../../store/ui/usePlayButtonStore";
@@ -17,7 +18,6 @@ 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();
@@ -42,6 +42,7 @@ const CompareLayOut = () => {
const { projectId } = useParams();
const { resetStates } = useRestStates();
const { createNewWindow } = useCreateNewWindow();
const { limitDistance, setLimitDistance } = useLimitDistance();
useEffect(() => {
return () => {
resetStates();
@@ -188,7 +189,10 @@ const CompareLayOut = () => {
}
});
};
console.log("limitDistance: ", limitDistance);
useEffect(() => {
setLimitDistance(false);
}, [limitDistance]);
return (
<>
{!createNewWindow && (

View File

@@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from "react";
import PerformanceResult from "./result-card/PerformanceResult";
import { Bar, Pie } from "react-chartjs-2";
import { useCompareProductDataStore } from "../../../store/builder/store";
import { useSimulationState } from "../../../store/simulation/useSimulationStore";
import { useSimulationState } from "../../../store/simulation/useSimulationStore";
export interface CompareProduct {
productUuid: string;
@@ -24,9 +24,12 @@ export interface CompareProduct {
const ComparisonResult = () => {
const { compareProductsData } = useCompareProductDataStore();
const { comparisonScene, mainScene } = useSimulationState();
const [comparedProducts, setComparedProducts] = useState<[CompareProduct, CompareProduct] | []>([]);
const [comparedProducts, setComparedProducts] = useState<[CompareProduct, CompareProduct] | []>(
[]
);
useEffect(() => {
console.log("compareProductsData: ", compareProductsData);
if (compareProductsData.length > 0 && comparisonScene && mainScene) {
setComparedProducts([compareProductsData[0], compareProductsData[1]]);
} else {
@@ -34,11 +37,6 @@ const ComparisonResult = () => {
}
}, [compareProductsData, comparisonScene, mainScene]);
useEffect(() => {
if (comparedProducts.length === 2) {
}
}, [comparedProducts]);
const options = useMemo(
() => ({
responsive: true,
@@ -64,7 +62,10 @@ const ComparisonResult = () => {
datasets: [
{
label: "Throughput (units/hr)",
data: [comparedProducts[0]?.simulationData.throughputData, comparedProducts[1]?.simulationData.throughputData],
data: [
comparedProducts[0]?.simulationData.throughputData,
comparedProducts[1]?.simulationData.throughputData,
],
backgroundColor: [purpleDark, purpleLight],
borderColor: [purpleDark, purpleLight],
borderWidth: 1,
@@ -79,7 +80,10 @@ const ComparisonResult = () => {
datasets: [
{
label: "Cycle Time (sec)",
data: [comparedProducts[0]?.simulationData.machineActiveTime, comparedProducts[1]?.simulationData.machineActiveTime],
data: [
comparedProducts[0]?.simulationData.machineActiveTime,
comparedProducts[1]?.simulationData.machineActiveTime,
],
backgroundColor: [purpleDark, purpleLight],
borderColor: "#fff",
borderWidth: 2,
@@ -92,7 +96,10 @@ const ComparisonResult = () => {
datasets: [
{
label: "Downtime (mins)",
data: [comparedProducts[0]?.simulationData.machineIdleTime, comparedProducts[1]?.simulationData.machineIdleTime],
data: [
comparedProducts[0]?.simulationData.machineIdleTime,
comparedProducts[1]?.simulationData.machineIdleTime,
],
backgroundColor: [purpleDark, purpleLight],
borderColor: "#fff",
borderWidth: 2,
@@ -105,7 +112,10 @@ const ComparisonResult = () => {
datasets: [
{
label: "Production Capacity (units)",
data: [comparedProducts[0]?.simulationData.productionCapacity, comparedProducts[1]?.simulationData.productionCapacity],
data: [
comparedProducts[0]?.simulationData.productionCapacity,
comparedProducts[1]?.simulationData.productionCapacity,
],
backgroundColor: [purpleDark, purpleLight],
borderColor: [purpleDark, purpleLight],
borderWidth: 1,
@@ -116,25 +126,40 @@ const ComparisonResult = () => {
};
const highestProductivityProduct =
(comparedProducts[0]?.simulationData?.productionCapacity ?? 0) > (comparedProducts[1]?.simulationData?.productionCapacity ?? 0) ? comparedProducts[0] : comparedProducts[1];
(comparedProducts[0]?.simulationData?.productionCapacity ?? 0) >
(comparedProducts[1]?.simulationData?.productionCapacity ?? 0)
? comparedProducts[0]
: comparedProducts[1];
const product1CyclePercentage =
((comparedProducts[0]?.simulationData?.machineActiveTime ?? 0) /
((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) + (compareProductsData[0]?.simulationData?.machineIdleTime ?? 0))) *
((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) +
(compareProductsData[0]?.simulationData?.machineIdleTime ?? 0))) *
100;
const product2CyclePercentage =
((comparedProducts[1]?.simulationData?.machineActiveTime ?? 0) /
((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) + (compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) *
((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) +
(compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) *
100;
const product1IdlePercentage =
((comparedProducts[0]?.simulationData?.machineIdleTime ?? 0) /
((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) + (compareProductsData[0]?.simulationData?.machineIdleTime ?? 0))) *
((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) +
(compareProductsData[0]?.simulationData?.machineIdleTime ?? 0))) *
100;
console.log(
"product1IdlePercentage: ",
compareProductsData[0]?.simulationData?.machineIdleTime
);
const product2IdlePercentage =
((comparedProducts[1]?.simulationData?.machineIdleTime ?? 0) /
((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) + (compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) *
((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) +
(compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) *
100;
console.log(
"product2IdlePercentage: ",
compareProductsData[1]?.simulationData?.machineIdleTime
);
return (
<div className="compare-result-container">
@@ -147,16 +172,28 @@ const ComparisonResult = () => {
<div className="layers-wrapper">
<div className="layers">
<div className="layer-name">{comparedProducts[0]?.productName}</div>
<div className="layer-time">{compareProductsData[0]?.simulationData.machineActiveTime} Sec</div>
<div className={`layer-change ${product1CyclePercentage >= 50 ? "profit" : "loss"}`}>
<div className="layer-time">
{compareProductsData[0]?.simulationData.machineActiveTime} Sec
</div>
<div
className={`layer-change ${
product1CyclePercentage >= 50 ? "profit" : "loss"
}`}
>
<span>{product1CyclePercentage >= 50 ? "↑" : "↓"}</span>
{(100 - product1CyclePercentage).toFixed(2)}%
</div>
</div>
<div className="layers">
<div className="layer-name">{comparedProducts[1]?.productName}</div>
<div className="layer-time">{compareProductsData[1]?.simulationData.machineActiveTime} Sec</div>
<div className={`layer-change ${product2CyclePercentage >= 50 ? "profit" : "loss"}`}>
<div className="layer-time">
{compareProductsData[1]?.simulationData.machineActiveTime} Sec
</div>
<div
className={`layer-change ${
product2CyclePercentage >= 50 ? "profit" : "loss"
}`}
>
<span>{product2CyclePercentage >= 50 ? "↑" : "↓"}</span>
{(100 - product2CyclePercentage).toFixed(2)}%
</div>
@@ -171,23 +208,69 @@ const ComparisonResult = () => {
{/* <EnergyUsage comparedProducts={comparedProducts} /> */}
<div className="cycle-time-container comparisionCard">
<div className="cycle-main">
<div className="cycle-header">Human Idle Time</div>
<div className="cycle-header">Machine Idle Time</div>
{/* <div className="cycle-header">Overall Downtime</div> */}
<div className="layers-wrapper">
<div className="layers">
<div className="layer-name">{comparedProducts[0]?.productName}</div>
<div className="layer-time">{compareProductsData[0]?.simulationData.machineIdleTime} Sec</div>
<div className={`layer-profit ${product1IdlePercentage >= 50 ? "profit" : "loss"}`}>
<span>{product1IdlePercentage >= 50 ? "↑" : "↓"}</span>
{(100 - product1IdlePercentage).toFixed(2)}%
<div className="layer-time">
{compareProductsData[0]?.simulationData.machineIdleTime} Sec
</div>
<div
className={`layer-profit ${
compareProductsData[0]?.simulationData?.machineIdleTime >
compareProductsData[1]?.simulationData?.machineIdleTime
? "profit"
: "loss"
}`}
>
<span>
{compareProductsData[0]?.simulationData?.machineIdleTime >
compareProductsData[1]?.simulationData?.machineIdleTime
? "↑"
: "↓"}
</span>
{(
((compareProductsData[0]?.simulationData?.machineIdleTime ??
0) /
((compareProductsData[0]?.simulationData
?.machineActiveTime ?? 0) +
(compareProductsData[1]?.simulationData
?.machineIdleTime ?? 0))) *
100
).toFixed(2)}
%
</div>
</div>
<div className="layers">
<div className="layer-name">{comparedProducts[1]?.productName}</div>
<div className="layer-time">{compareProductsData[1]?.simulationData.machineIdleTime} Sec</div>
<div className={`layer-profit ${product2IdlePercentage >= 50 ? "profit" : "loss"}`}>
<span>{product2IdlePercentage >= 50 ? "↑" : "↓"}</span>
{(100 - product2IdlePercentage).toFixed(2)}%
<div className="layer-time">
{compareProductsData[1]?.simulationData.machineIdleTime} Sec
</div>
<div
className={`layer-profit ${
compareProductsData[1]?.simulationData?.machineIdleTime >
compareProductsData[0]?.simulationData?.machineIdleTime
? "profit"
: "loss"
}`}
>
<span>
{compareProductsData[1]?.simulationData?.machineIdleTime >
compareProductsData[0]?.simulationData?.machineIdleTime
? "↑"
: "↓"}
</span>
{(
((compareProductsData[1]?.simulationData?.machineIdleTime ??
0) /
((compareProductsData[1]?.simulationData
?.machineActiveTime ?? 0) +
(compareProductsData[0]?.simulationData
?.machineIdleTime ?? 0))) *
100
).toFixed(2)}
%
</div>
</div>
</div>
@@ -201,11 +284,15 @@ const ComparisonResult = () => {
<div className="layers-wrapper">
<div className="layer-wrapper">
<div className="key">{comparedProducts[0]?.productName}</div>
<div className="value">{comparedProducts[0]?.simulationData.throughputData}/ hr</div>
<div className="value">
{comparedProducts[0]?.simulationData.throughputData}/ hr
</div>
</div>
<div className="layer-wrapper">
<div className="key">{comparedProducts[1]?.productName}</div>
<div className="value">{comparedProducts[1]?.simulationData.throughputData}/ hr</div>
<div className="value">
{comparedProducts[1]?.simulationData.throughputData}/ hr
</div>
</div>
<div className="chart">
<Bar data={throughputData} options={options} />
@@ -236,9 +323,13 @@ const ComparisonResult = () => {
<h4 className="overallScrapRate-header">Production Capacity</h4>
<div className="overallScrapRate-wrapper">
<div className="overallScrapRate-value">
<div className="overallScrapRate-label">{highestProductivityProduct?.productName}</div>
<div className="overallScrapRate-label">
{highestProductivityProduct?.productName}
</div>
<div className="overallScrapRate-key">Total product produced</div>
<div className="overallScrapRateKey-value">{highestProductivityProduct?.simulationData.productionCapacity}</div>
<div className="overallScrapRateKey-value">
{highestProductivityProduct?.simulationData.productionCapacity}
</div>
</div>
<div className="chart">
<Bar data={productionCapacityData} options={options} />
@@ -246,7 +337,9 @@ const ComparisonResult = () => {
</div>
</div>
{comparedProducts.length === 2 && <PerformanceResult comparedProducts={comparedProducts} />}
{comparedProducts.length === 2 && (
<PerformanceResult comparedProducts={comparedProducts} />
)}
</div>
</div>
);

View File

@@ -1,10 +1,11 @@
import React, { Suspense, useEffect, useState } from "react";
import { Suspense } 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";
import LoadingPage from "../../templates/LoadingPage";
const NewWindowScene = () => {
const { versionStore } = useSceneContext();
@@ -15,12 +16,21 @@ const NewWindowScene = () => {
return (
<>
{selectedVersion?.versionId && (
<div style={{ width: "100%", height: "100%" }}>
<div>
<Suspense fallback={null}>
<RenderInNewWindow
title="3D Viewer"
onClose={() => setCreateNewWindow(false)}
>
{/* Wait a tick to access child window */}
<Scene layout="Comparison Layout" />
{
<LoadingPage
progress={loadingProgress}
renderOver={false}
returnDefault={true}
/>
}
<div
style={{
position: "absolute",
@@ -31,7 +41,6 @@ const NewWindowScene = () => {
>
<Button />
</div>
<Scene layout="Comparison Layout" />
{!loadingProgress && <ComparisonResult />}
</RenderInNewWindow>
</Suspense>

View File

@@ -11,7 +11,15 @@ import { useFrame, useThree } from "@react-three/fiber";
import { useSceneContext } from "../scene/sceneContext";
import { useBuilderStore } from "../../store/builder/useBuilderStore";
import { useToggleView, useWallVisibility, useRoofVisibility, useShadows, useToolMode, useRenderDistance, useLimitDistance } from "../../store/builder/store";
import {
useToggleView,
useWallVisibility,
useRoofVisibility,
useShadows,
useToolMode,
useRenderDistance,
useLimitDistance,
} from "../../store/builder/store";
////////// 3D Function Imports //////////
@@ -36,12 +44,12 @@ export default function Builder() {
const csgRef = useRef<any>(null);
const { toggleView } = useToggleView();
const { setToolMode } = useToolMode();
const { toolMode, setToolMode } = useToolMode();
const { setRoofVisibility } = useRoofVisibility();
const { setWallVisibility } = useWallVisibility();
const { setShadows } = useShadows();
const { setRenderDistance } = useRenderDistance();
const { setLimitDistance } = useLimitDistance();
const { limitDistance, setLimitDistance } = useLimitDistance();
const { projectId } = useParams();
const { scene: storeScene, camera: storeCamera, controls: storeControls } = useSceneContext();
const { setHoveredPoint, setHoveredLine } = useBuilderStore();
@@ -72,7 +80,7 @@ export default function Builder() {
setRenderDistance(data.renderDistance);
setLimitDistance(data.limitDistance);
});
}, [projectId]);
}, [projectId, toolMode]);
useFrame(() => {
if (csgRef.current) {

View File

@@ -2,104 +2,110 @@
@use "../abstracts/mixins" as *;
.loading-wrapper {
height: 100vh;
width: 100vw;
background: var(--background-color-solid);
&.comparisionLoading {
position: fixed;
top: 0;
right: 0;
height: 100vh;
width: 50vw;
}
width: 100vw;
background: var(--background-color-solid);
z-index: 1000;
.loading-container {
position: relative;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 28px;
z-index: 5;
&::after {
content: "";
position: absolute;
background: var(--faint-gradient-color);
height: 50vh;
width: 50vw;
top: 0;
left: 0;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: #{$border-radius-circle};
filter: blur(200px);
z-index: -1;
&.comparisionLoading {
position: fixed;
top: 0;
right: 0;
height: 100vh;
width: 50vw;
}
.project-name {
font-size: var(--font-size-regular);
&.newWindowLoading {
position: fixed;
top: 0;
right: 0;
height: 10px;
width: 10px;
}
.loading-hero-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.logo {
@include flex-center;
width: 100%;
margin-bottom: 35px;
scale: 0.8;
circle {
fill: transparent;
}
}
.content {
font-family: #{$font-josefin-sans};
font-size: #{$xxlarge};
font-weight: #{$thin-weight};
max-width: 250px;
text-align: center;
line-height: 2rem;
}
}
.progress-container {
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.progress-value {
font-family: #{$font-josefin-sans};
font-weight: #{$thin-weight};
font-size: 96px;
margin-bottom: 22px;
text-align: center;
}
.progress-indicator-container {
height: 6px;
width: 60%;
background: var(--highlight-accent-color);
border-radius: #{$border-radius-small};
.loading-container {
position: relative;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 28px;
z-index: 5;
.progress-bar {
height: 6px;
background: var(--accent-color);
border-radius: #{$border-radius-small};
transition: width 0.2 ease;
&::after {
content: "";
position: absolute;
background: var(--faint-gradient-color);
height: 50vh;
width: 50vw;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: #{$border-radius-circle};
filter: blur(200px);
z-index: -1;
}
.project-name {
font-size: var(--font-size-regular);
}
.loading-hero-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.logo {
@include flex-center;
width: 100%;
margin-bottom: 35px;
scale: 0.8;
circle {
fill: transparent;
}
}
.content {
font-family: #{$font-josefin-sans};
font-size: #{$xxlarge};
font-weight: #{$thin-weight};
max-width: 250px;
text-align: center;
line-height: 2rem;
}
}
.progress-container {
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.progress-value {
font-family: #{$font-josefin-sans};
font-weight: #{$thin-weight};
font-size: 96px;
margin-bottom: 22px;
text-align: center;
}
.progress-indicator-container {
height: 6px;
width: 60%;
background: var(--highlight-accent-color);
border-radius: #{$border-radius-small};
position: relative;
.progress-bar {
height: 6px;
background: var(--accent-color);
border-radius: #{$border-radius-small};
transition: width 0.2 ease;
}
}
}
}
}
}
}