first commit

This commit is contained in:
2025-03-25 11:47:41 +05:30
commit 61b3c4ee2c
211 changed files with 36430 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
import { Canvas } from "@react-three/fiber";
import Throughput from "./cards/Throughput";
import ReturnOfInvestment from "./cards/ReturnOfInvestment";
import ProductionCapacity from "./cards/ProductionCapacity";
import { OrbitControls } from "@react-three/drei";
import StateWorking from "./cards/StateWorking";
const CardsScene = () => {
return (
<div className="cards-scene" style={{ width: "100%", height: "100%" }}>
<Canvas>
{/* 3d-cards */}
{/* <Throughput /> */}
{/* <ReturnOfInvestment /> */}
{/* <ProductionCapacity /> */}
{/* <StateWorking /> */}
<OrbitControls />
</Canvas>
</div>
);
};
export default CardsScene;

View File

@@ -0,0 +1,108 @@
import { Html } from "@react-three/drei";
import React from "react";
import { Bar } from "react-chartjs-2";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
TooltipItem, // Import TooltipItem for typing
} from "chart.js";
// Register ChartJS components
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend
);
const ProductionCapacity = () => {
// Chart data for a week
const chartData = {
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], // Days of the week
datasets: [
{
label: "Production Capacity (units/day)",
data: [1500, 1600, 1400, 1700, 1800, 1900, 2000], // Example daily production data
backgroundColor: "#6f42c1", // Theme color
borderColor: "#6f42c1",
borderWidth: 1,
borderRadius: 8, // Rounded corners for the bars
borderSkipped: false, // Ensure all corners are rounded
},
],
};
// Chart options
const chartOptions = {
responsive: true,
plugins: {
legend: {
display: false, // Hide legend
},
title: {
display: true,
text: "Weekly Production Capacity",
font: {
size: 16,
},
},
tooltip: {
callbacks: {
// Explicitly type the context parameter
label: (context: TooltipItem<"bar">) => {
const value = context.parsed.y; // Extract the y-axis value
return `${value} units`; // Customize tooltip to display "units"
},
},
},
},
scales: {
x: {
grid: {
display: false, // Hide x-axis grid lines
},
},
y: {
display: false, // Remove the y-axis completely
},
},
};
return (
<Html position={[0, 0, 0]} transform occlude>
<div className="productionCapacity-wrapper card">
<div className="headeproductionCapacityr-wrapper">
<div className="header">Production Capacity</div>
<div className="production-capacity">
<div className="value">1,200</div>{" "}
<div className="value">units/hour</div>
</div>
<div className="production-capacity">
<div className="current">
<div className="key">Current</div>
<div className="value">1500</div>
</div>
<div className="target">
<div className="key">Target</div>
<div className="value">2.345</div>
</div>
{/* <div className="value">units/hour</div> */}
</div>
</div>{" "}
<div className="bar-chart charts">
{/* Bar Chart */}
<Bar data={chartData} options={chartOptions} />
</div>
</div>
</Html>
);
};
export default ProductionCapacity;

View File

@@ -0,0 +1,131 @@
import { Html } from "@react-three/drei";
import React from "react";
import { Line } from "react-chartjs-2";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Tooltip,
ChartData,
ChartOptions,
} from "chart.js";
import { WavyIcon } from "../../../icons/3dChartIcons";
// Register Chart.js components
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Tooltip
);
// Define Props for SmoothLineGraphComponent
interface SmoothLineGraphProps {
data: ChartData<"line">; // Type for chart data
options?: ChartOptions<"line">; // Type for chart options (optional)
}
// SmoothLineGraphComponent using react-chartjs-2
const SmoothLineGraphComponent: React.FC<SmoothLineGraphProps> = ({
data,
options,
}) => {
return <Line data={data} options={options} />;
};
const ReturnOfInvestment = () => {
// Improved sample data for the smooth curve graph (single day)
const graphData: ChartData<"line"> = {
labels: [
"12 AM",
"3 AM",
"6 AM",
"9 AM",
"12 PM",
"3 PM",
"6 PM",
"9 PM",
"12 AM",
],
datasets: [
{
label: "Investment",
data: [100, 250, 400, 400, 500, 600, 700, 800, 900], // Example investment growth
borderColor: "rgba(75, 192, 192, 1)", // Light blue color
backgroundColor: "rgba(75, 192, 192, 0.2)",
fill: true,
tension: 0.4, // Smooth curve effect
pointRadius: 0, // Hide dots
pointHoverRadius: 0, // Hide hover dots
},
{
label: "Return",
data: [100, 200, 500, 250, 300, 350, 400, 450, 500], // Example return values
borderColor: "rgba(255, 99, 132, 1)", // Pink color
backgroundColor: "rgba(255, 99, 132, 0.2)",
fill: true,
tension: 0.4, // Smooth curve effect
pointRadius: 0, // Hide dots
pointHoverRadius: 0, // Hide hover dots
},
],
};
// Options for the smooth curve graph
const graphOptions: ChartOptions<"line"> = {
responsive: true,
maintainAspectRatio: false,
plugins: {
tooltip: {
enabled: true, // Enable tooltips on hover
mode: "index", // Show both datasets' values at the same index
intersect: false, // Allow hovering anywhere on the graph
},
},
scales: {
x: {
grid: {
display: false, // Hide x-axis grid lines
},
ticks: {
display: false, // Hide x-axis labels
},
},
y: {
grid: {
display: false, // Hide y-axis grid lines
},
ticks: {
display: false, // Hide y-axis labels
},
},
},
};
return (
<Html position={[0, 0, 0]} transform occlude>
<div className="returnOfInvestment card">
<div className="header">Return of Investment</div>
<div className="lineGraph charts">
{/* Smooth curve graph with two datasets */}
<SmoothLineGraphComponent data={graphData} options={graphOptions} />
</div>
<div className="returns-wrapper">
<div className="icon">
<WavyIcon />
</div>
<div className="value">5.78</div>
<div className="key">Years</div>
</div>
<div className="footer">
in <span>5y</span> with avg <span>7%</span> yearly return
</div>
</div>
</Html>
);
};
export default ReturnOfInvestment;

View File

@@ -0,0 +1,42 @@
import { Html } from "@react-three/drei";
import image from "../../../../assets/image/temp/image.png";
const StateWorking = () => {
const datas = [
{ key: "Oil Tank:", value: "24/341" },
{ key: "Oil Refin:", value: 36.023 },
{ key: "Transmission:", value: 36.023 },
{ key: "Fuel:", value: 36732 },
{ key: "Power:", value: 1300 },
{ key: "Time:", value: 13 - 9 - 2023 },
];
return (
<Html position={[0, 0, 0]} transform occlude>
<div className="stateWorking-wrapper card">
<div className="header-wrapper">
<div className="header">
<span>State</span>
<span>
Working <span>.</span>
</span>
</div>
<div className="img">
<img src={image} alt="" />
</div>
</div>
{/* Data */}
<div className="data-wrapper">
{datas.map((data, index) => (
<div className="data-table" key={index}>
<div className="data">{data.key}</div>
<div className="key">{data.value}</div>
</div>
))}
</div>
</div>
</Html>
);
};
export default StateWorking;

View File

