updating UI

This commit is contained in:
Nalvazhuthi
2025-05-03 10:03:39 +05:30
parent 52c6ab8a65
commit c187a07b22
10 changed files with 346 additions and 282 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,21 +1,101 @@
import React, { useState } from "react"; import React from "react";
import { ProductionCapacityIcon } from "../../icons/analysis"; import { Line } from "react-chartjs-2";
import {
Chart as ChartJS,
LineElement,
CategoryScale,
LinearScale,
PointElement,
} from "chart.js";
import { PowerIcon, ProductionCapacityIcon } from "../../icons/analysis";
const ProductionCapacity = ({ ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement);
progressPercent = 50,
avgProcessTime = "28.4 Secs/unit", // Helper function to generate random colors
machineUtilization = "78%", const getRandomColor = () => {
throughputValue = 128, const letters = "0123456789ABCDEF";
timeRange = { startTime: "08:00 AM", endTime: "09:00 AM" }, let color = "#";
}) => { for (let i = 0; i < 6; i++) {
const totalBars = 6; color += letters[Math.floor(Math.random() * 16)];
const barsToFill = Math.floor((progressPercent / 100) * totalBars); }
const partialFillPercent = return color;
((progressPercent / 100) * totalBars - barsToFill) * 100; };
const ThroughputSummary = () => {
// Define all data internally within the component
const timeRange = {
startTime: "08:00 AM",
endTime: "09:00 AM",
};
const throughputData = {
labels: ["08:00", "08:10", "08:20", "08:30", "08:40", "08:50", "09:00"],
data: [100, 120, 110, 130, 125, 128, 132],
totalThroughput: 1240,
assetUsage: 85,
};
const energyConsumption = {
energyConsumed: 456,
unit: "KWH",
};
// Dynamic shift data
const shiftUtilization = [
{ shift: 1, percentage: 30, color: "#F3C64D" },
{ shift: 2, percentage: 40, color: "#67B3F4" },
{ shift: 3, percentage: 30, color: "#7981F5" },
];
// Chart data configuration
const chartData = {
labels: throughputData.labels,
datasets: [
{
label: "Units/hour",
data: throughputData.data,
borderColor: "#B392F0",
tension: 0.4,
pointRadius: 0, // Hide points
},
],
};
const chartOptions = {
responsive: true,
scales: {
x: {
grid: {
display: false,
},
ticks: {
display: false,
color: "#fff",
},
},
y: {
grid: {
display: false,
},
ticks: {
display: false,
color: "#fff",
},
},
},
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: true,
},
},
};
return ( return (
<div className="productionCapacity-container analysis-card"> <div className="throughoutSummary analysis-card">
<div className="productionCapacity-wrapper analysis-card-wrapper"> <div className="throughoutSummary-wrapper analysis-card-wrapper">
<div className="card-header"> <div className="card-header">
<div className="header"> <div className="header">
<div className="main-header">Production Capacity</div> <div className="main-header">Production Capacity</div>
@@ -30,34 +110,63 @@ const ProductionCapacity = ({
<div className="process-container"> <div className="process-container">
<div className="throughput-value"> <div className="throughput-value">
<span className="value">{throughputValue}</span> Units/hour <span className="value">{throughputData.totalThroughput}</span>{" "}
Units/hour
</div> </div>
<div className="lineChart">
{/* Dynamic Progress Bar */} <div className="assetUsage">
<div className="progress-bar-wrapper"> <div className="key">Asset usage</div>
{[...Array(totalBars)].map((_, i) => ( <div className="value">{throughputData.assetUsage}%</div>
<div className="progress-bar" key={i}> </div>
{i < barsToFill ? ( <Line data={chartData} options={chartOptions} />
<div className="bar-fill full" />
) : i === barsToFill ? (
<div
className="bar-fill partial"
style={{ width: `${partialFillPercent}%` }}
/>
) : null}
</div>
))}
</div> </div>
</div> </div>
<div className="metrics-section"> <div className="footer">
<div className="metric"> <div className="energyConsumption footer-card">
<span className="label">Avg. Process Time</span> <div className="header">Energy Consumption</div>
<span className="value">{avgProcessTime}</span> <div className="value-container">
<div className="energy-icon">
<PowerIcon />
</div>
<div className="value-wrapper">
<div className="value">{energyConsumption.energyConsumed}</div>
<div className="unit">{energyConsumption.unit}</div>
</div>
</div>
</div> </div>
<div className="metric"> <div className="shiftUtilization footer-card">
<span className="label">Machine Utilization</span> <div className="header">Shift Utilization</div>
<span className="value">{machineUtilization}</span> <div className="value-container">
<div className="value">{throughputData.assetUsage}%</div>
<div className="progress-wrapper">
{/* Dynamically create progress bars based on shiftUtilization array */}
{shiftUtilization.map((shift, index) => (
<div
key={shift.shift}
className={`progress shift-${shift.shift}`}
style={{
width: `${shift.percentage}%`,
backgroundColor: shift.color,
}}
></div>
))}
</div>
<div className="progress-indicator">
{/* Dynamically create shift indicators with random colors */}
{shiftUtilization.map((shift, index) => (
<div className="shift-wrapper" key={shift.shift}>
<span
className={`indicator shift-${shift.shift}`}
style={{ backgroundColor: shift.color }} // Random color for indicator
></span>
<label>Shift {shift.shift}</label>
</div>
))}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -65,4 +174,4 @@ const ProductionCapacity = ({
); );
}; };
export default ProductionCapacity; export default ThroughputSummary;

View File

@@ -1,5 +1,11 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { ROISummaryIcon } from "../../icons/analysis"; import {
CostBreakDownIcon,
LightBulpIcon,
ROISummaryIcon,
ROISummaryProductName,
SonarCrownIcon,
} from "../../icons/analysis";
import SemiCircleProgress from "./SemiCircleProgress"; import SemiCircleProgress from "./SemiCircleProgress";
const ROISummary = ({ const ROISummary = ({
@@ -76,10 +82,12 @@ const ROISummary = ({
</div> </div>
</div> </div>
<div className="product-info"> <div className="product-info">
<ROISummaryProductName />
<div className="product-label">Product :</div> <div className="product-label">Product :</div>
<div className="product-name">{roiSummaryData.productName}</div> <div className="product-name">{roiSummaryData.productName}</div>
</div> </div>
<div className="playBack"> <div className="playBack">
<SonarCrownIcon />
<div className="icon"></div> <div className="icon"></div>
<div className="info"> <div className="info">
<span>+{roiSummaryData.roiPercentage}%</span> ROI with payback in <span>+{roiSummaryData.roiPercentage}%</span> ROI with payback in
@@ -116,7 +124,7 @@ const ROISummary = ({
<div className="cost-breakdown"> <div className="cost-breakdown">
<div className="breakdown-header" onClick={toggleTable}> <div className="breakdown-header" onClick={toggleTable}>
<div className="section-wrapper"> <div className="section-wrapper">
<span className="section-number"></span> <CostBreakDownIcon />
<span className="section-title">Cost Breakdown</span> <span className="section-title">Cost Breakdown</span>
</div> </div>
@@ -168,13 +176,18 @@ const ROISummary = ({
</div> </div>
<div className="tips-section"> <div className="tips-section">
<div className="tip-header"> <div className="tip-header">
<span className="lightbulb-icon">💡</span> <span className="lightbulb-icon">
<LightBulpIcon />
</span>
<span className="tip-title">How to improve ROI?</span> <span className="tip-title">How to improve ROI?</span>
</div> </div>
<div className="tip-description"> <div className="tip-description">
Increase CNC utilization by <span className="highlight">10%</span>{" "} Increase CNC utilization by <span className="highlight">10%</span>{" "}
to shave <span className="highlight">0.5</span> months of payback to shave <span className="highlight">0.5</span> months of payback
period period
<div className="placeHolder"></div>
<div className="placeHolder"></div>
<div className="placeHolder"></div>
</div> </div>
<button className="get-tips-button"> <button className="get-tips-button">
<div className="btn">Get ROI Boost Tips</div> <div className="btn">Get ROI Boost Tips</div>

View File

@@ -1,102 +1,21 @@
import React from "react"; import React, { useState } from "react";
import { Line } from "react-chartjs-2"; import { ThroughputSummaryIcon } from "../../icons/analysis";
import {
Chart as ChartJS,
LineElement,
CategoryScale,
LinearScale,
PointElement,
} from "chart.js";
import { PowerIcon, ThroughputSummaryIcon } from "../../icons/analysis";
import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor";
ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement); const ProductionCapacity = ({
progressPercent = 50,
// Helper function to generate random colors avgProcessTime = "28.4 Secs/unit",
const getRandomColor = () => { machineUtilization = "78%",
const letters = "0123456789ABCDEF"; throughputValue = 128,
let color = "#"; timeRange = { startTime: "08:00 AM", endTime: "09:00 AM" },
for (let i = 0; i < 6; i++) { }) => {
color += letters[Math.floor(Math.random() * 16)]; const totalBars = 6;
} const barsToFill = Math.floor((progressPercent / 100) * totalBars);
return color; const partialFillPercent =
}; ((progressPercent / 100) * totalBars - barsToFill) * 100;
const ThroughputSummary = () => {
// Define all data internally within the component
const timeRange = {
startTime: "08:00 AM",
endTime: "09:00 AM",
};
const throughputData = {
labels: ["08:00", "08:10", "08:20", "08:30", "08:40", "08:50", "09:00"],
data: [100, 120, 110, 130, 125, 128, 132],
totalThroughput: 1240,
assetUsage: 85,
};
const energyConsumption = {
energyConsumed: 456,
unit: "KWH",
};
// Dynamic shift data
const shiftUtilization = [
{ shift: 1, percentage: 30 },
{ shift: 2, percentage: 40 },
{ shift: 3, percentage: 30 },
];
// Chart data configuration
const chartData = {
labels: throughputData.labels,
datasets: [
{
label: "Units/hour",
data: throughputData.data,
borderColor: "#B392F0",
tension: 0.4,
pointRadius: 0, // Hide points
},
],
};
const chartOptions = {
responsive: true,
scales: {
x: {
grid: {
display: false,
},
ticks: {
display: false,
color: "#fff",
},
},
y: {
grid: {
display: false,
},
ticks: {
display: false,
color: "#fff",
},
},
},
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: true,
},
},
};
return ( return (
<div className="throughoutSummary analysis-card"> <div className="productionCapacity-container analysis-card">
<div className="throughoutSummary-wrapper analysis-card-wrapper"> <div className="productionCapacity-wrapper analysis-card-wrapper">
<div className="card-header"> <div className="card-header">
<div className="header"> <div className="header">
<div className="main-header">Throughput Summary</div> <div className="main-header">Throughput Summary</div>
@@ -111,63 +30,34 @@ const ThroughputSummary = () => {
<div className="process-container"> <div className="process-container">
<div className="throughput-value"> <div className="throughput-value">
<span className="value">{throughputData.totalThroughput}</span>{" "} <span className="value">{throughputValue}</span> Units/hour
Units/hour
</div> </div>
<div className="lineChart">
<div className="assetUsage"> {/* Dynamic Progress Bar */}
<div className="key">Asset usage</div> <div className="progress-bar-wrapper">
<div className="value">{throughputData.assetUsage}%</div> {[...Array(totalBars)].map((_, i) => (
</div> <div className="progress-bar" key={i}>
<Line data={chartData} options={chartOptions} /> {i < barsToFill ? (
<div className="bar-fill full" />
) : i === barsToFill ? (
<div
className="bar-fill partial"
style={{ width: `${partialFillPercent}%` }}
/>
) : null}
</div>
))}
</div> </div>
</div> </div>
<div className="footer"> <div className="metrics-section">
<div className="energyConsumption footer-card"> <div className="metric">
<div className="header">Energy Consumption</div> <span className="label">Avg. Process Time</span>
<div className="value-container"> <span className="value">{avgProcessTime}</span>
<div className="energy-icon">
<PowerIcon />
</div>
<div className="value-wrapper">
<div className="value">{energyConsumption.energyConsumed}</div>
<div className="unit">{energyConsumption.unit}</div>
</div>
</div>
</div> </div>
<div className="shiftUtilization footer-card"> <div className="metric">
<div className="header">Shift Utilization</div> <span className="label">Machine Utilization</span>
<div className="value-container"> <span className="value">{machineUtilization}</span>
<div className="value">{throughputData.assetUsage}%</div>
<div className="progress-wrapper">
{/* Dynamically create progress bars based on shiftUtilization array */}
{shiftUtilization.map((shift, index) => (
<div
key={shift.shift}
className={`progress shift-${shift.shift}`}
style={{
width: `${shift.percentage}%`,
backgroundColor: getAvatarColor(index),
}}
></div>
))}
</div>
<div className="progress-indicator">
{/* Dynamically create shift indicators with random colors */}
{shiftUtilization.map((shift, index) => (
<div className="shift-wrapper" key={shift.shift}>
<span
className={`indicator shift-${shift.shift}`}
style={{ backgroundColor: getAvatarColor(index) }} // Random color for indicator
></span>
<label>Shift {shift.shift}</label>
</div>
))}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -175,4 +65,4 @@ const ThroughputSummary = () => {
); );
}; };
export default ThroughputSummary; export default ProductionCapacity;

View File

@@ -1,71 +0,0 @@
type LogType = 'log' | 'info' | 'warning' | 'error';
interface LogEntry {
type: LogType;
message: string;
timestamp: Date;
context?: string;
}
class Logger {
private static instance: Logger;
private logs: LogEntry[] = [];
private subscribers: Array<(log: LogEntry) => void> = [];
private constructor() {}
public static getInstance(): Logger {
if (!Logger.instance) {
Logger.instance = new Logger();
}
return Logger.instance;
}
private notifySubscribers(log: LogEntry) {
this.subscribers.forEach(callback => callback(log));
}
private addLog(type: LogType, message: string, context?: string) {
const log: LogEntry = { type, message, timestamp: new Date(), context };
this.logs.push(log);
this.notifySubscribers(log);
if (process.env.NODE_ENV === 'development') {
const logMessage = context ? `[${context}] ${message}` : message;
console[type === 'warning' ? 'warn' : type](logMessage);
}
}
public log(message: string, context?: string) {
this.addLog('log', message, context);
}
public info(message: string, context?: string) {
this.addLog('info', message, context);
}
public warning(message: string, context?: string) {
this.addLog('warning', message, context);
}
public error(message: string, context?: string) {
this.addLog('error', message, context);
}
public getLogs(): LogEntry[] {
return [...this.logs];
}
public clear() {
this.logs = [];
}
public subscribe(callback: (log: LogEntry) => void) {
this.subscribers.push(callback);
return () => {
this.subscribers = this.subscribers.filter(sub => sub !== callback);
};
}
}
export const logger = Logger.getInstance();

View File

@@ -19,8 +19,8 @@ import {
} from "../../icons/ExportCommonIcons"; } from "../../icons/ExportCommonIcons";
import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor"; import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor";
import { useSubModuleStore } from "../../../store/useModuleStore"; import { useSubModuleStore } from "../../../store/useModuleStore";
import ProductionCapacity from "../analysis/ProductionCapacity"; import ProductionCapacity from "../analysis/ThroughputSummary";
import ThroughputSummary from "../analysis/ThroughputSummary"; import ThroughputSummary from "../analysis/ProductionCapacity";
import ROISummary from "../analysis/ROISummary"; import ROISummary from "../analysis/ROISummary";
const SimulationPlayer: React.FC = () => { const SimulationPlayer: React.FC = () => {

View File

@@ -56,7 +56,7 @@ import ZoneGroup from "./groups/zoneGroup";
import useModuleStore from "../../store/useModuleStore"; import useModuleStore from "../../store/useModuleStore";
import MeasurementTool from "../scene/tools/measurementTool"; import MeasurementTool from "../scene/tools/measurementTool";
import NavMesh from "../simulation/vehicle/navMesh/navMesh"; import NavMesh from "../simulation/vehicle/navMesh/navMesh";
import ProductionCapacity from "../../components/ui/analysis/ProductionCapacity"; import ProductionCapacity from "../../components/ui/analysis/ThroughputSummary";
export default function Builder() { export default function Builder() {
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.

View File

@@ -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 && (

View File

@@ -16,6 +16,7 @@
flex-direction: column; flex-direction: column;
gap: 12px; gap: 12px;
} }
.analysis-card { .analysis-card {
min-width: 333px; min-width: 333px;
background: var(--background-color); background: var(--background-color);
@@ -42,9 +43,14 @@
align-items: center; align-items: center;
.main-header { .main-header {
line-height: 20px; color: var(--text-color);
font-size: var(--font-size-regular); font-size: var(--font-size-regular);
} }
.sub-header {
color: var(--input-text-color);
font-size: var(--font-size-tiny);
}
} }
.process-container { .process-container {
@@ -114,6 +120,7 @@
} }
} }
} }
.throughoutSummary-wrapper { .throughoutSummary-wrapper {
.process-container { .process-container {
display: flex; display: flex;
@@ -166,7 +173,7 @@
padding: 8px; padding: 8px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 6px; gap: 16px;
&:first-child { &:first-child {
width: 85%; width: 85%;
@@ -182,6 +189,21 @@
align-items: center; align-items: center;
justify-content: end; justify-content: end;
gap: 6px; gap: 6px;
.progress-indicator {
padding-top: 10px;
}
.value-wrapper {
.value {
font-size: var(--font-size-xlarge);
}
.unit {
font-size: var(--font-size-small);
}
}
} }
} }
@@ -266,4 +288,4 @@
} }
} }
} }
} }

View File

@@ -67,8 +67,8 @@
min-width: 150px; min-width: 150px;
z-index: 3; z-index: 3;
transform: translate(-50%, -10%); transform: translate(-50%, -10%);
transition: transform 0.5s linear;
pointer-events: all; pointer-events: all;
transition: all 0.3s linear;
&::-webkit-scrollbar { &::-webkit-scrollbar {
display: none; display: none;
@@ -243,6 +243,7 @@
&:hover { &:hover {
background: var(--highlight-accent-color); background: var(--highlight-accent-color);
width: 100%; width: 100%;
.label { .label {
color: var(--accent-color); color: var(--accent-color);
} }
@@ -619,6 +620,7 @@
.label { .label {
color: var(--accent-color); color: var(--accent-color);
} }
background: var(--highlight-accent-color); background: var(--highlight-accent-color);
width: 100%; width: 100%;
@@ -933,4 +935,4 @@
opacity: 0; opacity: 0;
transform: scaleY(0); transform: scaleY(0);
} }
} }