updated real time viz ui
This commit is contained in:
parent
2da7011462
commit
92676cd12c
|
@ -58,8 +58,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.child {
|
.child {
|
||||||
padding-left: 13%;
|
// padding-left: 13%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,50 @@
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding-bottom: 40px;
|
padding-bottom: 40px;
|
||||||
|
|
||||||
|
.progressBar {
|
||||||
|
height: auto !important;
|
||||||
|
padding: 12px 10px 41px 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock {
|
||||||
|
padding: 13px 5px;
|
||||||
|
background-color: #E0DFFF80;
|
||||||
|
border-radius: 6.33px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.stock-item {
|
||||||
|
.stockValues {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 3px;
|
||||||
|
|
||||||
|
.value {
|
||||||
|
color: #4a90e2;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-description {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -63,6 +107,15 @@
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
background-color: #4a90e2;
|
||||||
|
color: #FCFDFD !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.zoon-wrapper.bottom {
|
||||||
|
bottom: 210px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect, useMemo, useCallback } from "react";
|
||||||
import asset1 from "../../assets/images/tempimages/asset1.png";
|
import asset1 from "../../assets/images/tempimages/asset1.png";
|
||||||
import asset2 from "../../assets/images/tempimages/asset2.png";
|
import asset2 from "../../assets/images/tempimages/asset2.png";
|
||||||
import asset3 from "../../assets/images/tempimages/asset3.png";
|
import asset3 from "../../assets/images/tempimages/asset3.png";
|
||||||
|
@ -39,21 +39,24 @@ const SideBar: React.FC<SideBarProps> = ({ header, defaultActive }) => {
|
||||||
const [filteredData, setFilteredData] = useState<FilteredAssets[]>([]);
|
const [filteredData, setFilteredData] = useState<FilteredAssets[]>([]);
|
||||||
const [inputData, setInputData] = useState<string>("");
|
const [inputData, setInputData] = useState<string>("");
|
||||||
|
|
||||||
const [assets, setAssets] = useState<FilteredAssets[]>([]);
|
const assets: FilteredAssets[] = useMemo(
|
||||||
|
() => [
|
||||||
|
{ filename: "Asset 1", thumbnail: asset1, modelfileID: "1" },
|
||||||
|
{ filename: "Asset 2", thumbnail: asset2, modelfileID: "2" },
|
||||||
|
{ filename: "Asset 3", thumbnail: asset3, modelfileID: "3" },
|
||||||
|
{ filename: "Asset 4", thumbnail: asset4, modelfileID: "4" },
|
||||||
|
{ filename: "Asset 5", thumbnail: asset5, modelfileID: "5" },
|
||||||
|
{ filename: "Asset 6", thumbnail: asset6, modelfileID: "6" },
|
||||||
|
{ filename: "Asset 7", thumbnail: asset7, modelfileID: "7" },
|
||||||
|
{ filename: "Asset 8", thumbnail: asset8, modelfileID: "8" },
|
||||||
|
{ filename: "Asset 9", thumbnail: asset9, modelfileID: "9" },
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
// const assets: FilteredAssets[] = [
|
// Memoized Input Change Handler
|
||||||
// { name: "Asset 1", img: asset1 },
|
const handleInputChange = useCallback(
|
||||||
// { name: "Asset 2", img: asset2 },
|
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
// { name: "Asset 3", img: asset3 },
|
|
||||||
// { name: "Asset 4", img: asset4 },
|
|
||||||
// { name: "Asset 5", img: asset5 },
|
|
||||||
// { name: "Asset 6", img: asset6 },
|
|
||||||
// { name: "Asset 7", img: asset7 },
|
|
||||||
// { name: "Asset 8", img: asset8 },
|
|
||||||
// { name: "Asset 9", img: asset9 },
|
|
||||||
// ];
|
|
||||||
|
|
||||||
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const value = event.target.value;
|
const value = event.target.value;
|
||||||
setInputData(value);
|
setInputData(value);
|
||||||
|
|
||||||
|
@ -61,11 +64,16 @@ const SideBar: React.FC<SideBarProps> = ({ header, defaultActive }) => {
|
||||||
asset.filename.toLowerCase().includes(value.toLowerCase())
|
asset.filename.toLowerCase().includes(value.toLowerCase())
|
||||||
);
|
);
|
||||||
setFilteredData(filtered);
|
setFilteredData(filtered);
|
||||||
};
|
},
|
||||||
|
[assets]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update Active State Only When Necessary
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setActive(defaultActive || header[0]);
|
if (defaultActive && defaultActive !== active) {
|
||||||
}, [header, defaultActive]);
|
setActive(defaultActive);
|
||||||
|
}
|
||||||
|
}, [defaultActive]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -86,6 +94,7 @@ const SideBar: React.FC<SideBarProps> = ({ header, defaultActive }) => {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Render Components Based on Active Header */}
|
||||||
{active === "Outline" && <Outline />}
|
{active === "Outline" && <Outline />}
|
||||||
{active === "Asset library" && <AssetLibrary />}
|
{active === "Asset library" && <AssetLibrary />}
|
||||||
{active === "Overview" && <Overview />}
|
{active === "Overview" && <Overview />}
|
||||||
|
@ -96,4 +105,4 @@ const SideBar: React.FC<SideBarProps> = ({ header, defaultActive }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SideBar;
|
export default React.memo(SideBar);
|
||||||
|
|
|
@ -1,13 +1,23 @@
|
||||||
import React, { useEffect, useRef, useMemo } from "react";
|
import React, { useEffect, useRef, useMemo } from "react";
|
||||||
import { Chart, ChartType } from "chart.js/auto";
|
import { Chart, ChartType } from "chart.js/auto";
|
||||||
import { useThemeStore, useWidgetStore } from "../../../../store/store";
|
import { useThemeStore } from "../../../../store/store";
|
||||||
|
|
||||||
|
// Define Props Interface
|
||||||
interface ChartComponentProps {
|
interface ChartComponentProps {
|
||||||
type: ChartType;
|
type: any; // Type of chart (e.g., "bar", "line", etc.)
|
||||||
title: string;
|
title: string; // Title of the chart
|
||||||
fontFamily?: string;
|
fontFamily?: string; // Optional font family for the chart title
|
||||||
fontSize?: string;
|
fontSize?: string; // Optional font size for the chart title
|
||||||
fontWeight?: "Light" | "Regular" | "Bold"; // Explicitly typing fontWeight
|
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 = ({
|
const ChartComponent = ({
|
||||||
|
@ -16,11 +26,12 @@ const ChartComponent = ({
|
||||||
fontFamily,
|
fontFamily,
|
||||||
fontSize,
|
fontSize,
|
||||||
fontWeight = "Regular", // Default to "Regular"
|
fontWeight = "Regular", // Default to "Regular"
|
||||||
|
data: propsData,
|
||||||
}: ChartComponentProps) => {
|
}: ChartComponentProps) => {
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
const { themeColor } = useThemeStore();
|
const { themeColor } = useThemeStore();
|
||||||
|
|
||||||
// Memoize theme colors to prevent unnecessary recalculations
|
// Memoize Theme Colors to Prevent Unnecessary Recalculations
|
||||||
const buttonActionColor = useMemo(
|
const buttonActionColor = useMemo(
|
||||||
() => themeColor[0] || "#5c87df",
|
() => themeColor[0] || "#5c87df",
|
||||||
[themeColor]
|
[themeColor]
|
||||||
|
@ -30,7 +41,7 @@ const ChartComponent = ({
|
||||||
[themeColor]
|
[themeColor]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Memoize font weight mapping
|
// Memoize Font Weight Mapping
|
||||||
const chartFontWeightMap = useMemo(
|
const chartFontWeightMap = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
Light: "lighter" as const,
|
Light: "lighter" as const,
|
||||||
|
@ -40,19 +51,19 @@ const ChartComponent = ({
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Parse and memoize fontSize
|
// Parse and Memoize Font Size
|
||||||
const fontSizeValue = useMemo(
|
const fontSizeValue = useMemo(
|
||||||
() => (fontSize ? parseInt(fontSize) : 12),
|
() => (fontSize ? parseInt(fontSize) : 12),
|
||||||
[fontSize]
|
[fontSize]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Determine and memoize font weight
|
// Determine and Memoize Font Weight
|
||||||
const fontWeightValue = useMemo(
|
const fontWeightValue = useMemo(
|
||||||
() => chartFontWeightMap[fontWeight], // No need for '|| "normal"' since fontWeight is guaranteed to be valid
|
() => chartFontWeightMap[fontWeight],
|
||||||
[fontWeight, chartFontWeightMap]
|
[fontWeight, chartFontWeightMap]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Memoize chart font style
|
// Memoize Chart Font Style
|
||||||
const chartFontStyle = useMemo(
|
const chartFontStyle = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
family: fontFamily || "Arial",
|
family: fontFamily || "Arial",
|
||||||
|
@ -62,23 +73,10 @@ const ChartComponent = ({
|
||||||
[fontFamily, fontSizeValue, fontWeightValue]
|
[fontFamily, fontSizeValue, fontWeightValue]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Memoize chart data
|
// Memoize Chart Data
|
||||||
const data = useMemo(
|
const data = useMemo(() => propsData, [propsData]);
|
||||||
() => ({
|
|
||||||
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
data: [65, 59, 80, 81, 56, 55, 40],
|
|
||||||
backgroundColor: buttonActionColor,
|
|
||||||
borderColor: buttonAbortColor,
|
|
||||||
borderWidth: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
[buttonActionColor, buttonAbortColor]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Memoize chart options
|
// Memoize Chart Options
|
||||||
const options = useMemo(
|
const options = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
responsive: true,
|
responsive: true,
|
||||||
|
@ -97,6 +95,7 @@ const ChartComponent = ({
|
||||||
[title, chartFontStyle]
|
[title, chartFontStyle]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Initialize Chart on Component Mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!canvasRef.current) return;
|
if (!canvasRef.current) return;
|
||||||
|
|
||||||
|
@ -105,10 +104,21 @@ const ChartComponent = ({
|
||||||
|
|
||||||
const chart = new Chart(ctx, { type, data, options });
|
const chart = new Chart(ctx, { type, data, options });
|
||||||
|
|
||||||
|
// Cleanup: Destroy the chart instance when the component unmounts
|
||||||
return () => chart.destroy();
|
return () => chart.destroy();
|
||||||
}, [type, data, options]); // Only recreate chart when these essentials change
|
}, [type, data, options]); // Only recreate the chart when these dependencies change
|
||||||
|
|
||||||
return <canvas ref={canvasRef} style={{ width: "100%", height: "100%" }} />;
|
return <canvas ref={canvasRef} style={{ width: "100%", height: "100%" }} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(ChartComponent);
|
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)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import RegularDropDown from "../../inputs/regularDropDown";
|
import RegularDropDown from "../../inputs/regularDropDown";
|
||||||
import { LinkIcon, RemoveIcon } from "../../../../assets/images/svgExports";
|
import { LinkIcon, RemoveIcon } from "../../../../assets/images/svgExports";
|
||||||
|
import { useWidgetStore } from "../../../../store/store";
|
||||||
|
|
||||||
interface Child {
|
interface Child {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -14,84 +15,72 @@ interface Group {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Data = () => {
|
const Data = () => {
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
const [selectedWidget] = useState("Widget 1");
|
const [selectedWidget] = useState("Widget 1");
|
||||||
const [groups, setGroups] = useState<Group[]>([
|
|
||||||
|
// State to store groups for all widgets (using Widget.id as keys)
|
||||||
|
const [chartDataGroups, setChartDataGroups] = useState<
|
||||||
|
Record<string, Group[]>
|
||||||
|
>({});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("Selected Chart ID:", selectedChartId);
|
||||||
|
|
||||||
|
// Initialize data groups for the newly selected widget if it doesn't exist
|
||||||
|
if (selectedChartId && !chartDataGroups[selectedChartId.id]) {
|
||||||
|
setChartDataGroups((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[selectedChartId.id]: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: Date.now(),
|
||||||
easing: "Connecter 1",
|
easing: "Connecter 1",
|
||||||
children: [
|
children: [
|
||||||
{ id: 1, easing: "Linear" },
|
{ id: Date.now(), easing: "Linear" },
|
||||||
{ id: 2, easing: "Ease Out" },
|
{ id: Date.now() + 1, easing: "Ease Out" },
|
||||||
{ id: 3, easing: "Linear" },
|
{ id: Date.now() + 2, easing: "Linear" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
],
|
||||||
|
}));
|
||||||
const handleLinkClick = (childId: number) => {
|
|
||||||
setGroups((currentGroups) => {
|
|
||||||
let sourceGroup: Group | undefined;
|
|
||||||
let sourceChild: Child | undefined;
|
|
||||||
|
|
||||||
// Find the source group and child
|
|
||||||
for (const group of currentGroups) {
|
|
||||||
sourceChild = group.children.find((c) => c.id === childId);
|
|
||||||
if (sourceChild) {
|
|
||||||
sourceGroup = group;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}, [selectedChartId]);
|
||||||
|
|
||||||
if (!sourceGroup || !sourceChild) return currentGroups;
|
// Handle linking children between groups
|
||||||
|
const handleLinkClick = (childId: number) => {};
|
||||||
// Remove child from source group
|
|
||||||
const updatedGroups = currentGroups
|
|
||||||
.map((group) => ({
|
|
||||||
...group,
|
|
||||||
children: group.children.filter((c) => c.id !== childId),
|
|
||||||
}))
|
|
||||||
.filter((group) => group.children.length > 0);
|
|
||||||
|
|
||||||
// Find or create target group
|
|
||||||
const targetGroup = updatedGroups.find(
|
|
||||||
(g) => g.id !== sourceGroup!.id && g.easing === sourceGroup!.easing
|
|
||||||
);
|
|
||||||
|
|
||||||
if (targetGroup) {
|
|
||||||
targetGroup.children.push(sourceChild);
|
|
||||||
} else {
|
|
||||||
updatedGroups.push({
|
|
||||||
id: Date.now(),
|
|
||||||
easing: sourceGroup.easing,
|
|
||||||
children: [sourceChild],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return updatedGroups;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// Remove a child from a group
|
||||||
const removeChild = (groupId: number, childId: number) => {
|
const removeChild = (groupId: number, childId: number) => {
|
||||||
setGroups((currentGroups) =>
|
setChartDataGroups((currentGroups) => {
|
||||||
currentGroups.map((group) => {
|
if (!selectedChartId) return currentGroups;
|
||||||
if (group.id === groupId) {
|
|
||||||
|
const currentChartData = currentGroups[selectedChartId.id] || [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
...currentGroups,
|
||||||
|
[selectedChartId.id]: currentChartData.map((group) =>
|
||||||
|
group.id === groupId
|
||||||
|
? {
|
||||||
...group,
|
...group,
|
||||||
children: group.children.map((child) =>
|
children: group.children.map((child) =>
|
||||||
child.id === childId ? { ...child, easing: "Linear" } : child
|
child.id === childId ? { ...child, easing: "Linear" } : child
|
||||||
),
|
),
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return group;
|
: group
|
||||||
})
|
),
|
||||||
);
|
};
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log("selectedChartId: ", selectedChartId?.title);
|
||||||
return (
|
return (
|
||||||
<div className="dataSideBar">
|
<div className="dataSideBar">
|
||||||
<div className="sideBarHeader">{selectedWidget}</div>
|
{selectedChartId?.title && (
|
||||||
{groups.map((group) => (
|
<div className="sideBarHeader">{selectedChartId?.title}</div>
|
||||||
|
)}
|
||||||
|
{selectedChartId &&
|
||||||
|
chartDataGroups[selectedChartId.id]?.map((group) => (
|
||||||
<div key={group.id} className="selectedMain-container">
|
<div key={group.id} className="selectedMain-container">
|
||||||
<div className="selectedMain">
|
{/* <div className="selectedMain">
|
||||||
<span className="bulletPoint">•</span>
|
<span className="bulletPoint">•</span>
|
||||||
<main>Data from</main>
|
<main>Data from</main>
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
|
@ -103,28 +92,34 @@ const Data = () => {
|
||||||
"Connecter 4",
|
"Connecter 4",
|
||||||
]}
|
]}
|
||||||
onSelect={(easing) => {
|
onSelect={(easing) => {
|
||||||
setGroups(
|
setChartDataGroups((prev) => ({
|
||||||
groups.map((g) => (g.id === group.id ? { ...g, easing } : g))
|
...prev,
|
||||||
);
|
[selectedChartId.id]: prev[selectedChartId.id].map((g) =>
|
||||||
|
g.id === group.id ? { ...g, easing } : g
|
||||||
|
),
|
||||||
|
}));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div> */}
|
||||||
|
{/* Render children only if there is a selected chart */}
|
||||||
{group.children.map((child) => (
|
{group.children.map((child) => (
|
||||||
<div key={child.id} className="selectedMain child">
|
<div key={child.id} className="selectedMain child">
|
||||||
<main>Input {child.id}</main>
|
<main>Input</main>
|
||||||
{/* Pass the current easing as the header */}
|
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={child.easing}
|
header={child.easing}
|
||||||
options={["Linear", "Ease In", "Ease Out", "Ease In-Out"]}
|
options={["Linear", "Ease In", "Ease Out", "Ease In-Out"]}
|
||||||
onSelect={(easing) => {
|
onSelect={(easing) => {
|
||||||
setGroups(
|
setChartDataGroups((prev) => ({
|
||||||
groups.map((g) => ({
|
...prev,
|
||||||
|
[selectedChartId.id]: prev[selectedChartId.id].map(
|
||||||
|
(g) => ({
|
||||||
...g,
|
...g,
|
||||||
children: g.children.map((c) =>
|
children: g.children.map((c) =>
|
||||||
c.id === child.id ? { ...c, easing } : c
|
c.id === child.id ? { ...c, easing } : c
|
||||||
),
|
),
|
||||||
}))
|
})
|
||||||
);
|
),
|
||||||
|
}));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="icon" onClick={() => handleLinkClick(child.id)}>
|
<div className="icon" onClick={() => handleLinkClick(child.id)}>
|
||||||
|
|
|
@ -1,22 +1,28 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import RegularDropDown from "../../inputs/regularDropDown";
|
import RegularDropDown from "../../inputs/regularDropDown";
|
||||||
import { useWidgetStore } from "../../../../store/store";
|
import { useWidgetStore } from "../../../../store/store";
|
||||||
import styles from "./Design.module.scss"; // Import SCSS file
|
|
||||||
import ChartComponent from "./chartComponent";
|
import ChartComponent from "./chartComponent";
|
||||||
|
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
// Define Props Interface
|
||||||
|
interface DesignProps {}
|
||||||
// Define the Widget interface
|
|
||||||
interface Widget {
|
interface Widget {
|
||||||
id: string;
|
id: string;
|
||||||
type: string; // Change this if the type is more specific
|
type: string; // Chart type (e.g., "bar", "line")
|
||||||
panel: Side; // You should define or import 'Side' type if not already defined
|
panel: "top" | "bottom" | "left" | "right"; // Panel location
|
||||||
title: string;
|
title: string;
|
||||||
fontFamily?: string;
|
fontFamily?: string;
|
||||||
fontSize?: string;
|
fontSize?: string;
|
||||||
fontWeight?: string;
|
fontWeight?: string;
|
||||||
|
data: {
|
||||||
|
labels: string[];
|
||||||
|
datasets: {
|
||||||
|
data: number[];
|
||||||
|
backgroundColor: string;
|
||||||
|
borderColor: string;
|
||||||
|
borderWidth: number;
|
||||||
|
}[];
|
||||||
|
}; // Data for the chart
|
||||||
}
|
}
|
||||||
|
|
||||||
const Design = () => {
|
const Design = () => {
|
||||||
const [selectedName, setSelectedName] = useState("drop down");
|
const [selectedName, setSelectedName] = useState("drop down");
|
||||||
const [selectedElement, setSelectedElement] = useState("drop down");
|
const [selectedElement, setSelectedElement] = useState("drop down");
|
||||||
|
@ -24,66 +30,70 @@ const Design = () => {
|
||||||
const [selectedSize, setSelectedSize] = useState("drop down");
|
const [selectedSize, setSelectedSize] = useState("drop down");
|
||||||
const [selectedWeight, setSelectedWeight] = useState("drop down");
|
const [selectedWeight, setSelectedWeight] = useState("drop down");
|
||||||
|
|
||||||
|
// Zustand Store Hooks
|
||||||
const { selectedChartId, setSelectedChartId, widgets, setWidgets } =
|
const { selectedChartId, setSelectedChartId, widgets, setWidgets } =
|
||||||
useWidgetStore(); // Get selected chart ID and list of widgets
|
useWidgetStore();
|
||||||
|
|
||||||
// Find the selected widget based on `selectedChartId`
|
// Log Selected Chart ID for Debugging
|
||||||
const selectedWidget = selectedChartId
|
|
||||||
? widgets.find((widget) => widget.id === selectedChartId.id)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// Function to update the selected widget
|
// Handle Widget Updates
|
||||||
const handleUpdateWidget = (updatedProperties: Partial<Widget>) => {
|
const handleUpdateWidget = (updatedProperties: Partial<Widget>) => {
|
||||||
if (!selectedWidget) {
|
if (!selectedChartId) return;
|
||||||
return;
|
|
||||||
}
|
// Update the selectedChartId
|
||||||
|
const updatedChartId = {
|
||||||
|
...selectedChartId,
|
||||||
|
...updatedProperties,
|
||||||
|
};
|
||||||
|
setSelectedChartId(updatedChartId);
|
||||||
|
|
||||||
// Update the widgets array
|
// Update the widgets array
|
||||||
const updatedWidgets = widgets.map((widget) =>
|
const updatedWidgets = widgets.map((widget) =>
|
||||||
widget.id === selectedWidget.id
|
widget.id === selectedChartId.id
|
||||||
? { ...widget, ...updatedProperties } // Merge existing widget with updated properties
|
? { ...widget, ...updatedProperties }
|
||||||
: widget
|
: widget
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update the global state with the new widgets array
|
|
||||||
setWidgets(updatedWidgets);
|
setWidgets(updatedWidgets);
|
||||||
|
|
||||||
// Update `selectedChartId` to reflect the changes
|
|
||||||
if (selectedChartId) {
|
|
||||||
const updatedChartId = {
|
|
||||||
...selectedChartId,
|
|
||||||
...updatedProperties, // Merge updated properties into `selectedChartId`
|
|
||||||
};
|
|
||||||
setSelectedChartId(updatedChartId);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
// Default Chart Data
|
||||||
// Log the current state of widgets for debugging
|
const defaultChartData = {
|
||||||
}, [widgets]);
|
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
data: [65, 59, 80, 81, 56, 55, 40],
|
||||||
|
backgroundColor: "#5c87df",
|
||||||
|
borderColor: "#ffffff",
|
||||||
|
borderWidth: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="design">
|
<div className="design">
|
||||||
{/* Display the selected widget's title */}
|
{/* Title of the Selected Widget */}
|
||||||
<div className="selectedWidget">
|
<div className="selectedWidget">
|
||||||
{selectedWidget ? selectedWidget.title : "Widget 1"}
|
{selectedChartId?.title || "Widget 1"}
|
||||||
</div>
|
|
||||||
<div className="reviewChart">
|
|
||||||
{/* Pass selectedWidget properties to ChartComponent */}
|
|
||||||
{selectedWidget && (
|
|
||||||
<ChartComponent
|
|
||||||
type={selectedWidget.type}
|
|
||||||
title={selectedWidget.title}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Design Options */}
|
{/* 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">
|
<div className="optionsContainer">
|
||||||
|
{/* Name Dropdown */}
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<span>Name</span>
|
<span>Name</span>
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={selectedWidget ? selectedWidget.title : "Select Name"}
|
header={selectedChartId?.title || "Select Name"}
|
||||||
options={["Option 1", "Option 2", "Option 3"]}
|
options={["Option 1", "Option 2", "Option 3"]}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
setSelectedName(value);
|
setSelectedName(value);
|
||||||
|
@ -92,22 +102,24 @@ const Design = () => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Element Dropdown */}
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<span>Element</span>
|
<span>Element</span>
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={selectedElement}
|
header={selectedChartId?.type || "Select Element"}
|
||||||
options={["Option 1", "Option 2", "Option 3"]}
|
options={["bar", "line", "pie", "doughnut", "radar", "polarArea"]} // Valid chart types
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
setSelectedElement(value);
|
setSelectedElement(value);
|
||||||
handleUpdateWidget({ type: value }); // Update element type
|
handleUpdateWidget({ type: value });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Font Family Dropdown */}
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<span>Font Family</span>
|
<span>Font Family</span>
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={selectedFont}
|
header={selectedChartId?.fontFamily || "Select Font"}
|
||||||
options={["Arial", "Roboto", "Sans-serif"]}
|
options={["Arial", "Roboto", "Sans-serif"]}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
setSelectedFont(value);
|
setSelectedFont(value);
|
||||||
|
@ -116,10 +128,11 @@ const Design = () => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Size Dropdown */}
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<span>Size</span>
|
<span>Size</span>
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={selectedSize}
|
header={selectedChartId?.fontSize || "Select Size"}
|
||||||
options={["12px", "14px", "16px", "18px"]}
|
options={["12px", "14px", "16px", "18px"]}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
setSelectedSize(value);
|
setSelectedSize(value);
|
||||||
|
@ -128,10 +141,11 @@ const Design = () => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Weight Dropdown */}
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<span>Weight</span>
|
<span>Weight</span>
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={selectedWeight}
|
header={selectedChartId?.fontWeight || "Select Weight"}
|
||||||
options={["Light", "Regular", "Bold"]}
|
options={["Light", "Regular", "Bold"]}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
setSelectedWeight(value);
|
setSelectedWeight(value);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useEffect, useRef } from "react";
|
import React, { useState } from "react";
|
||||||
import { useThemeStore, useWidgetStore } from "../../../../store/store";
|
import { useThemeStore, useWidgetStore } from "../../../../store/store";
|
||||||
import { ChartType } from "chart.js/auto";
|
import { ChartType } from "chart.js/auto";
|
||||||
import ChartComponent from "./chartComponent";
|
import ChartComponent from "./chartComponent";
|
||||||
|
@ -7,7 +7,6 @@ import {
|
||||||
SearchIcon,
|
SearchIcon,
|
||||||
ThemeIcon,
|
ThemeIcon,
|
||||||
} from "../../../../assets/images/svgExports";
|
} from "../../../../assets/images/svgExports";
|
||||||
import RegularDropDown from "../../inputs/regularDropDown";
|
|
||||||
|
|
||||||
const Widgets = () => {
|
const Widgets = () => {
|
||||||
const chartTypes: ChartType[] = [
|
const chartTypes: ChartType[] = [
|
||||||
|
@ -18,63 +17,14 @@ const Widgets = () => {
|
||||||
"radar",
|
"radar",
|
||||||
"polarArea",
|
"polarArea",
|
||||||
];
|
];
|
||||||
|
|
||||||
const { setDraggedAsset } = useWidgetStore((state) => state);
|
const { setDraggedAsset } = useWidgetStore((state) => state);
|
||||||
const [selectedValue, setSelectedValue] = useState<string | null>(null);
|
|
||||||
const [viewMode, setViewMode] = useState<"2D" | "3D" | "Floating">("2D");
|
const [viewMode, setViewMode] = useState<"2D" | "3D" | "Floating">("2D");
|
||||||
|
|
||||||
const switchView = (mode: "2D" | "3D" | "Floating") => {
|
const switchView = (mode: "2D" | "3D" | "Floating") => {
|
||||||
setViewMode(mode);
|
setViewMode(mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
const { themeColor, setThemeColor } = useThemeStore();
|
|
||||||
const [theme, setTheme] = useState<boolean>(false); // Default is false
|
|
||||||
const [activePresetIndex, setActivePresetIndex] = useState<number | null>(
|
|
||||||
null
|
|
||||||
);
|
|
||||||
const [customColor, setCustomColor] = useState<string>("#000000");
|
|
||||||
|
|
||||||
const themeContainerRef = useRef<HTMLDivElement | null>(null);
|
|
||||||
|
|
||||||
const preset = [
|
|
||||||
["#6F42C1", "#EEEEFE", "#B392F0"],
|
|
||||||
["#F8CB47", "#F79002", "#F73F65"],
|
|
||||||
["#FDA4B8", "#FF6A90", "#B91348"],
|
|
||||||
["#D1BCF6", "#987BEB", "#6443C9"],
|
|
||||||
["#FDC64B", "#EF9407", "#B54300"],
|
|
||||||
["#69E9AB", "#0BB96E", "#087348"],
|
|
||||||
["#85ADFC", "#246FFE", "#0050EB"],
|
|
||||||
["#F570C7", "#27CEF7", "#FFAD1A"],
|
|
||||||
["#6572F2", "#EE42B7", "#12B56E"],
|
|
||||||
["#10BA68", "#FDB022", "#EA48B5"],
|
|
||||||
["#10BA68", "#FDB022", "#EA48B5"],
|
|
||||||
["#6F42C1", "#CEB2F6", "#EA48B5"],
|
|
||||||
];
|
|
||||||
|
|
||||||
// Close theme container on outside click
|
|
||||||
useEffect(() => {
|
|
||||||
const themBtn = document.querySelector(".theme-switch");
|
|
||||||
|
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
|
||||||
// Check if the click is outside the theme container or theme button
|
|
||||||
if (
|
|
||||||
themeContainerRef.current &&
|
|
||||||
!themeContainerRef.current.contains(event.target as Node) &&
|
|
||||||
!themBtn?.contains(event.target as Node) // Ensure that the click is not inside the theme button
|
|
||||||
) {
|
|
||||||
setTheme(false); // Close the theme container when clicking outside
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener("mousedown", handleClickOutside);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener("mousedown", handleClickOutside); // Cleanup event listener on unmount
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {}, [theme]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="widgets-layout">
|
<div className="widgets-layout">
|
||||||
{/* Search Container */}
|
{/* Search Container */}
|
||||||
|
@ -87,7 +37,6 @@ const Widgets = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Options and Theme Management */}
|
{/* Options and Theme Management */}
|
||||||
<div className="ui-wrapper">
|
<div className="ui-wrapper">
|
||||||
<div className="options">
|
<div className="options">
|
||||||
|
@ -110,68 +59,24 @@ const Widgets = () => {
|
||||||
Floating
|
Floating
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Theme Switcher */}
|
|
||||||
<div
|
|
||||||
className="theme-switch"
|
|
||||||
onClick={() => setTheme(!theme)} // Toggle the theme container
|
|
||||||
>
|
|
||||||
<button className="theme-button">
|
|
||||||
<ThemeIcon />
|
|
||||||
<DropDownIcon />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Theme Presets */}
|
|
||||||
{theme && (
|
|
||||||
<div className="theme-container" ref={themeContainerRef}>
|
|
||||||
<h2>Presets</h2>
|
|
||||||
<div className="theme-preset-wrapper">
|
|
||||||
{preset.map((colors, index) => (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
className={`theme-preset ${
|
|
||||||
activePresetIndex === index ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => {
|
|
||||||
setThemeColor(colors);
|
|
||||||
setActivePresetIndex(index);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{colors.map((color, i) => (
|
|
||||||
<div
|
|
||||||
key={i}
|
|
||||||
className="color"
|
|
||||||
style={{ background: color }}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div className="custom-color">
|
|
||||||
<h3>Custom Color</h3>
|
|
||||||
<div className="color-displayer">
|
|
||||||
<input
|
|
||||||
type="color"
|
|
||||||
value={customColor}
|
|
||||||
onChange={(e) => {
|
|
||||||
const newColor = e.target.value;
|
|
||||||
setCustomColor(newColor);
|
|
||||||
setThemeColor([newColor, newColor, newColor]);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{customColor}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Chart Widgets */}
|
{/* Chart Widgets */}
|
||||||
<div className="chart-container">
|
<div className="chart-container">
|
||||||
{chartTypes.map((type, index) => {
|
{chartTypes.map((type, index) => {
|
||||||
const widgetTitle = `Widget ${index + 1}`;
|
const widgetTitle = `Widget ${index + 1}`;
|
||||||
|
const sampleData = {
|
||||||
|
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
data: [65, 59, 80, 81, 56, 55, 40],
|
||||||
|
backgroundColor: "#5c87df",
|
||||||
|
borderColor: "#ffffff",
|
||||||
|
borderWidth: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
|
@ -182,17 +87,110 @@ const Widgets = () => {
|
||||||
type,
|
type,
|
||||||
id: `widget-${index + 1}`,
|
id: `widget-${index + 1}`,
|
||||||
title: widgetTitle,
|
title: widgetTitle,
|
||||||
|
panel: "top", // Default panel assignment
|
||||||
|
data: sampleData, // Include data in the dragged asset
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onDragEnd={() => setDraggedAsset(null)}
|
onDragEnd={() => setDraggedAsset(null)}
|
||||||
>
|
>
|
||||||
<ChartComponent type={type} title={widgetTitle} />
|
<ChartComponent
|
||||||
|
type={type}
|
||||||
|
title={widgetTitle}
|
||||||
|
data={sampleData}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
<div
|
||||||
|
className="chart progressBar"
|
||||||
|
draggable
|
||||||
|
onDragStart={(e) => {
|
||||||
|
setDraggedAsset({
|
||||||
|
type: "progress", // New widget type
|
||||||
|
id: `widget-7`,
|
||||||
|
title: "Widget 7",
|
||||||
|
panel: "top",
|
||||||
|
data: {
|
||||||
|
stocks: [
|
||||||
|
{
|
||||||
|
key: "units",
|
||||||
|
value: 1000,
|
||||||
|
description: "Initial stock",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onDragEnd={() => setDraggedAsset(null)}
|
||||||
|
>
|
||||||
|
{" "}
|
||||||
|
<div className="header">Widget 7</div>
|
||||||
|
<div className="stock">
|
||||||
|
<span className="stock-item">
|
||||||
|
<span className="stockValues">
|
||||||
|
<div className="key">units</div>
|
||||||
|
<div className="value">1000</div>
|
||||||
|
</span>
|
||||||
|
<div className="stock-description">Initial stock</div>
|
||||||
|
</span>
|
||||||
|
<div className="icon">Icon</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="chart progressBar"
|
||||||
|
draggable
|
||||||
|
onDragStart={(e) => {
|
||||||
|
setDraggedAsset({
|
||||||
|
type: "progress",
|
||||||
|
id: `widget-8`,
|
||||||
|
title: "Widget 8",
|
||||||
|
panel: "top",
|
||||||
|
data: {
|
||||||
|
stocks: [
|
||||||
|
{
|
||||||
|
key: "units",
|
||||||
|
value: 1000,
|
||||||
|
description: "Initial stock",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "units",
|
||||||
|
value: 500,
|
||||||
|
description: "Additional stock",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onDragEnd={() => setDraggedAsset(null)}
|
||||||
|
>
|
||||||
|
{" "}
|
||||||
|
<div className="header">Widget 8</div>
|
||||||
|
<div className="stock">
|
||||||
|
<span className="stock-item">
|
||||||
|
<span className="stockValues">
|
||||||
|
<div className="key">units</div>
|
||||||
|
<div className="value">1000</div>
|
||||||
|
</span>
|
||||||
|
<div className="stock-description">Initial stock</div>
|
||||||
|
</span>
|
||||||
|
<div className="icon">Icon</div>
|
||||||
|
</div>
|
||||||
|
<div className="stock">
|
||||||
|
<span className="stock-item">
|
||||||
|
<span className="stockValues">
|
||||||
|
<div className="key">units</div>
|
||||||
|
<div className="value">1000</div>
|
||||||
|
</span>
|
||||||
|
<div className="stock-description">Initial stock</div>
|
||||||
|
</span>
|
||||||
|
<div className="icon">Icon</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Widgets;
|
export default Widgets;
|
||||||
|
|
||||||
|
// along with my charts i need to additionallly drag and drop my 2 widget 7 and widget 8 styled card to pannel
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export const ProgressCard = ({ title, data }: {
|
||||||
|
title: string;
|
||||||
|
data: { stocks: Array<{ key: string; value: number; description: string }> };
|
||||||
|
}) => (
|
||||||
|
<div className="chart progressBar">
|
||||||
|
<div className="header">{title}</div>
|
||||||
|
{data.stocks.map((stock, index) => (
|
||||||
|
<div key={index} className="stock">
|
||||||
|
<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">Icon</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useMemo, useState, useEffect, useRef } from "react";
|
||||||
import {
|
import {
|
||||||
DndContext,
|
DndContext,
|
||||||
closestCenter,
|
closestCenter,
|
||||||
|
@ -9,20 +9,20 @@ import {
|
||||||
} from "@dnd-kit/core";
|
} from "@dnd-kit/core";
|
||||||
import {
|
import {
|
||||||
SortableContext,
|
SortableContext,
|
||||||
useSortable,
|
|
||||||
verticalListSortingStrategy,
|
verticalListSortingStrategy,
|
||||||
arrayMove,
|
arrayMove,
|
||||||
|
useSortable,
|
||||||
} from "@dnd-kit/sortable";
|
} from "@dnd-kit/sortable";
|
||||||
|
import { useWidgetStore } from "../../store/store";
|
||||||
import { useWidgetStore } from "../../store/store"; // Assuming you have this store
|
import ChartComponent from "../../components/ui/sideBar/realTimeViz/chartComponent";
|
||||||
import ChartComponent from "../../components/ui/sideBar/realTimeViz/chartComponent"; // Assuming this exists
|
import SideBar from "../../components/layout/sideBar";
|
||||||
import SideBar from "../../components/layout/sideBar"; // Assuming this exists
|
|
||||||
import {
|
import {
|
||||||
CleanPannel,
|
CleanPannel,
|
||||||
DisableSorting,
|
DisableSorting,
|
||||||
EyeIcon,
|
EyeIcon,
|
||||||
LockIcon,
|
LockIcon,
|
||||||
} from "../../assets/images/svgExports"; // Assuming these are your icon components
|
} from "../../assets/images/svgExports";
|
||||||
|
import { ProgressCard } from "./progressCard ";
|
||||||
|
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
|
|
||||||
|
@ -38,15 +38,17 @@ const DraggableWidget = ({ widget }: { widget: any }) => {
|
||||||
transition,
|
transition,
|
||||||
isDragging,
|
isDragging,
|
||||||
} = useSortable({ id: widget.id });
|
} = useSortable({ id: widget.id });
|
||||||
|
const { setSelectedChartId } = useWidgetStore();
|
||||||
|
|
||||||
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
const style = useMemo(
|
||||||
|
() => ({
|
||||||
const style = {
|
|
||||||
transform: transform
|
transform: transform
|
||||||
? `translate3d(${transform.x}px, ${transform.y}px, 0)`
|
? `translate3d(${transform.x}px, ${transform.y}px, 0)`
|
||||||
: undefined,
|
: undefined,
|
||||||
transition: transition || "transform 200ms ease",
|
transition: transition || "transform 200ms ease",
|
||||||
};
|
}),
|
||||||
|
[transform, transition]
|
||||||
|
);
|
||||||
|
|
||||||
const handlePointerDown = () => {
|
const handlePointerDown = () => {
|
||||||
if (!isDragging) {
|
if (!isDragging) {
|
||||||
|
@ -64,75 +66,154 @@ const DraggableWidget = ({ widget }: { widget: any }) => {
|
||||||
style={style}
|
style={style}
|
||||||
onPointerDown={handlePointerDown}
|
onPointerDown={handlePointerDown}
|
||||||
>
|
>
|
||||||
|
{widget.type === "progress" ? (
|
||||||
|
<ProgressCard title={widget.title} data={widget.data} />
|
||||||
|
) : (
|
||||||
<ChartComponent
|
<ChartComponent
|
||||||
type={widget.type}
|
type={widget.type}
|
||||||
title={widget.title}
|
title={widget.title}
|
||||||
fontFamily={widget.fontFamily}
|
fontFamily={widget.fontFamily}
|
||||||
fontSize={widget.fontSize}
|
fontSize={widget.fontSize}
|
||||||
fontWeight={widget.fontWeight}
|
fontWeight={widget.fontWeight}
|
||||||
|
data={widget.data}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const RealTimeVisualization = () => {
|
const RealTimeVisualization = () => {
|
||||||
const [zone, setZone] = useState([
|
const [selectedZone, setSelectedZone] = useState("Manufacturing unit");
|
||||||
"Manufacturing unit",
|
const [panelDimensions, setPanelDimensions] = useState<{
|
||||||
"Assembly unit",
|
[side in Side]?: { width: number; height: number };
|
||||||
"Packing unit",
|
|
||||||
"Warehouse",
|
|
||||||
"Inventory",
|
|
||||||
]);
|
|
||||||
|
|
||||||
const [activeSides, setActiveSides] = useState<Side[]>([]);
|
|
||||||
const [panelOrder, setPanelOrder] = useState<Side[]>([]);
|
|
||||||
const [selectedSide, setSelectedSide] = useState<Side | null>(null);
|
|
||||||
const [lockedPanels, setLockedPanels] = useState<Side[]>([]);
|
|
||||||
const [activeExtraButton, setActiveExtraButton] = useState<{
|
|
||||||
[key in Side]?: string;
|
|
||||||
}>({});
|
}>({});
|
||||||
const { draggedAsset, addWidget, widgets, setWidgets } = useWidgetStore();
|
const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({});
|
||||||
|
|
||||||
|
const [zonesData, setZonesData] = useState<{
|
||||||
|
[key: string]: {
|
||||||
|
activeSides: Side[];
|
||||||
|
panelOrder: Side[];
|
||||||
|
lockedPanels: Side[];
|
||||||
|
widgets: {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
title: string;
|
||||||
|
panel: Side;
|
||||||
|
data: any;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}>({
|
||||||
|
"Manufacturing unit": {
|
||||||
|
activeSides: [],
|
||||||
|
panelOrder: [],
|
||||||
|
lockedPanels: [],
|
||||||
|
widgets: [],
|
||||||
|
},
|
||||||
|
"Assembly unit": {
|
||||||
|
activeSides: [],
|
||||||
|
panelOrder: [],
|
||||||
|
lockedPanels: [],
|
||||||
|
widgets: [],
|
||||||
|
},
|
||||||
|
"Packing unit": {
|
||||||
|
activeSides: [],
|
||||||
|
panelOrder: [],
|
||||||
|
lockedPanels: [],
|
||||||
|
widgets: [],
|
||||||
|
},
|
||||||
|
Warehouse: {
|
||||||
|
activeSides: [],
|
||||||
|
panelOrder: [],
|
||||||
|
lockedPanels: [],
|
||||||
|
widgets: [],
|
||||||
|
},
|
||||||
|
Inventory: {
|
||||||
|
activeSides: [],
|
||||||
|
panelOrder: [],
|
||||||
|
lockedPanels: [],
|
||||||
|
widgets: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {}, [zonesData]);
|
||||||
|
|
||||||
const sensors = useSensors(
|
const sensors = useSensors(
|
||||||
useSensor(PointerSensor),
|
useSensor(PointerSensor),
|
||||||
useSensor(KeyboardSensor)
|
useSensor(KeyboardSensor)
|
||||||
);
|
);
|
||||||
|
|
||||||
const toggleSide = (side: Side) => {
|
useEffect(() => {
|
||||||
setActiveSides((prev) => {
|
const observers: ResizeObserver[] = [];
|
||||||
const newActive = prev.includes(side)
|
const currentPanelRefs = panelRefs.current;
|
||||||
? prev.filter((s) => s !== side)
|
|
||||||
: [...prev, side];
|
|
||||||
setPanelOrder(newActive);
|
|
||||||
|
|
||||||
if (prev.includes(side)) {
|
zonesData[selectedZone].activeSides.forEach((side) => {
|
||||||
setSelectedSide(null);
|
const element = currentPanelRefs[side];
|
||||||
} else {
|
if (element) {
|
||||||
setSelectedSide(side);
|
const observer = new ResizeObserver((entries) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
const { width, height } = entry.contentRect;
|
||||||
|
setPanelDimensions((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[side]: { width, height },
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
observer.observe(element);
|
||||||
|
observers.push(observer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return newActive;
|
return () => {
|
||||||
|
observers.forEach((observer) => observer.disconnect());
|
||||||
|
};
|
||||||
|
}, [zonesData[selectedZone].activeSides, selectedZone]);
|
||||||
|
|
||||||
|
const toggleSide = (side: Side) => {
|
||||||
|
setZonesData((prev) => {
|
||||||
|
const zoneData = prev[selectedZone];
|
||||||
|
const newActiveSides = zoneData.activeSides.includes(side)
|
||||||
|
? zoneData.activeSides.filter((s) => s !== side)
|
||||||
|
: [...zoneData.activeSides, side];
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[selectedZone]: {
|
||||||
|
...zoneData,
|
||||||
|
activeSides: newActiveSides,
|
||||||
|
panelOrder: newActiveSides,
|
||||||
|
},
|
||||||
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleLockPanel = (side: Side) => {
|
const toggleLockPanel = (side: Side) => {
|
||||||
setLockedPanels((prev) =>
|
setZonesData((prev) => {
|
||||||
prev.includes(side)
|
const zoneData = prev[selectedZone];
|
||||||
? prev.filter((panel) => panel !== side)
|
const newLockedPanels = zoneData.lockedPanels.includes(side)
|
||||||
: [...prev, side]
|
? zoneData.lockedPanels.filter((panel) => panel !== side)
|
||||||
);
|
: [...zoneData.lockedPanels, side];
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[selectedZone]: {
|
||||||
|
...zoneData,
|
||||||
|
lockedPanels: newLockedPanels,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPanelStyle = (currentSide: Side) => {
|
const getPanelStyle = useMemo(
|
||||||
const currentIndex = panelOrder.indexOf(currentSide);
|
() => (side: Side) => {
|
||||||
const previousPanels = panelOrder.slice(0, currentIndex);
|
const currentIndex = zonesData[selectedZone].panelOrder.indexOf(side);
|
||||||
|
const previousPanels = zonesData[selectedZone].panelOrder.slice(
|
||||||
|
0,
|
||||||
|
currentIndex
|
||||||
|
);
|
||||||
const leftActive = previousPanels.includes("left");
|
const leftActive = previousPanels.includes("left");
|
||||||
const rightActive = previousPanels.includes("right");
|
const rightActive = previousPanels.includes("right");
|
||||||
const topActive = previousPanels.includes("top");
|
const topActive = previousPanels.includes("top");
|
||||||
const bottomActive = previousPanels.includes("bottom");
|
const bottomActive = previousPanels.includes("bottom");
|
||||||
|
|
||||||
switch (currentSide) {
|
switch (side) {
|
||||||
case "top":
|
case "top":
|
||||||
case "bottom":
|
case "bottom":
|
||||||
return {
|
return {
|
||||||
|
@ -141,10 +222,9 @@ const RealTimeVisualization = () => {
|
||||||
}px)`,
|
}px)`,
|
||||||
left: leftActive ? "204px" : "0",
|
left: leftActive ? "204px" : "0",
|
||||||
right: rightActive ? "204px" : "0",
|
right: rightActive ? "204px" : "0",
|
||||||
[currentSide]: "0",
|
[side]: "0",
|
||||||
height: "200px",
|
height: "200px",
|
||||||
};
|
};
|
||||||
|
|
||||||
case "left":
|
case "left":
|
||||||
case "right":
|
case "right":
|
||||||
return {
|
return {
|
||||||
|
@ -153,48 +233,109 @@ const RealTimeVisualization = () => {
|
||||||
}px)`,
|
}px)`,
|
||||||
top: topActive ? "204px" : "0",
|
top: topActive ? "204px" : "0",
|
||||||
bottom: bottomActive ? "204px" : "0",
|
bottom: bottomActive ? "204px" : "0",
|
||||||
[currentSide]: "0",
|
[side]: "0",
|
||||||
width: "200px",
|
width: "200px",
|
||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
[zonesData, selectedZone]
|
||||||
|
);
|
||||||
|
|
||||||
const handleDrop = (e: React.DragEvent, panel: Side) => {
|
const handleDrop = (e: React.DragEvent, panel: Side) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
const { draggedAsset } = useWidgetStore.getState();
|
||||||
if (draggedAsset) {
|
if (draggedAsset) {
|
||||||
addWidget({ ...draggedAsset, id: generateUniqueId(), panel });
|
if (zonesData[selectedZone].lockedPanels.includes(panel)) return;
|
||||||
|
|
||||||
|
const currentWidgetsInPanel = zonesData[selectedZone].widgets.filter(
|
||||||
|
(w) => w.panel === panel
|
||||||
|
).length;
|
||||||
|
|
||||||
|
const dimensions = panelDimensions[panel];
|
||||||
|
const CHART_WIDTH = 200; // Width of each chart for top/bottom panels
|
||||||
|
const CHART_HEIGHT = 200; // Height of each chart for left/right panels
|
||||||
|
let maxCharts = 0;
|
||||||
|
|
||||||
|
if (dimensions) {
|
||||||
|
if (panel === "top" || panel === "bottom") {
|
||||||
|
maxCharts = Math.floor(dimensions.width / CHART_WIDTH); // Use width for top/bottom
|
||||||
|
} else {
|
||||||
|
maxCharts = Math.floor(dimensions.height / CHART_HEIGHT); // Use height for left/right
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
maxCharts = panel === "top" || panel === "bottom" ? 5 : 3; // Default values
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentWidgetsInPanel >= maxCharts) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setZonesData((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[selectedZone]: {
|
||||||
|
...prev[selectedZone],
|
||||||
|
widgets: [
|
||||||
|
...prev[selectedZone].widgets,
|
||||||
|
{
|
||||||
|
...draggedAsset,
|
||||||
|
id: generateUniqueId(),
|
||||||
|
panel,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDragEnd = (event: any) => {
|
const handleDragEnd = (event: any) => {
|
||||||
const { active, over } = event;
|
const { active, over } = event;
|
||||||
|
|
||||||
if (!over) return;
|
if (!over) return;
|
||||||
|
|
||||||
const oldIndex = widgets.findIndex((widget) => widget.id === active.id);
|
setZonesData((prev) => {
|
||||||
|
const zoneData = prev[selectedZone];
|
||||||
|
const oldIndex = zoneData.widgets.findIndex(
|
||||||
|
(widget) => widget.id === active.id
|
||||||
|
);
|
||||||
const newPanel =
|
const newPanel =
|
||||||
widgets.find((widget) => widget.id === over.id)?.panel || active.panel;
|
zoneData.widgets.find((widget) => widget.id === over.id)?.panel ||
|
||||||
|
active.panel;
|
||||||
|
|
||||||
if (active.panel === newPanel) {
|
if (active.panel === newPanel) {
|
||||||
const newIndex = widgets.findIndex((widget) => widget.id === over.id);
|
const newIndex = zoneData.widgets.findIndex(
|
||||||
const reorderedWidgets = arrayMove(widgets, oldIndex, newIndex);
|
(widget) => widget.id === over.id
|
||||||
setWidgets(reorderedWidgets);
|
);
|
||||||
|
const reorderedWidgets = arrayMove(
|
||||||
|
zoneData.widgets,
|
||||||
|
oldIndex,
|
||||||
|
newIndex
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[selectedZone]: {
|
||||||
|
...zoneData,
|
||||||
|
widgets: reorderedWidgets,
|
||||||
|
},
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
const updatedWidgets = widgets.map((widget) =>
|
const updatedWidgets = zoneData.widgets.map((widget) =>
|
||||||
widget.id === active.id ? { ...widget, panel: newPanel } : widget
|
widget.id === active.id ? { ...widget, panel: newPanel } : widget
|
||||||
);
|
);
|
||||||
|
|
||||||
const widgetsInNewPanel = updatedWidgets.filter(
|
const widgetsInNewPanel = updatedWidgets.filter(
|
||||||
(w) => w.panel === newPanel
|
(w) => w.panel === newPanel
|
||||||
);
|
);
|
||||||
const newIndex = widgetsInNewPanel.findIndex((w) => w.id === over.id);
|
const newIndex = widgetsInNewPanel.findIndex((w) => w.id === over.id);
|
||||||
|
|
||||||
const reorderedWidgets = arrayMove(updatedWidgets, oldIndex, newIndex);
|
const reorderedWidgets = arrayMove(updatedWidgets, oldIndex, newIndex);
|
||||||
setWidgets(reorderedWidgets);
|
return {
|
||||||
|
...prev,
|
||||||
|
[selectedZone]: {
|
||||||
|
...zoneData,
|
||||||
|
widgets: reorderedWidgets,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -208,11 +349,20 @@ const RealTimeVisualization = () => {
|
||||||
header={["Overview", "Widgets", "Templates"]}
|
header={["Overview", "Widgets", "Templates"]}
|
||||||
defaultActive={"Widgets"}
|
defaultActive={"Widgets"}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="main-container relative">
|
<div className="main-container relative">
|
||||||
<div className="zoon-wrapper">
|
<div
|
||||||
{zone.map((zone, index) => (
|
className={`zoon-wrapper ${
|
||||||
<div className="zone">{zone}</div>
|
zonesData[selectedZone].activeSides.includes("bottom") && "bottom"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{Object.keys(zonesData).map((zone, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={`zone ${selectedZone === zone && "active"}`}
|
||||||
|
onClick={() => setSelectedZone(zone)}
|
||||||
|
>
|
||||||
|
{zone}
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{(["top", "right", "bottom", "left"] as Side[]).map((side) => (
|
{(["top", "right", "bottom", "left"] as Side[]).map((side) => (
|
||||||
|
@ -224,100 +374,100 @@ const RealTimeVisualization = () => {
|
||||||
>
|
>
|
||||||
+
|
+
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="extra-buttons"
|
className="extra-buttons"
|
||||||
style={{
|
style={{
|
||||||
display: activeSides.includes(side) ? "flex" : "none",
|
display: zonesData[selectedZone].activeSides.includes(side)
|
||||||
|
? "flex"
|
||||||
|
: "none",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`icon ${
|
className={`icon ${
|
||||||
activeExtraButton[side] === "Disable Sorting"
|
zonesData[selectedZone].lockedPanels.includes(side)
|
||||||
? "active"
|
? "active"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
title="Disable Sorting"
|
title="Disable Sorting"
|
||||||
onClick={() =>
|
onClick={() => toggleLockPanel(side)}
|
||||||
setActiveExtraButton((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[side]: "Disable Sorting",
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<DisableSorting />
|
<DisableSorting />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`icon ${
|
className={`icon ${
|
||||||
activeExtraButton[side] === "Hide Panel" ? "active" : ""
|
zonesData[selectedZone].lockedPanels.includes(side)
|
||||||
|
? "active"
|
||||||
|
: ""
|
||||||
}`}
|
}`}
|
||||||
title="Hide Panel"
|
title="Hide Panel"
|
||||||
onClick={() =>
|
onClick={() => toggleLockPanel(side)}
|
||||||
setActiveExtraButton((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[side]: "Hide Panel",
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<EyeIcon />
|
<EyeIcon />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`icon ${
|
className={`icon ${
|
||||||
activeExtraButton[side] === "Clean Panel" ? "active" : ""
|
zonesData[selectedZone].lockedPanels.includes(side)
|
||||||
|
? "active"
|
||||||
|
: ""
|
||||||
}`}
|
}`}
|
||||||
title="Clean Panel"
|
title="Clean Panel"
|
||||||
onClick={() =>
|
onClick={() => toggleLockPanel(side)}
|
||||||
setActiveExtraButton((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[side]: "Clean Panel",
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<CleanPannel />
|
<CleanPannel />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`icon ${
|
className={`icon ${
|
||||||
activeExtraButton[side] === "Lock Panel" ? "active" : ""
|
zonesData[selectedZone].lockedPanels.includes(side)
|
||||||
|
? "active"
|
||||||
|
: ""
|
||||||
}`}
|
}`}
|
||||||
title={
|
title={
|
||||||
lockedPanels.includes(side) ? "Unlock Panel" : "Lock Panel"
|
zonesData[selectedZone].lockedPanels.includes(side)
|
||||||
|
? "Unlock Panel"
|
||||||
|
: "Lock Panel"
|
||||||
}
|
}
|
||||||
onClick={() => {
|
onClick={() => toggleLockPanel(side)}
|
||||||
toggleLockPanel(side);
|
|
||||||
setActiveExtraButton((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[side]: "Lock Panel",
|
|
||||||
}));
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<LockIcon />
|
<LockIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
{zonesData[selectedZone].activeSides.map((side) => (
|
||||||
{activeSides.map((side) => (
|
|
||||||
<div
|
<div
|
||||||
key={side}
|
key={side}
|
||||||
className={`panel ${side}-panel absolute`}
|
className={`panel ${side}-panel absolute`}
|
||||||
style={getPanelStyle(side)}
|
style={getPanelStyle(side)} // Pass `side` to `getPanelStyle`
|
||||||
onDrop={(e) => handleDrop(e, side)}
|
onDrop={(e) => handleDrop(e, side)}
|
||||||
onDragOver={(e) => e.preventDefault()}
|
onDragOver={(e) => e.preventDefault()}
|
||||||
|
ref={(el) => {
|
||||||
|
if (el) {
|
||||||
|
panelRefs.current[side] = el;
|
||||||
|
} else {
|
||||||
|
delete panelRefs.current[side];
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="panel-content"
|
className="panel-content"
|
||||||
style={{
|
style={{
|
||||||
pointerEvents: lockedPanels.includes(side) ? "none" : "auto",
|
pointerEvents: zonesData[selectedZone].lockedPanels.includes(
|
||||||
opacity: lockedPanels.includes(side) ? "0.8" : "1",
|
side
|
||||||
|
)
|
||||||
|
? "none"
|
||||||
|
: "auto",
|
||||||
|
opacity: zonesData[selectedZone].lockedPanels.includes(side)
|
||||||
|
? "0.8"
|
||||||
|
: "1",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SortableContext
|
<SortableContext
|
||||||
items={widgets
|
items={zonesData[selectedZone].widgets
|
||||||
.filter((w) => w.panel === side)
|
.filter((w) => w.panel === side)
|
||||||
.map((w) => w.id)}
|
.map((w) => w.id)}
|
||||||
strategy={verticalListSortingStrategy}
|
strategy={verticalListSortingStrategy}
|
||||||
>
|
>
|
||||||
{widgets
|
{zonesData[selectedZone].widgets
|
||||||
.filter((w) => w.panel === side)
|
.filter((w) => w.panel === side)
|
||||||
.map((widget) => (
|
.map((widget) => (
|
||||||
<DraggableWidget widget={widget} key={widget.id} />
|
<DraggableWidget widget={widget} key={widget.id} />
|
||||||
|
@ -327,7 +477,6 @@ const RealTimeVisualization = () => {
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SideBar header={["Data", "Design"]} defaultActive={"Data"} />
|
<SideBar header={["Data", "Design"]} defaultActive={"Data"} />
|
||||||
</div>
|
</div>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
|
|
|
@ -275,50 +275,6 @@ export const useDrieUIValue = create<any>((set: any) => ({
|
||||||
|
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
|
|
||||||
// Define Widget interface
|
|
||||||
interface Widget {
|
|
||||||
id: string;
|
|
||||||
type: any;
|
|
||||||
panel: Side;
|
|
||||||
title: string; // Ensure title is a string
|
|
||||||
fontFamily?: string;
|
|
||||||
fontSize?: string;
|
|
||||||
fontWeight?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store interface
|
|
||||||
interface WidgetStore {
|
|
||||||
draggedAsset: { type: any; id: string; title: string } | null;
|
|
||||||
widgets: Widget[];
|
|
||||||
setDraggedAsset: (
|
|
||||||
asset: { type: any; id: string; title: string } | null
|
|
||||||
) => void;
|
|
||||||
addWidget: (widget: Widget) => void;
|
|
||||||
setWidgets: (widgets: Widget[]) => void;
|
|
||||||
selectedChartId: Widget | null; // Change this to store an object of type Widget
|
|
||||||
setSelectedChartId: (widget: Widget | {
|
|
||||||
"type": "line",
|
|
||||||
"id": "1741781992712-ecvq5t61y",
|
|
||||||
"title": "Widget 2",
|
|
||||||
"panel": "left",
|
|
||||||
"fontWeight": "Light",
|
|
||||||
"fontSize": "12px",
|
|
||||||
"fontFamily": "Sans-serif"
|
|
||||||
}) => void; // Update to accept a Widget object
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the store with Zustand
|
|
||||||
export const useWidgetStore = create<WidgetStore>((set) => ({
|
|
||||||
draggedAsset: null,
|
|
||||||
widgets: [],
|
|
||||||
setDraggedAsset: (asset) => set({ draggedAsset: asset }),
|
|
||||||
addWidget: (widget) =>
|
|
||||||
set((state) => ({ widgets: [...state.widgets, widget] })),
|
|
||||||
setWidgets: (widgets) => set({ widgets }),
|
|
||||||
selectedChartId: null,
|
|
||||||
setSelectedChartId: (widget) => set({ selectedChartId: widget }),
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface ThemeState {
|
interface ThemeState {
|
||||||
themeColor: string[]; // This should be an array of strings
|
themeColor: string[]; // This should be an array of strings
|
||||||
setThemeColor: (colors: string[]) => void; // This function will accept an array of strings
|
setThemeColor: (colors: string[]) => void; // This function will accept an array of strings
|
||||||
|
@ -328,3 +284,52 @@ export const useThemeStore = create<ThemeState>((set) => ({
|
||||||
themeColor: ["#5c87df", "#EEEEFE", "#969BA7"],
|
themeColor: ["#5c87df", "#EEEEFE", "#969BA7"],
|
||||||
setThemeColor: (colors) => set({ themeColor: colors }),
|
setThemeColor: (colors) => set({ themeColor: colors }),
|
||||||
}));
|
}));
|
||||||
|
// Define the WidgetStore interface
|
||||||
|
// Define the WidgetStore interface
|
||||||
|
interface Widget {
|
||||||
|
id: string;
|
||||||
|
type: string; // Can be chart type or "progress"
|
||||||
|
panel: "top" | "bottom" | "left" | "right";
|
||||||
|
title: string;
|
||||||
|
fontFamily?: string;
|
||||||
|
fontSize?: string;
|
||||||
|
fontWeight?: string;
|
||||||
|
data: {
|
||||||
|
// Chart data
|
||||||
|
labels?: string[];
|
||||||
|
datasets?: Array<{
|
||||||
|
data: number[];
|
||||||
|
backgroundColor: string;
|
||||||
|
borderColor: string;
|
||||||
|
borderWidth: number;
|
||||||
|
}>;
|
||||||
|
// Progress card data
|
||||||
|
stocks?: Array<{
|
||||||
|
key: string;
|
||||||
|
value: number;
|
||||||
|
description: string;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WidgetStore {
|
||||||
|
draggedAsset: Widget | null; // The currently dragged widget asset
|
||||||
|
widgets: Widget[]; // List of all widgets
|
||||||
|
selectedChartId: Widget | null; // The currently selected chart/widget
|
||||||
|
setDraggedAsset: (asset: Widget | null) => void; // Setter for draggedAsset
|
||||||
|
addWidget: (widget: Widget) => void; // Add a new widget
|
||||||
|
setWidgets: (widgets: Widget[]) => void; // Replace the entire widgets array
|
||||||
|
setSelectedChartId: (widget: Widget | null) => void; // Set the selected chart/widget
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the store with Zustand
|
||||||
|
export const useWidgetStore = create<WidgetStore>((set) => ({
|
||||||
|
draggedAsset: null,
|
||||||
|
widgets: [],
|
||||||
|
selectedChartId: null, // Initialize as null, not as an array
|
||||||
|
setDraggedAsset: (asset) => set({ draggedAsset: asset }),
|
||||||
|
addWidget: (widget) =>
|
||||||
|
set((state) => ({ widgets: [...state.widgets, widget] })),
|
||||||
|
setWidgets: (widgets) => set({ widgets }),
|
||||||
|
setSelectedChartId: (widget) => set({ selectedChartId: widget }),
|
||||||
|
}));
|
||||||
|
|
Loading…
Reference in New Issue