@@ -0,0 +1,124 @@
import { Html } from "@react-three/drei";
import React from "react";
import { Line } from "react-chartjs-2";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
ChartData,
ChartOptions,
} from "chart.js";
import { ThroughputIcon } from "../../../icons/3dChartIcons";
// Register Chart.js components
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
);
// Define Props for LineGraphComponent
interface LineGraphProps {
data: ChartData<"line">; // Type for chart data
options?: ChartOptions<"line">; // Type for chart options (optional)
}
// LineGraphComponent using react-chartjs-2
const LineGraphComponent: React.FC<LineGraphProps> = ({ data, options }) => {
return <Line data={data} options={options} />;
};
const Throughput = () => {
// Sample data for the line graph
const graphData: ChartData<"line"> = {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
datasets: [
{
label: "Throughput",
data: [1000, 1200, 1100, 1300, 1250, 1400], // Example throughput values
borderColor: "rgba(75, 192, 192, 1)",
backgroundColor: "rgba(75, 192, 192, 0.2)",
fill: true,
},
],
};
// Options for the line graph
const graphOptions: ChartOptions<"line"> = {
responsive: true,
plugins: {
legend: {
position: "top",
display: false,
},
title: {
display: true,
text: "Throughput Over Time",
},
},
scales: {
x: {
grid: {
display: true, // Show vertical grid lines
},
ticks: {
display: false, // Hide x-axis labels
},
},
y: {
grid: {
display: false, // Hide horizontal grid lines
},
ticks: {
display: false, // Hide y-axis labels
},
},
},
};
return (
<Html position={[0, 0, 0]} transform occlude>
<div className="throughput-wrapper">
<div className="header">Throughput</div>
<div className="display-value">
<div className="left">
<div className="icon">
<ThroughputIcon />
</div>
<div className="value-container">
<div className="value-wrapper">
<div className="value">1,200</div>
<div className="key"> Units/hr</div>
</div>
<div className="total-sales">
<div className="value">316</div>
<div className="key">sales</div>
</div>
</div>
</div>
<div className="right">
<div className="percent-increase">5.77%</div>
</div>
</div>
<div className="line-graph">
{/* Line graph using react-chartjs-2 */}
<LineGraphComponent data={graphData} options={graphOptions} />
</div>
<div className="footer">
You made an extra <span className="value">$1256.13</span> this month
</div>
</div>
</Html>
);
};
export default Throughput;

View File

@@ -0,0 +1,25 @@
import React, { useState } from "react";
import Search from "../../ui/inputs/Search";
const Assets: React.FC = () => {
const [searchValue, setSearchValue] = useState<string>("");
const handleSearchChange = (value: string) => {
setSearchValue(value);
console.log(value); // Log the search value if needed
};
return (
<div className="assets-container">
<Search onChange={handleSearchChange} />
{searchValue ? (
<div className="searched-content">
<p>Results for "{searchValue}"</p>
</div>
) : (
<></>
)}
</div>
);
};
export default Assets;

View File

@@ -0,0 +1,31 @@
import React from "react";
import { ToggleSidebarIcon } from "../../icons/HeaderIcons";
import { LogoIcon } from "../../icons/Logo";
import FileMenu from "../../ui/FileMenu";
import useToggleStore from "../../../store/useUIToggleStore";
const Header: React.FC = () => {
const { toggleUI, setToggleUI } = useToggleStore();
return (
<div className="header-container">
<div className="header-content">
<div className="logo-container">
<LogoIcon />
</div>
<div className="header-title">
<FileMenu />
</div>
</div>
<div
className={`toggle-sidebar-ui-button ${!toggleUI ? "active" : ""}`}
onClick={() => {
setToggleUI(!toggleUI);
}}
>
<ToggleSidebarIcon />
</div>
</div>
);
};
export default Header;

View File

@@ -0,0 +1,48 @@
import React, { useState } from "react";
import Search from "../../ui/inputs/Search";
import DropDownList from "../../ui/list/DropDownList";
const Outline: React.FC = () => {
const [searchValue, setSearchValue] = useState<string>("");
const handleSearchChange = (value: string) => {
setSearchValue(value);
console.log(value); // Log the search value if needed
};
const dropdownItems = [
{ id: "1", name: "Ground Floor" },
{ id: "2", name: "Floor 1" },
]; // Example dropdown items
return (
<div className="outline-container">
<Search onChange={handleSearchChange} />
{searchValue ? (
<div className="searched-content">
<p>Results for "{searchValue}"</p>
</div>
) : (
<div className="outline-content-container">
<DropDownList
value="Layers"
items={dropdownItems}
defaultOpen={true}
showKebabMenu={false}
showFocusIcon={true}
/>
<DropDownList
value="Scene"
items={dropdownItems}
defaultOpen={true}
listType="outline"
showKebabMenu={false}
showAddIcon={false}
/>
</div>
)}
</div>
);
};
export default Outline;

View File

@@ -0,0 +1,70 @@
import React, { useEffect, useState } from "react";
import ToggleHeader from "../../ui/inputs/ToggleHeader";
import Outline from "./Outline";
import Header from "./Header";
import useToggleStore from "../../../store/useUIToggleStore";
import Assets from "./Assets";
import useModuleStore from "../../../store/useModuleStore";
import Widgets from "./visualization/widgets/Widgets";
import Templates from "./visualization/Templates";
import Search from "../../ui/inputs/Search";
const SideBarLeft: React.FC = () => {
const [activeOption, setActiveOption] = useState("Widgets");
const { toggleUI } = useToggleStore();
const { activeModule } = useModuleStore();
// Reset activeOption whenever activeModule changes
useEffect(() => {
setActiveOption("Outline");
if (activeModule === "visualization") setActiveOption("Widgets");
}, [activeModule]);
const handleToggleClick = (option: string) => {
setActiveOption(option); // Update the active option
};
const handleSearchChange = (value: string) => {
// Log the search value for now
console.log(value);
};
return (
<div className="sidebar-left-wrapper">
<Header />
{toggleUI && (
<div className="sidebar-left-container">
{activeModule === "visualization" ? (
<>
<ToggleHeader
options={["Widgets", "Templates"]}
activeOption={activeOption}
handleClick={handleToggleClick}
/>
<Search onChange={handleSearchChange} />
<div className="sidebar-left-content-container">
{activeOption === "Widgets" ? <Widgets /> : <Templates />}
</div>
</>
) : activeModule === "market" ? (
<></>
) : (
<>
<ToggleHeader
options={["Outline", "Assets"]}
activeOption={activeOption}
handleClick={handleToggleClick}
/>
<div className="sidebar-left-content-container">
{activeOption === "Outline" ? <Outline /> : <Assets />}
</div>
</>
)}
</div>
)}
</div>
);
};
export default SideBarLeft;

View File

