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 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;