@@ -0,0 +1,125 @@
import useTemplateStore from "../../../../store/useTemplateStore";
import { useSelectedZoneStore } from "../../../../store/useZoneStore";
const Templates = () => {
const { templates, removeTemplate } = useTemplateStore();
const { setSelectedZone } = useSelectedZoneStore();
console.log("templates: ", templates);
const handleDeleteTemplate = (id: string) => {
removeTemplate(id);
};
const handleLoadTemplate = (template: any) => {
setSelectedZone((prev) => ({
...prev,
panelOrder: template.panelOrder,
activeSides: Array.from(
new Set([...prev.activeSides, ...template.panelOrder])
),
widgets: template.widgets,
}));
};
return (
<div
className="template-list"
style={{
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(180px, 1fr))",
gap: "1rem",
padding: "1rem",
}}
>
{templates.map((template) => (
<div
key={template.id}
className="template-item"
style={{
border: "1px solid #e0e0e0",
borderRadius: "8px",
padding: "1rem",
transition: "box-shadow 0.3s ease",
}}
>
{template.snapshot && (
<div style={{ position: "relative", paddingBottom: "56.25%" }}>
{" "}
{/* 16:9 aspect ratio */}
<img
src={template.snapshot} // Corrected from template.image to template.snapshot
alt={`${template.name} preview`}
style={{
position: "absolute",
width: "100%",
height: "100%",
objectFit: "contain",
borderRadius: "4px",
cursor: "pointer",
transition: "transform 0.3s ease",
// ':hover': {
// transform: 'scale(1.05)'
// }
}}
onClick={() => handleLoadTemplate(template)}
/>
</div>
)}
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginTop: "0.5rem",
}}
>
<div
onClick={() => handleLoadTemplate(template)}
style={{
cursor: "pointer",
fontWeight: "500",
// ':hover': {
// textDecoration: 'underline'
// }
}}
>
{template.name}
</div>
<button
onClick={() => handleDeleteTemplate(template.id)}
style={{
padding: "0.25rem 0.5rem",
background: "#ff4444",
color: "white",
border: "none",
borderRadius: "4px",
cursor: "pointer",
transition: "opacity 0.3s ease",
// ':hover': {
// opacity: 0.8
// }
}}
aria-label="Delete template"
>
Delete
</button>
</div>
</div>
))}
{templates.length === 0 && (
<div
style={{
textAlign: "center",
color: "#666",
padding: "2rem",
gridColumn: "1 / -1",
}}
>
No saved templates yet. Create one in the visualization view!
</div>
)}
</div>
);
};
export default Templates;

View File

@@ -0,0 +1,130 @@
import React, { useEffect, useRef, useMemo } from "react";
import { Chart } from "chart.js/auto";
// import { useThemeStore } from "../../../../../store/useThemeStore";
// Define Props Interface
interface ChartComponentProps {
type: any; // Type of chart (e.g., "bar", "line", etc.)
title: string; // Title of the chart
fontFamily?: string; // Optional font family for the chart title
fontSize?: string; // Optional font size for the chart title
fontWeight?: "Light" | "Regular" | "Bold"; // Optional font weight for the chart title
data: {
labels: string[]; // Labels for the x-axis
datasets: {
data: number[]; // Data points for the chart
backgroundColor: string; // Background color for the chart
borderColor: string; // Border color for the chart
borderWidth: number; // Border width for the chart
}[];
}; // Data for the chart
}
const ChartComponent = ({
type,
title,
fontFamily,
fontSize,
fontWeight = "Regular", // Default to "Regular"
data: propsData,
}: ChartComponentProps) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
// const { themeColor } = useThemeStore();
// Memoize Theme Colors to Prevent Unnecessary Recalculations
// const buttonActionColor = useMemo(
// () => themeColor[0] || "#5c87df",
// [themeColor]
// );
// const buttonAbortColor = useMemo(
// () => themeColor[1] || "#ffffff",
// [themeColor]
// );
// Memoize Font Weight Mapping
const chartFontWeightMap = useMemo(
() => ({
Light: "lighter" as const,
Regular: "normal" as const,
Bold: "bold" as const,
}),
[]
);
// Parse and Memoize Font Size
const fontSizeValue = useMemo(
() => (fontSize ? parseInt(fontSize) : 12),
[fontSize]
);
// Determine and Memoize Font Weight
const fontWeightValue = useMemo(
() => chartFontWeightMap[fontWeight],
[fontWeight, chartFontWeightMap]
);
// Memoize Chart Font Style
const chartFontStyle = useMemo(
() => ({
family: fontFamily || "Arial",
size: fontSizeValue,
weight: fontWeightValue,
color: "#2B3344",
}),
[fontFamily, fontSizeValue, fontWeightValue]
);
// Memoize Chart Data
const data = useMemo(() => propsData, [propsData]);
// Memoize Chart Options
const options = useMemo(
() => ({
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: title,
font: chartFontStyle,
align: "start", // Left align the title
padding: {
top: 10, // Add padding above the title
bottom: 20, // Add padding between the title and the chart
},
},
legend: {
display: false,
},
},
}),
[title, chartFontStyle]
);
// Initialize Chart on Component Mount
useEffect(() => {
if (!canvasRef.current) return;
const ctx = canvasRef.current.getContext("2d");
if (!ctx) return;
const chart = new Chart(ctx, { type, data, options });
// Cleanup: Destroy the chart instance when the component unmounts
return () => chart.destroy();
}, [type, data, options]); // Only recreate the chart when these dependencies change
return <canvas ref={canvasRef} style={{ width: "100%", height: "100%" }} />;
};
export default React.memo(ChartComponent, (prevProps, nextProps) => {
// Custom comparison function to prevent unnecessary re-renders
return (
prevProps.type === nextProps.type &&
prevProps.title === nextProps.title &&
prevProps.fontFamily === nextProps.fontFamily &&
prevProps.fontSize === nextProps.fontSize &&
prevProps.fontWeight === nextProps.fontWeight &&
JSON.stringify(prevProps.data) === JSON.stringify(nextProps.data)
);
});

View File

@@ -0,0 +1,28 @@
import { useState } from "react";
import ToggleHeader from "../../../../ui/inputs/ToggleHeader";
import Widgets2D from "./Widgets2D";
import Widgets3D from "./Widgets3D";
import WidgetsFloating from "./WidgetsFloating";
const Widgets = () => {
const [activeOption, setActiveOption] = useState("Floating");
const handleToggleClick = (option: string) => {
setActiveOption(option);
};
return (
<div className="widget-left-sideBar">
<ToggleHeader
options={["2D", "3D", "Floating"]}
activeOption={activeOption}
handleClick={handleToggleClick}
/>
{activeOption === "2D" && <Widgets2D />}
{activeOption === "3D" && <Widgets3D />}
{activeOption === "Floating" && <WidgetsFloating />}
</div>
);
};
export default Widgets;

View File

@@ -0,0 +1,141 @@
import React from "react";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import { ChartType } from "chart.js/auto";
import ChartComponent from "./ChartComponent";
import { StockIncreseIcon } from "../../../../icons/RealTimeVisulationIcons";
const chartTypes: ChartType[] = [
"bar",
"line",
"pie",
"doughnut",
"radar",
"polarArea",
];
const sampleData = {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
datasets: [
{
data: [65, 59, 80, 81, 56, 55, 40],
backgroundColor: "#6f42c1",
borderColor: "#ffffff",
borderWidth: 1,
},
],
};
interface WidgetProps {
type: ChartType;
index: number;
title: string;
}
const ChartWidget: React.FC<WidgetProps> = ({ type, index, title }) => {
const { setDraggedAsset } = useWidgetStore((state) => state);
return (
<div
className={`chart chart-${index + 1}`}
draggable
onDragStart={() => {
setDraggedAsset({
type,
id: `widget-${index + 1}`,
title,
panel: "top",
data: sampleData,
});
}}
onDragEnd={() => setDraggedAsset(null)}
>
<ChartComponent type={type} title={title} data={sampleData} />
</div>
);
};
const ProgressBarWidget = ({
id,
title,
data,
}: {
id: string;
title: string;
data: any;
}) => {
const { setDraggedAsset } = useWidgetStore((state) => state);
return (
<div
className="chart progressBar"
draggable
onDragStart={() => {
setDraggedAsset({
type: "progress",
id,
title,
panel: "top",
data,
});
}}
onDragEnd={() => setDraggedAsset(null)}
>
<div className="header">{title}</div>
{data.stocks.map((stock: any, index: number) => (
<div className="stock" key={index}>
<span className="stock-item">
<span className="stockValues">
<div className="key">{stock.key}</div>
<div className="value">{stock.value}</div>
</span>
<div className="stock-description">{stock.description}</div>
</span>
<div className="icon">
<StockIncreseIcon />
</div>
</div>
))}
</div>
);
};
const Widgets2D = () => {
return (
<div className="widget2D">
<div className="chart-container">
{chartTypes.map((type, index) => {
const widgetTitle = `Widget ${index + 1}`;
return (
<ChartWidget
key={index}
type={type}
index={index}
title={widgetTitle}
/>
);
})}
<ProgressBarWidget
id="widget-7"
title="Widget 7"
data={{
stocks: [
{ key: "units", value: 1000, description: "Initial stock" },
],
}}
/>
<ProgressBarWidget
id="widget-8"
title="Widget 8"
data={{
stocks: [
{ key: "units", value: 1000, description: "Initial stock" },
{ key: "units", value: 500, description: "Additional stock" },
],
}}
/>
</div>
</div>
);
};
export default Widgets2D;

View File

@@ -0,0 +1,30 @@
import widget1 from "../../../../../assets/image/3D/ProductionCapacity.png";
import widget2 from "../../../../../assets/image/3D/ReturnOfInvestment.png";
import widget3 from "../../../../../assets/image/3D/StateWorking.png";
import widget4 from "../../../../../assets/image/3D/Throughput.png";
const Widgets3D = () => {
const widgets = [
{ name: "Widget 1", img: widget1 },
{ name: "Widget 2", img: widget2 },
{ name: "Widget 3", img: widget3 },
{ name: "Widget 4", img: widget4 },
];
return (
<div className="widgets-container widget3D">
{widgets?.map((widget, index) => (
<div key={index} className="widget-item" draggable>
<div className="widget-name">{widget.name}</div>
<img
className="widget-image"
src={widget.img}
alt={widget.name}
draggable={false}
/>
</div>
))}
</div>
);
};
export default Widgets3D;

View File

@@ -0,0 +1,79 @@
import React from "react";
import {
CartIcon,
DocumentIcon,
GlobeIcon,
WalletIcon,
} from "../../../../icons/3dChartIcons";
import SimpleCard from "../../../../ui/realTimeVis/floating/SimpleCard";
import WarehouseThroughput from "../../../../ui/realTimeVis/floating/WarehouseThroughput";
import ProductivityDashboard from "../../../../ui/realTimeVis/floating/ProductivityDashboard";
import FleetEfficiency from "../../../../ui/realTimeVis/floating/FleetEfficiency";
interface Widget {
id: string;
name: string;
}
const WidgetsFloating = () => {
// const [widgets, setWidgets] = useState<Widget[]>([
// { id: "1", name: "Working State Widget" },
// { id: "2", name: "Floating Widget 2" },
// { id: "3", name: "Floating Widget 3" },
// { id: "4", name: "Floating Widget 4" },
// ]);
// Function to handle drag start
const handleDragStart = (
e: React.DragEvent<HTMLDivElement>,
widget: Widget
) => {
e.dataTransfer.setData("application/json", JSON.stringify(widget));
};
return (
<div className="floatingWidgets-wrapper">
{/* {widgets.map((widget) => (
<div
key={widget.id}
className="floating"
draggable
onDragStart={(e) => handleDragStart(e, widget)}
>
{widget.name}
</div>
))} */}
{/* Floating 1 */}
<SimpleCard
header={"Todays Money"}
icon={WalletIcon}
value={"$53,000"}
per={"+55%"}
/>
<SimpleCard
header={"Todays Users"}
icon={GlobeIcon}
value={"1,200"}
per={"+30%"}
/>
<SimpleCard
header={"New Clients"}
icon={DocumentIcon}
value={"250"}
per={"+12%"}
/>
<SimpleCard
header={"Total Sales"}
icon={CartIcon}
value={"$150,000"}
per={"+20%"}
/>{" "}
<WarehouseThroughput />
{/* <ProductivityDashboard /> */}
<FleetEfficiency />
</div>
);
};
export default WidgetsFloating;

View File

@@ -0,0 +1,50 @@
import React from "react";
import { AppDockIcon } from "../../icons/HeaderIcons";
import orgImg from "../../../assets/orgTemp.png"
const Header: React.FC = () => {
const guestUsers = [
{ value: "Nazria", color: "#43C06D" },
{ value: "Name1", color: "#0050EB" },
{ value: "Abigail", color: "#FF6600" },
{ value: "Jack", color: "#488EF6" },
]; // Example guest users array
return (
<div className="header-container">
<div className="options-container">
<div className="share-button">Share</div>
<div className="app-docker-button">
<AppDockIcon />
</div>
</div>
<div className="split"></div>
<div className="users-container">
<div className="guest-users-container">
{guestUsers.length > 3 && (
<div className="other-guest">+{guestUsers.length - 3}</div>
)}
{guestUsers.slice(0, 3).map((user, index) => (
<div
key={index}
className="user-profile"
style={{ background: user.color }}
>
{user.value[0]}
</div>
))}
</div>
<div className="user-profile-container">
<div className="user-profile" style={{ background: "#48AC2A" }}>
V
</div>
<div className="user-organization">
<img src={orgImg} alt="" />
</div>
</div>
</div>
</div>
);
};
export default Header;

View File

@@ -0,0 +1,117 @@
import React, { useEffect, useState } from "react";
import Header from "./Header";
import useModuleStore from "../../../store/useModuleStore";
import {
AnalysisIcon,
MechanicsIcon,
PropertiesIcon,
SimulationIcon,
} from "../../icons/SimulationIcons";
import useToggleStore from "../../../store/useUIToggleStore";
import MachineMechanics from "./mechanics/MachineMechanics";
import Visualization from "./visualization/Visualization";
import GlobalProperties from "./properties/GlobalProperties";
import AsstePropertiies from "./properties/AssetProperties";
import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations";
const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore();
const [activeList, setActiveList] = useState("properties");
const { toggleUI } = useToggleStore();
// Reset activeList whenever activeModule changes
useEffect(() => {
setActiveList("properties");
}, [activeModule]);
return (
<div className="sidebar-right-wrapper">
<Header />
{toggleUI && (
<div className="sidebar-actions-container">
<div
className={`sidebar-action-list ${
activeList === "properties" ? "active" : ""
}`}
onClick={() => setActiveList("properties")}
>
<PropertiesIcon isActive={activeList === "properties"} />
</div>
{activeModule === "simulation" && (
<>
<div
className={`sidebar-action-list ${
activeList === "mechanics" ? "active" : ""
}`}
onClick={() => setActiveList("mechanics")}
>
<MechanicsIcon isActive={activeList === "mechanics"} />
</div>
<div
className={`sidebar-action-list ${
activeList === "simulations" ? "active" : ""
}`}
onClick={() => setActiveList("simulations")}
>
<SimulationIcon isActive={activeList === "simulations"} />
</div>
<div
className={`sidebar-action-list ${
activeList === "analysis" ? "active" : ""
}`}
onClick={() => setActiveList("analysis")}
>
<AnalysisIcon isActive={activeList === "analysis"} />
</div>
</>
)}
</div>
)}
{/* process builder */}
{toggleUI &&
activeList === "properties" &&
activeModule !== "visualization" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<GlobalProperties />
{/* <AsstePropertiies /> */}
</div>
</div>
)}
{/* simulation */}
{toggleUI && activeModule === "simulation" && (
<>
{activeList === "mechanics" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<MachineMechanics />
</div>
</div>
)}
{activeList === "analysis" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<Analysis />
</div>
</div>
)}
{activeList === "simulations" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<Simulations />
</div>
</div>
)}
</>
)}
{/* realtime visualization */}
{toggleUI && activeModule === "visualization" && <Visualization />}
</div>
);
};
export default SideBarRight;

View File

@@ -0,0 +1,143 @@
import React, { useState } from "react";
import { AI_Icon } from "../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
import { AnalysisPresetsType } from "../../../../types/analysis";
import RenderAnalysisInputs from "./RenderAnalysisInputs";
const Analysis: React.FC = () => {
const [selectedOption, setSelectedOption] = useState("Throughput time");
const handleSelect = (option: string) => {
setSelectedOption(option); // Normalize for key matching
};
const AnalysisPresets: AnalysisPresetsType = {
"Throughput time": [
{ type: "default", inputs: { label: "Height", activeOption: "mm" } },
{ type: "default", inputs: { label: "Width", activeOption: "mm" } },
{ type: "default", inputs: { label: "Length", activeOption: "mtr" } },
{ type: "default", inputs: { label: "Thickness", activeOption: "mm" } },
{
type: "default",
inputs: { label: "Raw Material", activeOption: "mm" },
},
{
type: "range",
inputs: { label: "Material flow", activeOption: "m/min" },
},
],
"Production capacity": [
{ type: "default", inputs: { label: "Height", activeOption: "mm" } },
{ type: "default", inputs: { label: "Width", activeOption: "mm" } },
{ type: "default", inputs: { label: "Length", activeOption: "mtr" } },
{ type: "default", inputs: { label: "Thickness", activeOption: "mm" } },
{
type: "default",
inputs: { label: "Raw Material", activeOption: "mm" },
},
{
type: "range",
inputs: { label: "Material flow", activeOption: "m/min" },
},
{
type: "range",
inputs: { label: "Shift 1", activeOption: "hr(s)" },
},
{
type: "range",
inputs: { label: "Shift 2", activeOption: "hr(s)" },
},
{
type: "range",
inputs: { label: "Over time", activeOption: "hr(s)" },
},
],
ROI: [
{
type: "default",
inputs: { label: "Equipment Cost", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Employee Salary", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Labor Cost", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Cost per unit", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Electricity cost", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Upkeep Cost", activeOption: "INR" },
},
{
type: "default",
inputs: { label: "Working Hours", activeOption: "Hrs" },
},
{
type: "default",
inputs: { label: "Power Usage", activeOption: "KWH" },
},
{ type: "default", inputs: { label: "KWH", activeOption: "Mos" } },
{
type: "default",
inputs: { label: "Man Power", activeOption: "Person" },
},
],
};
return (
<div className="analysis-main-wrapper">
<div className="analysis-main-container">
<div className="header">Object</div>
<div className="generate-report-button">
<AI_Icon /> Generate Report
</div>
<div className="analysis-content-container">
<div className="dropdown-header-container">
<div className="value">Create Analysis</div>
</div>
<div className="dropdown-content-container">
<RegularDropDown
header={selectedOption}
options={["Throughput time", "Production capacity", "ROI"]}
onSelect={handleSelect}
search={false}
/>
</div>
{/* Render only the selected option */}
<RenderAnalysisInputs
keyName={selectedOption}
presets={
AnalysisPresets[selectedOption as keyof AnalysisPresetsType]
}
/>
<div className="buttons-container">
<input type="button" value={"Clear"} className="cancel" />
<input type="button" value={"Calculate"} className="submit" />
</div>
<div className="create-custom-analysis-container">
<div className="custom-analysis-header">Create Custom Analysis</div>
<div className="content">
Click <span>'Create'</span> to enhances decision-making by
providing actionable insights, optimizing operations that adapts
to the unique challenges.
</div>
<div className="input">
<input type="button" value={"Create"} className="submit" />
</div>
</div>
</div>
</div>
</div>
);
};
export default Analysis;

View File

@@ -0,0 +1,38 @@
import React from "react";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import InputRange from "../../../ui/inputs/InputRange";
import { AnalysisPresetsType } from "../../../../types/analysis";
interface InputRendererProps {
keyName: string;
presets: AnalysisPresetsType[keyof AnalysisPresetsType];
}
const RenderAnalysisInputs: React.FC<InputRendererProps> = ({
keyName,
presets,
}) => {
return (
<div key={`main-${keyName}`} className="analysis-inputs">
{presets.map((preset, index) => {
if (preset.type === "default") {
return (
<InputWithDropDown
key={index}
label={preset.inputs.label}
value=""
activeOption={preset.inputs.activeOption}
onChange={() => {}}
/>
);
}
if (preset.type === "range") {
return <InputRange key={index} label={preset.inputs.label} />;
}
return null;
})}
</div>
);
};
export default RenderAnalysisInputs;

View File

@@ -0,0 +1,41 @@
import React from "react";
interface PositionInputProps {
onChange: (value: string) => void; // Callback for value change
placeholder?: string; // Optional placeholder
type?: string; // Input type (e.g., text, number, email)
}
const PositionInput: React.FC<PositionInputProps> = ({
onChange,
placeholder = "Enter value", // Default placeholder
type = "number", // Default type
}) => {
return (
<div className="custom-input-container">
<div className="header">Position</div>
<div className="inputs-container">
<div className="input-container">
<div className="custom-input-label">X : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
/>
</div>
<div className="input-container">
<div className="custom-input-label">Y : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
/>
</div>
</div>
</div>
);
};
export default PositionInput;

View File

@@ -0,0 +1,32 @@
import React from "react";
interface RotationInputProps {
onChange: (value: string) => void; // Callback for value change
placeholder?: string; // Optional placeholder
type?: string; // Input type (e.g., text, number, email)
}
const RotationInput: React.FC<RotationInputProps> = ({
onChange,
placeholder = "Enter value", // Default placeholder
type = "number", // Default type
}) => {
return (
<div className="custom-input-container">
<div className="header">Rotation</div>
<div className="inputs-container" style={{display: "block"}}>
<div className="input-container">
<div className="custom-input-label">Rotate : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
/>
</div>
</div>
</div>
);
};
export default RotationInput;

View File

@@ -0,0 +1,205 @@
import React, { useRef, useState } from "react";
import {
AddIcon,
InfoIcon,
RemoveIcon,
ResizeHeightIcon,
} from "../../../icons/ExportCommonIcons";
import RenameInput from "../../../ui/inputs/RenameInput";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
import { handleResize } from "../../../../functions/handleResizePannel";
import EyeDropInput from "../../../ui/inputs/EyeDropInput";
const MachineMechanics: React.FC = () => {
const [actionList, setActionList] = useState<string[]>([]);
const [triggerList, setTriggerList] = useState<string[]>([]);
const [selectedItem, setSelectedItem] = useState<{
type: "action" | "trigger";
name: string;
} | null>(null);
const actionsContainerRef = useRef<HTMLDivElement>(null);
const triggersContainerRef = useRef<HTMLDivElement>(null);
const handleAddAction = () => {
setActionList([...actionList, `Action ${actionList.length + 1}`]);
};
const handleAddTrigger = () => {
setTriggerList([...triggerList, `Trigger ${triggerList.length + 1}`]);
};
const handleRemoveAction = (index: number) => {
setActionList(actionList.filter((_, i) => i !== index));
if (
selectedItem?.type === "action" &&
selectedItem.name === actionList[index]
) {
setSelectedItem(null);
}
};
const handleRemoveTrigger = (index: number) => {
setTriggerList(triggerList.filter((_, i) => i !== index));
if (
selectedItem?.type === "trigger" &&
selectedItem.name === triggerList[index]
) {
setSelectedItem(null);
}
};
const handleSelectItem = (type: "action" | "trigger", name: string) => {
setSelectedItem({ type, name });
};
const [processes, setProcesses] = useState<string[]>([]);
const [activeProcess, setActiveProcesses] = useState<string>();
const handleSelect = (option: string) => {
setActiveProcesses(option); // Update the active option state
};
const handleAddProcess = () => {
const newProcess = `Process ${processes.length + 1}`; // Generate new process name dynamically
setProcesses((prevProcesses) => [...prevProcesses, newProcess]); // Update the state with the new process
};
return (
<div className="machine-mechanics-container">
<div className="machine-mechanics-header">Selected Object</div>
<div className="process-list-container">
<div className="label">Process:</div>
<RegularDropDown
header={activeProcess || "add process ->"}
options={processes}
onSelect={handleSelect}
/>
<div className="add-new-process" onClick={handleAddProcess}>
<AddIcon />
</div>
</div>
<div className="machine-mechanics-content-container">
<div className="actions">
<div className="header">
<div className="header-value">Actions</div>
<div className="add-button" onClick={handleAddAction}>
<AddIcon /> Add
</div>
</div>
<div
className="lists-main-container"
ref={actionsContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{actionList.map((action, index) => (
<div
key={index}
className={`list-item ${
selectedItem?.type === "action" &&
selectedItem.name === action
? "active"
: ""
}`}
>
<div
className="value"
onClick={() => handleSelectItem("action", action)}
>
<RenameInput value={action} />
</div>
<div
className="remove-button"
onClick={() => handleRemoveAction(index)}
>
<RemoveIcon />
</div>
</div>
))}
</div>
<div
className="resize-icon"
id="action-resize"
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
>
<ResizeHeightIcon />
</div>
</div>
</div>
<div className="triggers">
<div className="header">
<div className="header-value">Triggers</div>
<div className="add-button" onClick={handleAddTrigger}>
<AddIcon /> Add
</div>
</div>
<div
className="lists-main-container"
ref={triggersContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{triggerList.map((trigger, index) => (
<div
key={index}
className={`list-item ${
selectedItem?.type === "trigger" &&
selectedItem.name === trigger
? "active"
: ""
}`}
>
<div
className="value"
onClick={() => handleSelectItem("trigger", trigger)}
>
<RenameInput value={trigger} />
</div>
<div
className="remove-button"
onClick={() => handleRemoveTrigger(index)}
>
<RemoveIcon />
</div>
</div>
))}
</div>
<div
className="resize-icon"
id="trigger-resize"
onMouseDown={(e) => handleResize(e, triggersContainerRef)}
>
<ResizeHeightIcon />
</div>
</div>
</div>
<div className="selected-properties-container">
{selectedItem && (
<>
<div className="properties-header">{selectedItem.name}</div>
<LabledDropdown
defaultOption="On-hit"
options={["On-hit", "Buffer"]}
/>
<InputWithDropDown
label="Speed"
value=""
activeOption=".mm"
onChange={() => {}}
/>
<EyeDropInput />
</>
)}
</div>
<div className="footer">
<InfoIcon />
By Selecting Path, you can create Object Triggers.
</div>
</div>
</div>
);
};
export default MachineMechanics;

View File

@@ -0,0 +1,88 @@
import React, { useState } from "react";
import InputToggle from "../../../ui/inputs/InputToggle";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import { RemoveIcon } from "../../../icons/ExportCommonIcons";
import PositionInput from "../customInput/PositionInputs";
import RotationInput from "../customInput/RotationInput";
interface UserData {
id: number; // Unique identifier for the user data
label: string; // Label of the user data field
value: string; // Value of the user data field
}
const AssetProperties: React.FC = () => {
const [userData, setUserData] = useState<UserData[]>([]); // State to track user data
const [nextId, setNextId] = useState(1); // Unique ID for new entries
// Function to handle adding new user data
const handleAddUserData = () => {
const newUserData: UserData = {
id: nextId,
label: `Property ${nextId}`,
value: "",
};
setUserData([...userData, newUserData]);
setNextId(nextId + 1); // Increment the ID for the next entry
};
// Function to update the value of a user data entry
const handleUserDataChange = (id: number, newValue: string) => {
setUserData((prevUserData) =>
prevUserData.map((data) =>
data.id === id ? { ...data, value: newValue } : data
)
);
};
// Remove user data
const handleRemoveUserData = (id: number) => {
setUserData((prevUserData) =>
prevUserData.filter((data) => data.id !== id)
);
};
return (
<div className="asset-properties-container">
<div className="header">Selected Object</div>
<div className="split"></div>
<PositionInput onChange={() => {}} />
<RotationInput onChange={() => {}} />
<div className="split"></div>
<InputToggle inputKey="visible" label="Visible" />
<InputToggle inputKey="frustumCull" label="Frustum cull" />
<div className="header">User Data</div>
{/* Map through userData and render InputWithDropDown for each entry */}
{userData.map((data) => (
<div className="input-container">
<InputWithDropDown
key={data.id}
label={data.label}
value={data.value}
editableLabel
onChange={(newValue) => handleUserDataChange(data.id, newValue)} // Pass the change handler
/>
<div
className="remove-button"
onClick={() => handleRemoveUserData(data.id)}
>
<RemoveIcon />
</div>
</div>
))}
{/* Add new user data */}
<div className="optimize-button" onClick={handleAddUserData}>
+ Add
</div>
</div>
);
};
export default AssetProperties;

View File

@@ -0,0 +1,81 @@
import React, { useState } from "react";
import InputRange from "../../../ui/inputs/InputRange";
import InputToggle from "../../../ui/inputs/InputToggle";
import { AI_Icon } from "../../../icons/ExportCommonIcons";
import LabeledButton from "../../../ui/inputs/LabledButton";
const GlobalProperties: React.FC = () => {
const [limitDistance, setLimitDistance] = useState(false);
const [distance, setDistance] = useState<number>(5);
const [limitGridDistance, setLimitGridDistance] = useState(false);
const [gridDistance, setGridDistance] = useState<number>(5);
function optimizeScene() {
setLimitDistance(true);
setDistance(5);
}
function updateDistance(value: number) {
setDistance(value);
}
function updateGridDistance(value: number) {
setGridDistance(value);
}
return (
<div className="global-properties-container">
<div className="header">Environment</div>
<div className="optimize-button" onClick={optimizeScene}>
<AI_Icon />
Optimize
</div>
<div className="split"></div>
<InputToggle inputKey="1" label="Roof Visibility" />
<InputToggle inputKey="2" label="Wall Visibility" />
<InputToggle inputKey="3" label="Shadows Visibility" />
<LabeledButton label="Reset Camera" onClick={() => {}} value="Reset"/>
<div className="split"></div>
<InputToggle
inputKey="4"
label="Limit Render Distance"
value={limitDistance}
onClick={() => {
setLimitDistance(!limitDistance);
}}
/>
<InputRange
label="Distance"
disabled={!limitDistance}
value={distance}
key={"5"}
onChange={(value: number) => updateDistance(value)}
/>
<div className="split"></div>
<InputToggle
inputKey="6"
label="Display Grid"
value={limitGridDistance}
onClick={() => {
setLimitGridDistance(!limitGridDistance);
}}
/>
<InputRange
label="Tile Distance"
disabled={!limitGridDistance}
value={gridDistance}
key={"7"}
onChange={(value: number) => updateGridDistance(value)}
/>
</div>
);
};
export default GlobalProperties;

View File

@@ -0,0 +1,147 @@
import React, { useRef, useState } from "react";
import {
AddIcon,
ArrowIcon,
RemoveIcon,
ResizeHeightIcon,
} from "../../../icons/ExportCommonIcons";
import RenameInput from "../../../ui/inputs/RenameInput";
import { handleResize } from "../../../../functions/handleResizePannel";
interface Path {
pathName: string; // Represents the name of the path
Children: string[]; // Represents the list of child points
}
interface DropListProps {
val: Path; // Use the Path interface for the val prop
}
const DropList: React.FC<DropListProps> = ({ val }) => {
const [openDrop, setOpenDrop] = useState(false);
return (
<div className="process-container">
<div
className="value"
onClick={() => {
setOpenDrop(!openDrop);
}}
>
{val.pathName}
<div className="arrow-container">
<ArrowIcon />
</div>
</div>
{val.Children && openDrop && (
<div className="children-drop">
{val.Children.map((child, index) => (
<div key={index} className="value">
{child}
</div>
))}
</div>
)}
</div>
);
};
const Simulations: React.FC = () => {
const productsContainerRef = useRef<HTMLDivElement>(null);
const [productsList, setProductsList] = useState<string[]>([]);
const [selectedItem, setSelectedItem] = useState<string>();
const handleAddAction = () => {
setProductsList([...productsList, `Product ${productsList.length + 1}`]);
};
const handleRemoveAction = (index: number) => {
setProductsList(productsList.filter((_, i) => i !== index));
if (selectedItem === productsList[index]) {
setSelectedItem("");
}
};
const Value = [
{ pathName: "Path 1", Children: ["Point 1", "Point 2"] },
{ pathName: "Path 2", Children: ["Point 1", "Point 2"] },
{ pathName: "Path 3", Children: ["Point 1", "Point 2"] },
];
return (
<div className="simulations-container">
<div className="header">Simulations</div>
<div className="add-product-container">
<div className="actions">
<div className="header">
<div className="header-value">Products</div>
<div className="add-button" onClick={handleAddAction}>
<AddIcon /> Add
</div>
</div>
<div
className="lists-main-container"
ref={productsContainerRef}
style={{ height: "120px" }}
>
<div className="list-container">
{productsList.map((action, index) => (
<div
key={index}
className={`list-item ${
selectedItem === action ? "active" : ""
}`}
>
<div
className="value"
onClick={() => setSelectedItem(action)}
>
<input type="radio" name="products" id="products" />
<RenameInput value={action} />
</div>
<div
className="remove-button"
onClick={() => handleRemoveAction(index)}
>
<RemoveIcon />
</div>
</div>
))}
</div>
<div
className="resize-icon"
id="action-resize"
onMouseDown={(e) => handleResize(e, productsContainerRef)}
>
<ResizeHeightIcon />
</div>
</div>
</div>
<div className="simulation-process">
<div className="collapse-header-container">
<div className="header">Operations</div>
<div className="arrow-container">
<ArrowIcon />
</div>
</div>
{Value.map((val) => (
<DropList val={val} />
))}
</div>
<div className="compare-simulations-container">
<div className="compare-simulations-header">
Need to Compare Layout?
</div>
<div className="content">
Click <span>'Compare'</span> to review and analyze the layout
differences between them.
</div>
<div className="input">
<input type="button" value={"Compare"} className="submit" />
</div>
</div>
</div>
</div>
);
};
export default Simulations;

View File

@@ -0,0 +1,27 @@
import { useState } from "react";
import ToggleHeader from "../../../ui/inputs/ToggleHeader";
import Data from "./data/Data";
import Design from "./design/Design";
const Visualization = () => {
const [activeOption, setActiveOption] = useState("Data");
const handleToggleClick = (option: string) => {
setActiveOption(option); // Update the active option
};
return (
<div className="visualization-right-sideBar">
<ToggleHeader
options={["Data", "Design"]}
activeOption={activeOption}
handleClick={handleToggleClick}
/>
<div className="sidebar-right-content-container">
{activeOption === "Data" ? <Data /> : <Design />}
</div>
</div>
);
};
export default Visualization;

View File

@@ -0,0 +1,175 @@
import { useEffect, useState } from "react";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons";
import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown";
// Define the data structure for demonstration purposes
const DATA_STRUCTURE = {
furnace: {
coolingRate: "coolingRate",
furnaceTemperature: "furnaceTemperature",
heatingRate: "heatingRate",
machineId: "machineId",
powerConsumption: "powerConsumption",
status: "status",
timestamp: "timestamp",
vacuumLevel: "vacuumLevel",
},
testDevice: {
abrasiveLevel: {
data1: "Data 1",
data2: "Data 2",
data3: "Data 3",
},
airPressure: "airPressure",
machineId: "machineId",
powerConsumption: "powerConsumption",
status: "status",
temperature: {
data1: "Data 1",
data2: "Data 2",
data3: "Data 3",
},
timestamp: {
data1: {
Data01: "Data 01",
Data02: "Data 02",
Data03: "Data 03",
},
data2: "Data 2",
data3: "Data 3",
},
},
};
interface Child {
id: number;
easing: string;
}
interface Group {
id: number;
easing: string;
children: Child[];
}
const Data = () => {
const { selectedChartId } = useWidgetStore();
// State to store groups for all widgets (using Widget.id as keys)
const [chartDataGroups, setChartDataGroups] = useState<
Record<string, Group[]>
>({});
useEffect(() => {
// Initialize data groups for the newly selected widget if it doesn't exist
if (selectedChartId && !chartDataGroups[selectedChartId.id]) {
setChartDataGroups((prev) => ({
...prev,
[selectedChartId.id]: [
{
id: Date.now(),
easing: "Connecter 1",
children: [{ id: Date.now(), easing: "Linear" }],
},
],
}));
}
}, [selectedChartId]);
// Handle adding a new child to the group
const handleAddClick = (groupId: number) => {
setChartDataGroups((prevGroups) => {
const currentGroups = prevGroups[selectedChartId.id] || [];
const group = currentGroups.find((g) => g.id === groupId);
if (group && group.children.length < 7) {
const newChild = { id: Date.now(), easing: "Linear" };
return {
...prevGroups,
[selectedChartId.id]: currentGroups.map((g) =>
g.id === groupId ? { ...g, children: [...g.children, newChild] } : g
),
};
}
return prevGroups;
});
};
// Remove a child from a group
const removeChild = (groupId: number, childId: number) => {
setChartDataGroups((currentGroups) => {
const currentChartData = currentGroups[selectedChartId.id] || [];
return {
...currentGroups,
[selectedChartId.id]: currentChartData.map((group) =>
group.id === groupId
? {
...group,
children: group.children.filter(
(child) => child.id !== childId
),
}
: group
),
};
});
};
return (
<div className="dataSideBar">
{selectedChartId?.title && (
<div className="sideBarHeader">{selectedChartId?.title}</div>
)}
{/* Render groups dynamically */}
{chartDataGroups[selectedChartId?.id]?.map((group) => (
<div key={group.id} className="inputs-wrapper">
{group.children.map((child, index) => (
<div key={child.id} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropDown data={DATA_STRUCTURE} />
{/* Add Icon */}
{group.children.length < 7 && (
<div
className="icon"
onClick={() => handleAddClick(group.id)} // Pass groupId to handleAddClick
>
<AddIcon />
</div>
)}
{/* Remove Icon */}
<span
className={`datas__separator ${
group.children.length > 1 ? "" : "disable"
}`}
onClick={(e) => {
e.stopPropagation(); // Prevent event bubbling
removeChild(group.id, child.id); // Pass groupId and childId to removeChild
}}
>
<RemoveIcon />
</span>
</div>
</div>
))}
</div>
))}
{/* Info Box */}
<div className="infoBox">
<span className="infoIcon">i</span>
<p>
<em>
By adding templates and widgets, you create a customizable and
dynamic environment.
</em>
</p>
</div>
</div>
);
};
export default Data;

View File

@@ -0,0 +1,209 @@
import { useState } from "react";
import { useWidgetStore } from "../../../../../store/useWidgetStore";
import ChartComponent from "../../../sidebarLeft/visualization/widgets/ChartComponent";
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
// Define Props Interface
interface Widget {
id: string;
type: string; // Chart type (e.g., "bar", "line")
panel: "top" | "bottom" | "left" | "right"; // Panel location
title: string;
fontFamily?: string;
fontSize?: string;
fontWeight?: string;
data: {
labels: string[];
datasets: {
data: number[];
backgroundColor: string;
borderColor: string;
borderWidth: number;
}[];
}; // Data for the chart
}
const Design = () => {
const [selectedName, setSelectedName] = useState("drop down");
console.log("selectedName: ", selectedName);
const [selectedElement, setSelectedElement] = useState("drop down");
console.log("selectedElement: ", selectedElement);
const [selectedFont, setSelectedFont] = useState("drop down");
console.log("selectedFont: ", selectedFont);
const [selectedSize, setSelectedSize] = useState("drop down");
console.log("selectedSize: ", selectedSize);
const [selectedWeight, setSelectedWeight] = useState("drop down");
console.log("selectedWeight: ", selectedWeight);
const [elementColor, setElementColor] = useState("#6f42c1"); // Default color for elements
const [showColorPicker, setShowColorPicker] = useState(false); // Manage visibility of the color picker
// Zustand Store Hooks
const { selectedChartId, setSelectedChartId, widgets, setWidgets } =
useWidgetStore();
// Handle Widget Updates
const handleUpdateWidget = (updatedProperties: Partial<Widget>) => {
if (!selectedChartId) return;
// Update the selectedChartId
const updatedChartId = {
...selectedChartId,
...updatedProperties,
};
setSelectedChartId(updatedChartId);
// Update the widgets array
const updatedWidgets = widgets.map((widget) =>
widget.id === selectedChartId.id
? { ...widget, ...updatedProperties }
: widget
);
setWidgets(updatedWidgets);
};
// Default Chart Data
const defaultChartData = {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
datasets: [
{
data: [65, 59, 80, 81, 56, 55, 40],
backgroundColor: elementColor, // Default background color
borderColor: "#ffffff", // Default border color
borderWidth: 1,
},
],
};
return (
<div className="design">
{/* Title of the Selected Widget */}
<div className="selectedWidget">
{selectedChartId?.title || "Widget 1"}
</div>
{/* Chart Component */}
<div className="reviewChart">
{selectedChartId && (
<ChartComponent
type={selectedChartId.type}
title={selectedChartId.title}
data={selectedChartId.data || defaultChartData} // Use widget data or default
/>
)}
</div>
{/* Options Container */}
<div className="optionsContainer">
{/* Name Dropdown */}
<div className="option">
<span>Name</span>
<RegularDropDown
header={selectedChartId?.title || "Select Name"}
options={["Option 1", "Option 2", "Option 3"]}
onSelect={(value) => {
setSelectedName(value);
handleUpdateWidget({ title: value });
}}
/>
</div>
{/* Element Dropdown */}
<div className="option">
<span>Element</span>
<RegularDropDown
header={selectedChartId?.type || "Select Element"}
options={["bar", "line", "pie", "doughnut", "radar", "polarArea"]} // Valid chart types
onSelect={(value) => {
setSelectedElement(value);
handleUpdateWidget({ type: value });
}}
/>
</div>
{/* Font Family Dropdown */}
<div className="option">
<span>Font Family</span>
<RegularDropDown
header={selectedChartId?.fontFamily || "Select Font"}
options={["Arial", "Roboto", "Sans-serif"]}
onSelect={(value) => {
setSelectedFont(value);
handleUpdateWidget({ fontFamily: value });
}}
/>
</div>
{/* Size Dropdown */}
<div className="option">
<span>Size</span>
<RegularDropDown
header={selectedChartId?.fontSize || "Select Size"}
options={["12px", "14px", "16px", "18px"]}
onSelect={(value) => {
setSelectedSize(value);
handleUpdateWidget({ fontSize: value });
}}
/>
</div>
{/* Weight Dropdown */}
<div className="option">
<span>Weight</span>
<RegularDropDown
header={selectedChartId?.fontWeight || "Select Weight"}
options={["Light", "Regular", "Bold"]}
onSelect={(value) => {
setSelectedWeight(value);
handleUpdateWidget({ fontWeight: value });
}}
/>
</div>
{/* Element Color Picker */}
<div className="option">
<div
className="header"
onClick={() => setShowColorPicker((prev) => !prev)}
>
<span>Element Color</span>
<div className="icon"></div>{" "}
{/* Change icon based on the visibility */}
</div>
{/* Show color picker only when 'showColorPicker' is true */}
{showColorPicker && (
<div className="colorDisplayer">
<input
type="color"
value={elementColor}
onChange={(e) => {
setElementColor(e.target.value);
handleUpdateWidget({
data: {
labels: selectedChartId?.data?.labels || [],
datasets: [
{
...selectedChartId?.data?.datasets[0],
backgroundColor: e.target.value, // Update the element color
},
],
},
});
}}
/>
{/* Display the selected color value */}
<span style={{ marginLeft: "10px" }}>{elementColor}</span>
</div>
)}
</div>
</div>
</div>
);
};
export default Design;