Merge remote-tracking branch 'origin/main' into simulation-agv
This commit is contained in:
commit
69ca2a3121
|
@ -1,5 +1,5 @@
|
||||||
import { Html } from "@react-three/drei";
|
import { Html } from "@react-three/drei";
|
||||||
import React from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { Bar } from "react-chartjs-2";
|
import { Bar } from "react-chartjs-2";
|
||||||
import {
|
import {
|
||||||
Chart as ChartJS,
|
Chart as ChartJS,
|
||||||
|
@ -11,6 +11,11 @@ import {
|
||||||
Legend,
|
Legend,
|
||||||
TooltipItem, // Import TooltipItem for typing
|
TooltipItem, // Import TooltipItem for typing
|
||||||
} from "chart.js";
|
} from "chart.js";
|
||||||
|
import { ThroughputIcon } from "../../../icons/3dChartIcons";
|
||||||
|
import { useWidgetStore } from "../../../../store/useWidgetStore";
|
||||||
|
import useChartStore from "../../../../store/useChartStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import io from "socket.io-client";
|
||||||
|
|
||||||
// Register ChartJS components
|
// Register ChartJS components
|
||||||
ChartJS.register(
|
ChartJS.register(
|
||||||
|
@ -22,12 +27,28 @@ ChartJS.register(
|
||||||
Legend
|
Legend
|
||||||
);
|
);
|
||||||
interface ProductionCapacityProps {
|
interface ProductionCapacityProps {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductionCapacity : React.FC<ProductionCapacityProps> = ({ position }) => {
|
const ProductionCapacity : React.FC<ProductionCapacityProps> = ({ id, type, position }) => {
|
||||||
|
|
||||||
|
const { selectedChartId,setSelectedChartId } = useWidgetStore();
|
||||||
|
|
||||||
|
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||||
|
const [measurements, setmeasurements] = useState<any>({});
|
||||||
|
const [duration, setDuration] = useState("1h")
|
||||||
|
const [name, setName] = useState("Widget")
|
||||||
|
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
|
||||||
|
labels: [],
|
||||||
|
datasets: [],
|
||||||
|
});
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
// Chart data for a week
|
// Chart data for a week
|
||||||
const chartData = {
|
const defaultChartData = {
|
||||||
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], // Days of the week
|
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], // Days of the week
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
|
@ -78,12 +99,94 @@ const ProductionCapacity : React.FC<ProductionCapacityProps> = ({ position }) =>
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||||
|
|
||||||
|
const socket = io(`http://${iotApiUrl}`);
|
||||||
|
|
||||||
|
const inputData = {
|
||||||
|
measurements,
|
||||||
|
duration,
|
||||||
|
interval: 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const startStream = () => {
|
||||||
|
socket.emit("lineInput", inputData);
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.on("connect", startStream);
|
||||||
|
|
||||||
|
socket.on("lineOutput", (response) => {
|
||||||
|
const responseData = response.data;
|
||||||
|
|
||||||
|
// Extract timestamps and values
|
||||||
|
const labels = responseData.time;
|
||||||
|
const datasets = Object.keys(measurements).map((key) => {
|
||||||
|
const measurement = measurements[key];
|
||||||
|
const datasetKey = `${measurement.name}.${measurement.fields}`;
|
||||||
|
return {
|
||||||
|
label: datasetKey,
|
||||||
|
data: responseData[datasetKey]?.values ?? [],
|
||||||
|
backgroundColor: "#6f42c1", // Theme color
|
||||||
|
borderColor: "#6f42c1",
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 8, // Rounded corners for the bars
|
||||||
|
borderSkipped: false, // Ensure all corners are rounded
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setChartData({ labels, datasets });
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.off("lineOutput");
|
||||||
|
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
}, [measurements, duration, iotApiUrl]);
|
||||||
|
|
||||||
|
const fetchSavedInputes = async() => {
|
||||||
|
|
||||||
|
if (id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setmeasurements(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setName(response.data.widgetName)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedChartId?.id === id) {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,[chartMeasurements, chartDuration, widgetName])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Html position={[position[0], position[1], position[2]]}
|
<Html position={[position[0], position[1], position[2]]}
|
||||||
scale={[0.5, 0.5, 0.5]}
|
scale={[0.5, 0.5, 0.5]}
|
||||||
transform
|
transform
|
||||||
sprite>
|
sprite>
|
||||||
<div className="productionCapacity-wrapper card">
|
<div className="productionCapacity-wrapper card"
|
||||||
|
onClick={
|
||||||
|
() => setSelectedChartId({
|
||||||
|
id: id,
|
||||||
|
type: type
|
||||||
|
})
|
||||||
|
}>
|
||||||
<div className="headeproductionCapacityr-wrapper">
|
<div className="headeproductionCapacityr-wrapper">
|
||||||
<div className="header">Production Capacity</div>
|
<div className="header">Production Capacity</div>
|
||||||
<div className="production-capacity">
|
<div className="production-capacity">
|
||||||
|
@ -104,7 +207,7 @@ const ProductionCapacity : React.FC<ProductionCapacityProps> = ({ position }) =>
|
||||||
</div>{" "}
|
</div>{" "}
|
||||||
<div className="bar-chart charts">
|
<div className="bar-chart charts">
|
||||||
{/* Bar Chart */}
|
{/* Bar Chart */}
|
||||||
<Bar data={chartData} options={chartOptions} />
|
<Bar data={Object.keys(measurements).length > 0 ? chartData : defaultChartData } options={chartOptions} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Html>
|
</Html>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Html } from "@react-three/drei";
|
import { Html } from "@react-three/drei";
|
||||||
import React from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { Line } from "react-chartjs-2";
|
import { Line } from "react-chartjs-2";
|
||||||
import {
|
import {
|
||||||
Chart as ChartJS,
|
Chart as ChartJS,
|
||||||
|
@ -12,6 +12,10 @@ import {
|
||||||
ChartOptions,
|
ChartOptions,
|
||||||
} from "chart.js";
|
} from "chart.js";
|
||||||
import { WavyIcon } from "../../../icons/3dChartIcons";
|
import { WavyIcon } from "../../../icons/3dChartIcons";
|
||||||
|
import { useWidgetStore } from "../../../../store/useWidgetStore";
|
||||||
|
import useChartStore from "../../../../store/useChartStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import io from "socket.io-client";
|
||||||
|
|
||||||
// Register Chart.js components
|
// Register Chart.js components
|
||||||
ChartJS.register(
|
ChartJS.register(
|
||||||
|
@ -36,9 +40,24 @@ const SmoothLineGraphComponent: React.FC<SmoothLineGraphProps> = ({
|
||||||
return <Line data={data} options={options} />;
|
return <Line data={data} options={options} />;
|
||||||
};
|
};
|
||||||
interface ReturnOfInvestmentProps {
|
interface ReturnOfInvestmentProps {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
}
|
}
|
||||||
const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ position }) => {
|
const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, position }) => {
|
||||||
|
|
||||||
|
const { selectedChartId,setSelectedChartId } = useWidgetStore();
|
||||||
|
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||||
|
const [measurements, setmeasurements] = useState<any>({});
|
||||||
|
const [duration, setDuration] = useState("1h")
|
||||||
|
const [name, setName] = useState("Widget")
|
||||||
|
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
|
||||||
|
labels: [],
|
||||||
|
datasets: [],
|
||||||
|
});
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
// Improved sample data for the smooth curve graph (single day)
|
// Improved sample data for the smooth curve graph (single day)
|
||||||
const graphData: ChartData<"line"> = {
|
const graphData: ChartData<"line"> = {
|
||||||
labels: [
|
labels: [
|
||||||
|
@ -107,16 +126,100 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ position }) =>
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||||
|
|
||||||
|
const socket = io(`http://${iotApiUrl}`);
|
||||||
|
|
||||||
|
const inputData = {
|
||||||
|
measurements,
|
||||||
|
duration,
|
||||||
|
interval: 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const startStream = () => {
|
||||||
|
socket.emit("lineInput", inputData);
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.on("connect", startStream);
|
||||||
|
|
||||||
|
socket.on("lineOutput", (response) => {
|
||||||
|
const responseData = response.data;
|
||||||
|
|
||||||
|
// Extract timestamps and values
|
||||||
|
const labels = responseData.time;
|
||||||
|
const datasets = Object.keys(measurements).map((key, index) => {
|
||||||
|
const measurement = measurements[key];
|
||||||
|
const datasetKey = `${measurement.name}.${measurement.fields}`;
|
||||||
|
return {
|
||||||
|
label: datasetKey,
|
||||||
|
data: responseData[datasetKey]?.values ?? [],
|
||||||
|
borderColor: index === 0 ? "rgba(75, 192, 192, 1)": "rgba(255, 99, 132, 1)", // Light blue color
|
||||||
|
backgroundColor: index === 0 ? "rgba(75, 192, 192, 0.2)": "rgba(255, 99, 132, 0.2)",
|
||||||
|
fill: true,
|
||||||
|
tension: 0.4, // Smooth curve effect
|
||||||
|
pointRadius: 0, // Hide dots
|
||||||
|
pointHoverRadius: 0, // Hide hover dots
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setChartData({ labels, datasets });
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.off("lineOutput");
|
||||||
|
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
}, [measurements, duration, iotApiUrl]);
|
||||||
|
|
||||||
|
const fetchSavedInputes = async() => {
|
||||||
|
|
||||||
|
if (id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setmeasurements(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setName(response.data.widgetName)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedChartId?.id === id) {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,[chartMeasurements, chartDuration, widgetName])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Html position={[position[0], position[1], position[2]]}
|
<Html position={[position[0], position[1], position[2]]}
|
||||||
scale={[0.5, 0.5, 0.5]}
|
scale={[0.5, 0.5, 0.5]}
|
||||||
transform
|
transform
|
||||||
|
zIndexRange={[1,0]}
|
||||||
sprite>
|
sprite>
|
||||||
<div className="returnOfInvestment card">
|
<div className="returnOfInvestment card"
|
||||||
|
onClick={
|
||||||
|
() => setSelectedChartId({
|
||||||
|
id: id,
|
||||||
|
type: type
|
||||||
|
})
|
||||||
|
}>
|
||||||
<div className="header">Return of Investment</div>
|
<div className="header">Return of Investment</div>
|
||||||
<div className="lineGraph charts">
|
<div className="lineGraph charts">
|
||||||
{/* Smooth curve graph with two datasets */}
|
{/* Smooth curve graph with two datasets */}
|
||||||
<SmoothLineGraphComponent data={graphData} options={graphOptions} />
|
<SmoothLineGraphComponent data={Object.keys(measurements).length > 0 ? chartData : graphData} options={graphOptions} />
|
||||||
</div>
|
</div>
|
||||||
<div className="returns-wrapper">
|
<div className="returns-wrapper">
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
|
|
|
@ -1,28 +1,112 @@
|
||||||
import { Html } from "@react-three/drei";
|
import { Html } from "@react-three/drei";
|
||||||
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
|
import { useWidgetStore } from "../../../../store/useWidgetStore";
|
||||||
|
import useChartStore from "../../../../store/useChartStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import io from "socket.io-client";
|
||||||
|
|
||||||
// import image from "../../../../assets/image/temp/image.png";
|
// import image from "../../../../assets/image/temp/image.png";
|
||||||
interface StateWorkingProps {
|
interface StateWorkingProps {
|
||||||
|
id:string;
|
||||||
|
type: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
}
|
}
|
||||||
const StateWorking: React.FC<StateWorkingProps> = ({ position }) => {
|
const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position }) => {
|
||||||
const datas = [
|
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||||
{ key: "Oil Tank:", value: "24/341" },
|
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||||
{ key: "Oil Refin:", value: 36.023 },
|
const [measurements, setmeasurements] = useState<any>({});
|
||||||
{ key: "Transmission:", value: 36.023 },
|
const [duration, setDuration] = useState("1h")
|
||||||
{ key: "Fuel:", value: 36732 },
|
const [name, setName] = useState("Widget")
|
||||||
{ key: "Power:", value: 1300 },
|
const [datas, setDatas] = useState<any>({});
|
||||||
{ key: "Time:", value: 13 - 9 - 2023 },
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
];
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
// 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 },
|
||||||
|
// ];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||||
|
const socket = io(`http://${iotApiUrl}`);
|
||||||
|
const inputData = {
|
||||||
|
measurements,
|
||||||
|
duration,
|
||||||
|
interval: 1000,
|
||||||
|
};
|
||||||
|
const startStream = () => {
|
||||||
|
socket.emit("lastInput", inputData);
|
||||||
|
};
|
||||||
|
socket.on("connect", startStream);
|
||||||
|
socket.on("lastOutput", (response) => {
|
||||||
|
const responseData = response;
|
||||||
|
console.log("responceeeeeeeeeee",response);
|
||||||
|
|
||||||
|
setDatas(responseData);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.off("lastOutput");
|
||||||
|
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
}, [measurements, duration, iotApiUrl]);
|
||||||
|
|
||||||
|
const fetchSavedInputes = async() => {
|
||||||
|
|
||||||
|
if (id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setmeasurements(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setName(response.data.widgetName)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("dataaaaa",datas);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedChartId?.id === id) {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,[chartMeasurements, chartDuration, widgetName])
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Html position={[position[0], position[1], position[2]]}
|
<Html position={[position[0], position[1], position[2]]}
|
||||||
scale={[0.5, 0.5, 0.5]}
|
scale={[0.5, 0.5, 0.5]}
|
||||||
transform
|
transform
|
||||||
|
zIndexRange={[1,0]}
|
||||||
sprite>
|
sprite>
|
||||||
<div className="stateWorking-wrapper card">
|
<div className="stateWorking-wrapper card"
|
||||||
|
onClick={
|
||||||
|
() => setSelectedChartId({
|
||||||
|
id: id,
|
||||||
|
type: type
|
||||||
|
})
|
||||||
|
}>
|
||||||
<div className="header-wrapper">
|
<div className="header-wrapper">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<span>State</span>
|
<span>State</span>
|
||||||
<span>
|
<span>
|
||||||
Working <span>.</span>
|
{datas?.input1 ? datas.input1 : 'input1'} <span>.</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="img">
|
<div className="img">
|
||||||
|
@ -31,12 +115,36 @@ const StateWorking: React.FC<StateWorkingProps> = ({ position }) => {
|
||||||
</div>
|
</div>
|
||||||
{/* Data */}
|
{/* Data */}
|
||||||
<div className="data-wrapper">
|
<div className="data-wrapper">
|
||||||
{datas.map((data, index) => (
|
{/* {datas.map((data, index) => (
|
||||||
<div className="data-table" key={index}>
|
<div className="data-table" key={index}>
|
||||||
<div className="data">{data.key}</div>
|
<div className="data">{data.key}</div>
|
||||||
<div className="key">{data.value}</div>
|
<div className="key">{data.value}</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))} */}
|
||||||
|
<div className="data-table">
|
||||||
|
<div className="data">{measurements?.input2?.fields ? measurements.input2.fields : 'input2'}</div>
|
||||||
|
<div className="key">{datas?.input2 ? datas.input2 : 'data'}</div>
|
||||||
|
</div>
|
||||||
|
<div className="data-table">
|
||||||
|
<div className="data">{measurements?.input3?.fields ? measurements.input3.fields : 'input3'}</div>
|
||||||
|
<div className="key">{datas?.input3 ? datas.input3 : 'data'}</div>
|
||||||
|
</div>
|
||||||
|
<div className="data-table">
|
||||||
|
<div className="data">{measurements?.input4?.fields ? measurements.input4.fields : 'input4'}</div>
|
||||||
|
<div className="key">{datas?.input4 ? datas.input4 : 'data'}</div>
|
||||||
|
</div>
|
||||||
|
<div className="data-table">
|
||||||
|
<div className="data">{measurements?.input5?.fields ? measurements.input5.fields : 'input5'}</div>
|
||||||
|
<div className="key">{datas?.input5 ? datas.input5 : 'data'}</div>
|
||||||
|
</div>
|
||||||
|
<div className="data-table">
|
||||||
|
<div className="data">{measurements?.input6?.fields ? measurements.input6.fields : 'input6'}</div>
|
||||||
|
<div className="key">{datas?.input6 ? datas.input6 : 'data'}</div>
|
||||||
|
</div>
|
||||||
|
<div className="data-table">
|
||||||
|
<div className="data">{measurements?.input7?.fields ? measurements.input7.fields : 'input7'}</div>
|
||||||
|
<div className="key">{datas?.input7 ? datas.input7 : 'data'}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Html>
|
</Html>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Html } from "@react-three/drei";
|
import { Html } from "@react-three/drei";
|
||||||
import React from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { Line } from "react-chartjs-2";
|
import { Line } from "react-chartjs-2";
|
||||||
import {
|
import {
|
||||||
Chart as ChartJS,
|
Chart as ChartJS,
|
||||||
|
@ -14,6 +14,10 @@ import {
|
||||||
ChartOptions,
|
ChartOptions,
|
||||||
} from "chart.js";
|
} from "chart.js";
|
||||||
import { ThroughputIcon } from "../../../icons/3dChartIcons";
|
import { ThroughputIcon } from "../../../icons/3dChartIcons";
|
||||||
|
import { useWidgetStore } from "../../../../store/useWidgetStore";
|
||||||
|
import useChartStore from "../../../../store/useChartStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import io from "socket.io-client";
|
||||||
|
|
||||||
// Register Chart.js components
|
// Register Chart.js components
|
||||||
ChartJS.register(
|
ChartJS.register(
|
||||||
|
@ -38,10 +42,25 @@ const LineGraphComponent: React.FC<LineGraphProps> = ({ data, options }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ThroughputProps {
|
interface ThroughputProps {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Throughput: React.FC<ThroughputProps> = ({ position }) => {
|
const Throughput: React.FC<ThroughputProps> = ({ id, type, position }) => {
|
||||||
|
|
||||||
|
const { selectedChartId,setSelectedChartId } = useWidgetStore();
|
||||||
|
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||||
|
const [measurements, setmeasurements] = useState<any>({});
|
||||||
|
const [duration, setDuration] = useState("1h")
|
||||||
|
const [name, setName] = useState("Widget")
|
||||||
|
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
|
||||||
|
labels: [],
|
||||||
|
datasets: [],
|
||||||
|
});
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
|
||||||
// Sample data for the line graph
|
// Sample data for the line graph
|
||||||
const graphData: ChartData<"line"> = {
|
const graphData: ChartData<"line"> = {
|
||||||
|
@ -90,13 +109,94 @@ const Throughput: React.FC<ThroughputProps> = ({ position }) => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||||
|
|
||||||
|
const socket = io(`http://${iotApiUrl}`);
|
||||||
|
|
||||||
|
const inputData = {
|
||||||
|
measurements,
|
||||||
|
duration,
|
||||||
|
interval: 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const startStream = () => {
|
||||||
|
socket.emit("lineInput", inputData);
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.on("connect", startStream);
|
||||||
|
|
||||||
|
socket.on("lineOutput", (response) => {
|
||||||
|
const responseData = response.data;
|
||||||
|
|
||||||
|
// Extract timestamps and values
|
||||||
|
const labels = responseData.time;
|
||||||
|
const datasets = Object.keys(measurements).map((key) => {
|
||||||
|
const measurement = measurements[key];
|
||||||
|
const datasetKey = `${measurement.name}.${measurement.fields}`;
|
||||||
|
return {
|
||||||
|
label: datasetKey,
|
||||||
|
data: responseData[datasetKey]?.values ?? [],
|
||||||
|
borderColor: "rgba(75, 192, 192, 1)",
|
||||||
|
backgroundColor: "rgba(75, 192, 192, 0.2)",
|
||||||
|
fill: true,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setChartData({ labels, datasets });
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.off("lineOutput");
|
||||||
|
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
}, [measurements, duration, iotApiUrl]);
|
||||||
|
|
||||||
|
const fetchSavedInputes = async() => {
|
||||||
|
|
||||||
|
if (id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setmeasurements(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setName(response.data.widgetName)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedChartId?.id === id) {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,[chartMeasurements, chartDuration, widgetName])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Html position={[position[0], position[1], position[2]]}
|
<Html position={[position[0], position[1], position[2]]}
|
||||||
scale={[0.5, 0.5, 0.5]}
|
scale={[0.5, 0.5, 0.5]}
|
||||||
transform
|
transform
|
||||||
|
zIndexRange={[1, 0]}
|
||||||
sprite>
|
sprite>
|
||||||
<div className="throughput-wrapper">
|
<div className="throughput-wrapper"
|
||||||
<div className="header">Throughput</div>
|
onClick={
|
||||||
|
() => setSelectedChartId({
|
||||||
|
id: id,
|
||||||
|
type: type
|
||||||
|
})
|
||||||
|
}>
|
||||||
|
<div className="header">{name}</div>
|
||||||
<div className="display-value">
|
<div className="display-value">
|
||||||
<div className="left">
|
<div className="left">
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
|
@ -119,7 +219,7 @@ const Throughput: React.FC<ThroughputProps> = ({ position }) => {
|
||||||
</div>
|
</div>
|
||||||
<div className="line-graph">
|
<div className="line-graph">
|
||||||
{/* Line graph using react-chartjs-2 */}
|
{/* Line graph using react-chartjs-2 */}
|
||||||
<LineGraphComponent data={graphData} options={graphOptions} />
|
<LineGraphComponent data={Object.keys(measurements).length > 0 ? chartData : graphData} options={graphOptions} />
|
||||||
</div>
|
</div>
|
||||||
<div className="footer">
|
<div className="footer">
|
||||||
You made an extra <span className="value">$1256.13</span> this month
|
You made an extra <span className="value">$1256.13</span> this month
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
// ConfirmationDialog.tsx
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface ConfirmationPopupProps {
|
||||||
|
message: string;
|
||||||
|
onConfirm: () => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ConfirmationPopup: React.FC<ConfirmationPopupProps> = ({
|
||||||
|
message,
|
||||||
|
onConfirm,
|
||||||
|
onCancel,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="confirmation-overlay">
|
||||||
|
<div className="confirmation-modal">
|
||||||
|
<p className="message">{message}</p>
|
||||||
|
<div className="buttton-wrapper">
|
||||||
|
<div className="confirmation-button" onClick={onConfirm}>
|
||||||
|
OK
|
||||||
|
</div>
|
||||||
|
<div className="confirmation-button" onClick={onCancel}>
|
||||||
|
Cancel
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ConfirmationPopup;
|
|
@ -9,13 +9,14 @@ import { getCategoryAsset } from "../../../services/factoryBuilder/assest/assets
|
||||||
import arch from "../../../assets/gltf-glb/arch.glb";
|
import arch from "../../../assets/gltf-glb/arch.glb";
|
||||||
import door from "../../../assets/gltf-glb/door.glb";
|
import door from "../../../assets/gltf-glb/door.glb";
|
||||||
import window from "../../../assets/gltf-glb/window.glb";
|
import window from "../../../assets/gltf-glb/window.glb";
|
||||||
|
import { fetchAssets } from "../../../services/marketplace/fetchAssets";
|
||||||
import { useSelectedItem } from "../../../store/store";
|
import { useSelectedItem } from "../../../store/store";
|
||||||
interface AssetProp {
|
interface AssetProp {
|
||||||
filename: string;
|
filename: string;
|
||||||
thumbnail?: string;
|
thumbnail?: string;
|
||||||
category: string;
|
category: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
tags?: string;
|
tags: string;
|
||||||
url?: String;
|
url?: String;
|
||||||
uploadDate?: number;
|
uploadDate?: number;
|
||||||
isArchieve?: boolean;
|
isArchieve?: boolean;
|
||||||
|
@ -23,19 +24,58 @@ interface AssetProp {
|
||||||
price?: number;
|
price?: number;
|
||||||
CreatedBy?: String;
|
CreatedBy?: String;
|
||||||
}
|
}
|
||||||
|
interface CategoryListProp {
|
||||||
|
assetImage?: string;
|
||||||
|
assetName?: string;
|
||||||
|
categoryImage: string;
|
||||||
|
category: string;
|
||||||
|
}
|
||||||
const Assets: React.FC = () => {
|
const Assets: React.FC = () => {
|
||||||
const { setSelectedItem } = useSelectedItem();
|
const { setSelectedItem } = useSelectedItem();
|
||||||
const [searchValue, setSearchValue] = useState<string>("");
|
const [searchValue, setSearchValue] = useState<string>("");
|
||||||
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
||||||
const [filteredAsset, setFilteredAsset] = useState<AssetProp[]>([]);
|
const [categoryAssets, setCategoryAssets] = useState<AssetProp[]>([]);
|
||||||
|
const [filtereredAssets, setFiltereredAssets] = useState<AssetProp[]>([]);
|
||||||
|
const [categoryList, setCategoryList] = useState<CategoryListProp[]>([]);
|
||||||
|
|
||||||
const handleSearchChange = (value: string) => {
|
const handleSearchChange = (value: string) => {
|
||||||
|
const searchTerm = value.toLowerCase();
|
||||||
setSearchValue(value);
|
setSearchValue(value);
|
||||||
setSelectedCategory(null); // Reset selected category when search changes
|
if (searchTerm.trim() === "" && !selectedCategory) {
|
||||||
};
|
setCategoryAssets([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const filteredModels = filtereredAssets?.filter((model) => {
|
||||||
|
if (!model?.tags || !model?.filename || !model?.category) return false;
|
||||||
|
if (searchTerm.startsWith(":") && searchTerm.length > 1) {
|
||||||
|
const tagSearchTerm = searchTerm.slice(1);
|
||||||
|
return model.tags.toLowerCase().includes(tagSearchTerm);
|
||||||
|
} else if (selectedCategory) {
|
||||||
|
return (
|
||||||
|
model.category
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(selectedCategory.toLowerCase()) &&
|
||||||
|
model.filename.toLowerCase().includes(searchTerm)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return model.filename.toLowerCase().includes(searchTerm);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const categoryList = useMemo(
|
setCategoryAssets(filteredModels);
|
||||||
() => [
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
const filteredAssets = async () => {
|
||||||
|
try {
|
||||||
|
const filt = await fetchAssets();
|
||||||
|
setFiltereredAssets(filt);
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
|
filteredAssets();
|
||||||
|
}, [categoryAssets]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCategoryList([
|
||||||
{
|
{
|
||||||
assetName: "Doors",
|
assetName: "Doors",
|
||||||
assetImage: "",
|
assetImage: "",
|
||||||
|
@ -58,10 +98,8 @@ const Assets: React.FC = () => {
|
||||||
{ category: "Workstation", categoryImage: workStation },
|
{ category: "Workstation", categoryImage: workStation },
|
||||||
{ category: "Machines", categoryImage: machines },
|
{ category: "Machines", categoryImage: machines },
|
||||||
{ category: "Workers", categoryImage: worker },
|
{ category: "Workers", categoryImage: worker },
|
||||||
],
|
]);
|
||||||
[]
|
}, []);
|
||||||
);
|
|
||||||
|
|
||||||
const fetchCategoryAssets = async (asset: any) => {
|
const fetchCategoryAssets = async (asset: any) => {
|
||||||
setSelectedCategory(asset);
|
setSelectedCategory(asset);
|
||||||
if (asset === "Feneration") {
|
if (asset === "Feneration") {
|
||||||
|
@ -70,60 +108,93 @@ const Assets: React.FC = () => {
|
||||||
filename: "arch",
|
filename: "arch",
|
||||||
category: "Feneration",
|
category: "Feneration",
|
||||||
url: arch,
|
url: arch,
|
||||||
|
tags: "arch",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
filename: "door",
|
filename: "door",
|
||||||
category: "Feneration",
|
category: "Feneration",
|
||||||
url: door,
|
url: door,
|
||||||
|
thumbnail: feneration,
|
||||||
|
tags: "door",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
filename: "window",
|
filename: "window",
|
||||||
category: "Feneration",
|
category: "Feneration",
|
||||||
url: window,
|
url: window,
|
||||||
|
tags: "window",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
setFilteredAsset(localAssets);
|
setCategoryAssets(localAssets);
|
||||||
|
setFiltereredAssets(localAssets);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const res = await getCategoryAsset(asset);
|
const res = await getCategoryAsset(asset);
|
||||||
setFilteredAsset(res || []); // Ensure it's always an array
|
setCategoryAssets(res);
|
||||||
} catch (error) { }
|
setFiltereredAssets(res);
|
||||||
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => { }, [filteredAsset]);
|
|
||||||
return (
|
return (
|
||||||
<div className="assets-container">
|
<div className="assets-container">
|
||||||
<Search onChange={handleSearchChange} />
|
<Search onChange={handleSearchChange} />
|
||||||
{searchValue ? (
|
{searchValue ? (
|
||||||
<div className="searched-content">
|
<div className="assets-result">
|
||||||
<p>Results for "{searchValue}"</p>
|
<div className="assets-wrapper">
|
||||||
|
<div className="searched-content">
|
||||||
|
<p>Results for {searchValue}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="assets-container">
|
||||||
|
{categoryAssets &&
|
||||||
|
categoryAssets?.map((asset: any, index: number) => (
|
||||||
|
<div key={index} className="assets">
|
||||||
|
<img
|
||||||
|
src={asset?.thumbnail}
|
||||||
|
alt={asset.filename}
|
||||||
|
className="asset-image"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="asset-name">
|
||||||
|
{asset.filename
|
||||||
|
.split("_")
|
||||||
|
.map(
|
||||||
|
(word: any) =>
|
||||||
|
word.charAt(0).toUpperCase() + word.slice(1)
|
||||||
|
)
|
||||||
|
.join(" ")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : selectedCategory ? (
|
) : selectedCategory ? (
|
||||||
<div className="assets-wrapper">
|
<div className="assets-wrapper">
|
||||||
{/* Back Button */}
|
|
||||||
<div
|
<div
|
||||||
className="back-button"
|
className="back-button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedCategory(null);
|
setSelectedCategory(null);
|
||||||
setFilteredAsset([]);
|
setCategoryAssets([]);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
← Back
|
← Back
|
||||||
</div>
|
</div>
|
||||||
<h2>{selectedCategory}</h2>
|
<h2>{selectedCategory}</h2>
|
||||||
<div className="assets-container">
|
<div className="assets-container">
|
||||||
{filteredAsset &&
|
{categoryAssets &&
|
||||||
filteredAsset?.map((asset: any, index: number) => (
|
categoryAssets?.map((asset: any, index: number) => (
|
||||||
<div key={index} className="assets">
|
<div key={index} className="assets">
|
||||||
{asset?.thumbnail && (
|
<img
|
||||||
<img
|
src={asset?.thumbnail}
|
||||||
src={asset?.thumbnail}
|
alt={asset.filename}
|
||||||
alt={asset.filename}
|
className="asset-image"
|
||||||
className="asset-image"
|
onPointerDown={() =>
|
||||||
onPointerDown={() => setSelectedItem({ name: asset.filename, id: asset.modelfileID })}
|
setSelectedItem({
|
||||||
/>
|
name: asset.filename,
|
||||||
)}
|
id: asset.modelfileID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className="asset-name">
|
<div className="asset-name">
|
||||||
{asset.filename
|
{asset.filename
|
||||||
.split("_")
|
.split("_")
|
||||||
|
|
|
@ -59,9 +59,11 @@ const ProgressBarWidget = ({
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
data,
|
data,
|
||||||
|
type
|
||||||
}: {
|
}: {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
type: string;
|
||||||
data: any;
|
data: any;
|
||||||
}) => {
|
}) => {
|
||||||
const { setDraggedAsset } = useWidgetStore((state) => state);
|
const { setDraggedAsset } = useWidgetStore((state) => state);
|
||||||
|
@ -72,7 +74,7 @@ const ProgressBarWidget = ({
|
||||||
draggable
|
draggable
|
||||||
onDragStart={() => {
|
onDragStart={() => {
|
||||||
setDraggedAsset({
|
setDraggedAsset({
|
||||||
type: "progress",
|
type: type,
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
panel: "top",
|
panel: "top",
|
||||||
|
@ -99,6 +101,7 @@ const ProgressBarWidget = ({
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
console.log(chartTypes, "chartTypes");
|
||||||
|
|
||||||
const Widgets2D = () => {
|
const Widgets2D = () => {
|
||||||
return (
|
return (
|
||||||
|
@ -123,6 +126,7 @@ const Widgets2D = () => {
|
||||||
{ key: "units", value: 1000, description: "Initial stock" },
|
{ key: "units", value: 1000, description: "Initial stock" },
|
||||||
],
|
],
|
||||||
}}
|
}}
|
||||||
|
type={"progress 1"}
|
||||||
/>
|
/>
|
||||||
<ProgressBarWidget
|
<ProgressBarWidget
|
||||||
id="widget-8"
|
id="widget-8"
|
||||||
|
@ -133,6 +137,7 @@ const Widgets2D = () => {
|
||||||
{ key: "units", value: 500, description: "Additional stock" },
|
{ key: "units", value: 500, description: "Additional stock" },
|
||||||
],
|
],
|
||||||
}}
|
}}
|
||||||
|
type={"progress 2"}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -33,6 +33,7 @@ const RenderAnalysisInputs: React.FC<InputRendererProps> = ({
|
||||||
label={preset.inputs.label}
|
label={preset.inputs.label}
|
||||||
min={0}
|
min={0}
|
||||||
max={0}
|
max={0}
|
||||||
|
value={5}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import InputRange from "../../../ui/inputs/InputRange";
|
import InputRange from "../../../ui/inputs/InputRange";
|
||||||
import InputToggle from "../../../ui/inputs/InputToggle";
|
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||||
import { AI_Icon } from "../../../icons/ExportCommonIcons";
|
import { AI_Icon } from "../../../icons/ExportCommonIcons";
|
||||||
|
@ -6,17 +6,20 @@ import LabeledButton from "../../../ui/inputs/LabledButton";
|
||||||
import {
|
import {
|
||||||
useAzimuth,
|
useAzimuth,
|
||||||
useElevation,
|
useElevation,
|
||||||
|
useLimitDistance,
|
||||||
useRenderDistance,
|
useRenderDistance,
|
||||||
useResetCamera,
|
useResetCamera,
|
||||||
useRoofVisibility,
|
useRoofVisibility,
|
||||||
useSelectedWallItem,
|
useSelectedWallItem,
|
||||||
useShadows,
|
useShadows,
|
||||||
useSocketStore,
|
useSocketStore,
|
||||||
|
useTileDistance,
|
||||||
useToggleView,
|
useToggleView,
|
||||||
useWallVisibility,
|
useWallVisibility,
|
||||||
} from "../../../../store/store";
|
} from "../../../../store/store";
|
||||||
import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment";
|
import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment";
|
||||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||||
|
import { validateBBox } from "@turf/helpers";
|
||||||
const GlobalProperties: React.FC = () => {
|
const GlobalProperties: React.FC = () => {
|
||||||
const { toggleView, setToggleView } = useToggleView();
|
const { toggleView, setToggleView } = useToggleView();
|
||||||
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
||||||
|
@ -27,26 +30,95 @@ const GlobalProperties: React.FC = () => {
|
||||||
const { elevation, setElevation } = useElevation();
|
const { elevation, setElevation } = useElevation();
|
||||||
const { azimuth, setAzimuth } = useAzimuth();
|
const { azimuth, setAzimuth } = useAzimuth();
|
||||||
const { renderDistance, setRenderDistance } = useRenderDistance();
|
const { renderDistance, setRenderDistance } = useRenderDistance();
|
||||||
|
const { setPlaneValue, setGridValue, planeValue, gridValue } =
|
||||||
|
useTileDistance();
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(gridValue, planeValue, "values");
|
||||||
|
}, [gridValue, planeValue]);
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const [limitDistance, setLimitDistance] = useState(false);
|
const { limitDistance, setLimitDistance } = useLimitDistance();
|
||||||
const [distance, setDistance] = useState<number>(30);
|
const [distance, setDistance] = useState<number>(40);
|
||||||
|
useEffect(() => {}, [limitDistance]);
|
||||||
|
|
||||||
const [limitGridDistance, setLimitGridDistance] = useState(false);
|
const [limitGridDistance, setLimitGridDistance] = useState(false);
|
||||||
const [gridDistance, setGridDistance] = useState<number>(5);
|
const [gridDistance, setGridDistance] = useState<number>(3);
|
||||||
|
|
||||||
function optimizeScene() {
|
const optimizeScene = async (value: any) => {
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
|
||||||
|
|
||||||
|
const data = await setEnvironment(
|
||||||
|
organization,
|
||||||
|
localStorage.getItem("userId")!,
|
||||||
|
wallVisibility,
|
||||||
|
roofVisibility,
|
||||||
|
shadows,
|
||||||
|
30,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
setRenderDistance(30);
|
||||||
setLimitDistance(true);
|
setLimitDistance(true);
|
||||||
setDistance(30);
|
};
|
||||||
}
|
const limitRenderDistance = async () => {
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
|
||||||
|
|
||||||
|
if (limitDistance) {
|
||||||
|
let data = await setEnvironment(
|
||||||
|
organization,
|
||||||
|
localStorage.getItem("userId")!,
|
||||||
|
wallVisibility,
|
||||||
|
roofVisibility,
|
||||||
|
shadows,
|
||||||
|
75,
|
||||||
|
!limitDistance
|
||||||
|
);
|
||||||
|
setRenderDistance(75);
|
||||||
|
} else {
|
||||||
|
let data = await setEnvironment(
|
||||||
|
organization,
|
||||||
|
localStorage.getItem("userId")!,
|
||||||
|
wallVisibility,
|
||||||
|
roofVisibility,
|
||||||
|
shadows,
|
||||||
|
renderDistance,
|
||||||
|
!limitDistance
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setLimitDistance(!limitDistance);
|
||||||
|
};
|
||||||
|
|
||||||
function updateDistance(value: number) {
|
function updateDistance(value: number) {
|
||||||
setDistance(value);
|
setDistance(value);
|
||||||
setRenderDistance(value);
|
setRenderDistance(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateGridDistance(value: number) {
|
function updateGridDistance(value: number) {
|
||||||
setGridDistance(value);
|
setGridDistance(value);
|
||||||
|
// setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
|
||||||
|
// setPlaneValue({ height: value * 100, width: value * 100 });
|
||||||
}
|
}
|
||||||
|
function updatedGrid(value: number) {
|
||||||
|
console.log(" (value * 100) / 4 : ", (value * 100) / 4);
|
||||||
|
setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
|
||||||
|
setPlaneValue({ height: value * 100, width: value * 100 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedDist = async (value: number) => {
|
||||||
|
const email = localStorage.getItem("email");
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
|
||||||
|
setRenderDistance(value);
|
||||||
|
// setDistance(value);
|
||||||
|
const data = await setEnvironment(
|
||||||
|
organization,
|
||||||
|
localStorage.getItem("userId")!,
|
||||||
|
wallVisibility,
|
||||||
|
roofVisibility,
|
||||||
|
shadows,
|
||||||
|
value,
|
||||||
|
limitDistance
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// Function to toggle roof visibility
|
// Function to toggle roof visibility
|
||||||
const changeRoofVisibility = async () => {
|
const changeRoofVisibility = async () => {
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
|
@ -58,7 +130,9 @@ const GlobalProperties: React.FC = () => {
|
||||||
localStorage.getItem("userId")!,
|
localStorage.getItem("userId")!,
|
||||||
wallVisibility,
|
wallVisibility,
|
||||||
!roofVisibility,
|
!roofVisibility,
|
||||||
shadows
|
shadows,
|
||||||
|
renderDistance,
|
||||||
|
limitDistance
|
||||||
);
|
);
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -85,7 +159,9 @@ const GlobalProperties: React.FC = () => {
|
||||||
localStorage.getItem("userId")!,
|
localStorage.getItem("userId")!,
|
||||||
!wallVisibility,
|
!wallVisibility,
|
||||||
roofVisibility,
|
roofVisibility,
|
||||||
shadows
|
shadows,
|
||||||
|
renderDistance,
|
||||||
|
limitDistance
|
||||||
);
|
);
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -112,7 +188,9 @@ const GlobalProperties: React.FC = () => {
|
||||||
localStorage.getItem("userId")!,
|
localStorage.getItem("userId")!,
|
||||||
wallVisibility,
|
wallVisibility,
|
||||||
roofVisibility,
|
roofVisibility,
|
||||||
!shadows
|
!shadows,
|
||||||
|
renderDistance,
|
||||||
|
limitDistance
|
||||||
);
|
);
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -184,18 +262,24 @@ const GlobalProperties: React.FC = () => {
|
||||||
inputKey="4"
|
inputKey="4"
|
||||||
label="Limit Render Distance"
|
label="Limit Render Distance"
|
||||||
value={limitDistance}
|
value={limitDistance}
|
||||||
onClick={() => {
|
// onClick={() => {
|
||||||
setLimitDistance(!limitDistance);
|
// setLimitDistance(!limitDistance);
|
||||||
|
// // setDistance(75);
|
||||||
|
// // setRenderDistance(75);
|
||||||
|
// }}
|
||||||
|
onClick={async () => {
|
||||||
|
await limitRenderDistance(); // Call the function here
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<InputRange
|
<InputRange
|
||||||
label="Distance"
|
label="Distance"
|
||||||
disabled={!limitDistance}
|
disabled={!limitDistance}
|
||||||
value={distance}
|
value={renderDistance}
|
||||||
key={"5"}
|
|
||||||
min={CONSTANTS.distanceConfig.minDistance}
|
min={CONSTANTS.distanceConfig.minDistance}
|
||||||
max={CONSTANTS.distanceConfig.maxDistance}
|
max={CONSTANTS.distanceConfig.maxDistance}
|
||||||
onChange={(value: number) => updateDistance(value)}
|
onChange={(value: number) => updateDistance(value)}
|
||||||
|
onPointerUp={updatedDist}
|
||||||
|
key={"6"}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="split"></div>
|
<div className="split"></div>
|
||||||
|
@ -213,7 +297,10 @@ const GlobalProperties: React.FC = () => {
|
||||||
disabled={!limitGridDistance}
|
disabled={!limitGridDistance}
|
||||||
value={gridDistance}
|
value={gridDistance}
|
||||||
key={"7"}
|
key={"7"}
|
||||||
|
min={1}
|
||||||
|
max={5}
|
||||||
onChange={(value: number) => updateGridDistance(value)}
|
onChange={(value: number) => updateGridDistance(value)}
|
||||||
|
onPointerUp={updatedGrid}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||||
|
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||||
|
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||||
|
import useChartStore from "../../../../../store/useChartStore";
|
||||||
|
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
|
||||||
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||||
|
|
||||||
|
type Props = {};
|
||||||
|
|
||||||
|
const BarChartInput = (props: Props) => {
|
||||||
|
const [widgetName, setWidgetName] = useState('Widget');
|
||||||
|
const { setMeasurements, updateDuration, updateName } = useChartStore();
|
||||||
|
const [duration, setDuration] = useState('1h')
|
||||||
|
const [dropDowndata, setDropDownData] = useState({});
|
||||||
|
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||||
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchZoneData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
// console.log("dropdown data:", response.data);
|
||||||
|
setDropDownData(response.data);
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchZoneData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchSavedInputes = async () => {
|
||||||
|
if (selectedChartId.id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setSelections(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setWidgetName(response.data.widgetName)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchSavedInputes();
|
||||||
|
|
||||||
|
}, [selectedChartId.id]);
|
||||||
|
|
||||||
|
// Sync Zustand state when component mounts
|
||||||
|
useEffect(() => {
|
||||||
|
setMeasurements(selections);
|
||||||
|
updateDuration(duration);
|
||||||
|
updateName(widgetName);
|
||||||
|
}, [selections, duration, widgetName]);
|
||||||
|
|
||||||
|
|
||||||
|
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, {
|
||||||
|
organization: organization,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
widget: {
|
||||||
|
id: selectedChartId.id,
|
||||||
|
panel: selectedChartId.panel,
|
||||||
|
widgetName: inputName,
|
||||||
|
Data: {
|
||||||
|
measurements: inputMeasurement,
|
||||||
|
duration: inputDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any);
|
||||||
|
if (response.status === 200) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||||
|
|
||||||
|
// async() => {
|
||||||
|
const newSelections = { ...selections };
|
||||||
|
if (selectedData === null) {
|
||||||
|
delete newSelections[inputKey];
|
||||||
|
} else {
|
||||||
|
newSelections[inputKey] = selectedData;
|
||||||
|
}
|
||||||
|
// setMeasurements(newSelections); // Update Zustand store
|
||||||
|
console.log(newSelections);
|
||||||
|
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||||
|
setSelections(newSelections);
|
||||||
|
}
|
||||||
|
// sendInputes(newSelections, duration); // Send data to server
|
||||||
|
// return newSelections;
|
||||||
|
// };
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectDuration = async (option: string) => {
|
||||||
|
if (await sendInputes(selections, option, widgetName)) {
|
||||||
|
setDuration(option);
|
||||||
|
}
|
||||||
|
// setDuration(option);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNameChange = async (name:any) => {
|
||||||
|
console.log('name change requested',name);
|
||||||
|
|
||||||
|
if (await sendInputes(selections, duration, name)) {
|
||||||
|
setWidgetName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="inputs-wrapper">
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Title</div>
|
||||||
|
<RenameInput value={selectedChartId?.title || "untited"} onRename={handleNameChange}/>
|
||||||
|
</div>
|
||||||
|
{[...Array(3)].map((_, index) => {
|
||||||
|
const inputKey = `input${index + 1}`;
|
||||||
|
return (
|
||||||
|
<div key={index} className="datas">
|
||||||
|
<div className="datas__label">Input {index + 1}</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<MultiLevelDropdown
|
||||||
|
data={dropDowndata}
|
||||||
|
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||||
|
onUnselect={() => handleSelect(inputKey, null)}
|
||||||
|
selectedValue={selections[inputKey]} // Load from Zustand
|
||||||
|
/>
|
||||||
|
<div className="icon">
|
||||||
|
<AddIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Duration</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<RegularDropDown
|
||||||
|
header={duration}
|
||||||
|
options={["1h", "2h", "12h"]}
|
||||||
|
onSelect={handleSelectDuration}
|
||||||
|
search={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BarChartInput;
|
|
@ -0,0 +1,178 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||||
|
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||||
|
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||||
|
import useChartStore from "../../../../../store/useChartStore";
|
||||||
|
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
|
||||||
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||||
|
|
||||||
|
type Props = {};
|
||||||
|
|
||||||
|
const FleetEfficiencyInputComponent = (props: Props) => {
|
||||||
|
const [widgetName, setWidgetName] = useState('Widget');
|
||||||
|
const { setFlotingMeasurements, updateFlotingDuration, updateHeader } = useChartStore();
|
||||||
|
const [duration, setDuration] = useState('1h')
|
||||||
|
const [dropDowndata, setDropDownData] = useState({});
|
||||||
|
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||||
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchZoneData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
// console.log("dropdown data:", response.data);
|
||||||
|
setDropDownData(response.data);
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchZoneData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchSavedInputes = async () => {
|
||||||
|
if (selectedChartId.id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
console.log(response.data);
|
||||||
|
|
||||||
|
setSelections(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setWidgetName(response.data.header)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchSavedInputes();
|
||||||
|
|
||||||
|
}, [selectedChartId.id]);
|
||||||
|
|
||||||
|
// Sync Zustand state when component mounts
|
||||||
|
useEffect(() => {
|
||||||
|
setFlotingMeasurements(selections);
|
||||||
|
updateFlotingDuration(duration);
|
||||||
|
updateHeader(widgetName);
|
||||||
|
}, [selections, duration, widgetName]);
|
||||||
|
|
||||||
|
|
||||||
|
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/floatwidget/save`, {
|
||||||
|
organization: organization,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
widget: {
|
||||||
|
id: selectedChartId.id,
|
||||||
|
header: inputName,
|
||||||
|
Data: {
|
||||||
|
measurements: inputMeasurement,
|
||||||
|
duration: inputDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any);
|
||||||
|
if (response.status === 200) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||||
|
|
||||||
|
// async() => {
|
||||||
|
const newSelections = { ...selections };
|
||||||
|
if (selectedData === null) {
|
||||||
|
delete newSelections[inputKey];
|
||||||
|
} else {
|
||||||
|
newSelections[inputKey] = selectedData;
|
||||||
|
}
|
||||||
|
// setMeasurements(newSelections); // Update Zustand store
|
||||||
|
console.log(newSelections);
|
||||||
|
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||||
|
setSelections(newSelections);
|
||||||
|
}
|
||||||
|
// sendInputes(newSelections, duration); // Send data to server
|
||||||
|
// return newSelections;
|
||||||
|
// };
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectDuration = async (option: string) => {
|
||||||
|
if (await sendInputes(selections, option, widgetName)) {
|
||||||
|
setDuration(option);
|
||||||
|
}
|
||||||
|
// setDuration(option);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNameChange = async (name:any) => {
|
||||||
|
console.log('name change requested',name);
|
||||||
|
|
||||||
|
if (await sendInputes(selections, duration, name)) {
|
||||||
|
setWidgetName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="inputs-wrapper">
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Title</div>
|
||||||
|
<RenameInput value={selectedChartId?.header || "untited"} onRename={handleNameChange}/>
|
||||||
|
</div>
|
||||||
|
{[...Array(1)].map((_, index) => {
|
||||||
|
const inputKey = `input${index + 1}`;
|
||||||
|
return (
|
||||||
|
<div key={index} className="datas">
|
||||||
|
<div className="datas__label">Input {index + 1}</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<MultiLevelDropdown
|
||||||
|
data={dropDowndata}
|
||||||
|
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||||
|
onUnselect={() => handleSelect(inputKey, null)}
|
||||||
|
selectedValue={selections[inputKey]} // Load from Zustand
|
||||||
|
/>
|
||||||
|
<div className="icon">
|
||||||
|
<AddIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{/* <div className="datas">
|
||||||
|
<div className="datas__label">Duration</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<RegularDropDown
|
||||||
|
header={duration}
|
||||||
|
options={["1h", "2h", "12h"]}
|
||||||
|
onSelect={handleSelectDuration}
|
||||||
|
search={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div> */}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FleetEfficiencyInputComponent;
|
|
@ -12,7 +12,7 @@ type Props = {};
|
||||||
|
|
||||||
const FlotingWidgetInput = (props: Props) => {
|
const FlotingWidgetInput = (props: Props) => {
|
||||||
const [widgetName, setWidgetName] = useState('Widget');
|
const [widgetName, setWidgetName] = useState('Widget');
|
||||||
const { setMeasurements, updateDuration, updateName } = useChartStore();
|
const { setFlotingMeasurements, updateFlotingDuration, updateHeader } = useChartStore();
|
||||||
const [duration, setDuration] = useState('1h')
|
const [duration, setDuration] = useState('1h')
|
||||||
const [dropDowndata, setDropDownData] = useState({});
|
const [dropDowndata, setDropDownData] = useState({});
|
||||||
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||||
|
@ -43,11 +43,13 @@ const FlotingWidgetInput = (props: Props) => {
|
||||||
const fetchSavedInputes = async () => {
|
const fetchSavedInputes = async () => {
|
||||||
if (selectedChartId.id !== "") {
|
if (selectedChartId.id !== "") {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`);
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
|
console.log(response.data);
|
||||||
|
|
||||||
setSelections(response.data.Data.measurements)
|
setSelections(response.data.Data.measurements)
|
||||||
setDuration(response.data.Data.duration)
|
setDuration(response.data.Data.duration)
|
||||||
setWidgetName(response.data.widgetName)
|
setWidgetName(response.data.header)
|
||||||
} else {
|
} else {
|
||||||
console.log("Unexpected response:", response);
|
console.log("Unexpected response:", response);
|
||||||
}
|
}
|
||||||
|
@ -63,9 +65,9 @@ const FlotingWidgetInput = (props: Props) => {
|
||||||
|
|
||||||
// Sync Zustand state when component mounts
|
// Sync Zustand state when component mounts
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMeasurements(selections);
|
setFlotingMeasurements(selections);
|
||||||
updateDuration(duration);
|
updateFlotingDuration(duration);
|
||||||
updateName(widgetName);
|
updateHeader(widgetName);
|
||||||
}, [selections, duration, widgetName]);
|
}, [selections, duration, widgetName]);
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,8 +78,7 @@ const FlotingWidgetInput = (props: Props) => {
|
||||||
zoneId: selectedZone.zoneId,
|
zoneId: selectedZone.zoneId,
|
||||||
widget: {
|
widget: {
|
||||||
id: selectedChartId.id,
|
id: selectedChartId.id,
|
||||||
panel: selectedChartId.panel,
|
header: inputName,
|
||||||
widgetName: inputName,
|
|
||||||
Data: {
|
Data: {
|
||||||
measurements: inputMeasurement,
|
measurements: inputMeasurement,
|
||||||
duration: inputDuration
|
duration: inputDuration
|
||||||
|
@ -135,7 +136,7 @@ const FlotingWidgetInput = (props: Props) => {
|
||||||
<div className="inputs-wrapper">
|
<div className="inputs-wrapper">
|
||||||
<div className="datas">
|
<div className="datas">
|
||||||
<div className="datas__label">Title</div>
|
<div className="datas__label">Title</div>
|
||||||
<RenameInput value={selectedChartId?.title || "untited"} onRename={handleNameChange}/>
|
<RenameInput value={selectedChartId?.header || "untited"} onRename={handleNameChange}/>
|
||||||
</div>
|
</div>
|
||||||
{[...Array(6)].map((_, index) => {
|
{[...Array(6)].map((_, index) => {
|
||||||
const inputKey = `input${index + 1}`;
|
const inputKey = `input${index + 1}`;
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
import React from 'react'
|
||||||
|
import LineGrapInput from './LineGrapInput'
|
||||||
|
import BarChartInput from './BarChartInput'
|
||||||
|
import PieChartInput from './PieChartInput'
|
||||||
|
import FlotingWidgetInput from './FlotingWidgetInput'
|
||||||
|
import FleetEfficiencyInputComponent from './FleetEfficiencyInputComponent'
|
||||||
|
import Progress1Input from './Progress1Input'
|
||||||
|
import Progress2Input from './Progress2Input'
|
||||||
|
import Widget2InputCard3D from './Widget2InputCard3D'
|
||||||
|
import Widget3InputCard3D from './Widget3InputCard3D'
|
||||||
|
import Widget4InputCard3D from './Widget4InputCard3D'
|
||||||
|
import WarehouseThroughputInputComponent from './WarehouseThroughputInputComponent'
|
||||||
|
import { useWidgetStore } from '../../../../../store/useWidgetStore'
|
||||||
|
|
||||||
|
const InputSelecterComponent = () => {
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
console.log('selectedChartId:',selectedChartId);
|
||||||
|
|
||||||
|
|
||||||
|
if (selectedChartId && selectedChartId.type && selectedChartId.type === 'bar' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">2D Widget Input</div>
|
||||||
|
<BarChartInput />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'line' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">2D Widget Input</div>
|
||||||
|
<LineGrapInput />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'pie' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">2D Widget Input</div>
|
||||||
|
<PieChartInput />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'doughnut' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">2D Widget Input</div>
|
||||||
|
<PieChartInput />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'polarArea' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">2D Widget Input</div>
|
||||||
|
<PieChartInput />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'progress 1' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">2D Widget Input</div>
|
||||||
|
<Progress1Input />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'progress 2' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">2D Widget Input</div>
|
||||||
|
<Progress2Input />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'warehouseThroughput floating' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">Floting Widget Input</div>
|
||||||
|
<WarehouseThroughputInputComponent />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'fleetEfficiency floating' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">Floting Widget Input</div>
|
||||||
|
<FleetEfficiencyInputComponent />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'floating total-card' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">Floting Widget Input</div>
|
||||||
|
<FleetEfficiencyInputComponent />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'ui-Widget 1' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">3D Widget Input</div>
|
||||||
|
<Widget4InputCard3D />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'ui-Widget 2' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">3D Widget Input</div>
|
||||||
|
<Widget2InputCard3D />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'ui-Widget 3' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">3D Widget Input</div>
|
||||||
|
<Widget3InputCard3D />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'ui-Widget 4' ) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="sideBarHeader">3D Widget Input</div>
|
||||||
|
<Widget4InputCard3D />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
return (
|
||||||
|
<div>No chart selected</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InputSelecterComponent
|
|
@ -256,7 +256,7 @@ const LineGrapInput = (props: Props) => {
|
||||||
<div className="datas__label">Title</div>
|
<div className="datas__label">Title</div>
|
||||||
<RenameInput value={selectedChartId?.title || "untited"} onRename={handleNameChange}/>
|
<RenameInput value={selectedChartId?.title || "untited"} onRename={handleNameChange}/>
|
||||||
</div>
|
</div>
|
||||||
{[...Array(6)].map((_, index) => {
|
{[...Array(4)].map((_, index) => {
|
||||||
const inputKey = `input${index + 1}`;
|
const inputKey = `input${index + 1}`;
|
||||||
return (
|
return (
|
||||||
<div key={index} className="datas">
|
<div key={index} className="datas">
|
||||||
|
|
|
@ -1,78 +1,177 @@
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from "react";
|
||||||
import MultiLevelDropdown from '../../../../ui/inputs/MultiLevelDropDown'
|
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||||
import { AddIcon } from '../../../../icons/ExportCommonIcons'
|
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||||
import axios from 'axios'
|
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||||
|
import useChartStore from "../../../../../store/useChartStore";
|
||||||
|
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
|
||||||
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||||
|
|
||||||
type Props = {}
|
type Props = {};
|
||||||
|
|
||||||
const PieChartInput = (props: Props) => {
|
const PieChartInput = (props: Props) => {
|
||||||
const [dropDowndata, setDropDownData] = useState({})
|
const [widgetName, setWidgetName] = useState('Widget');
|
||||||
const [selections, setSelections] = useState<Record<string, {name: string, fields: string}>>({})
|
const { setMeasurements, updateDuration, updateName } = useChartStore();
|
||||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
const [duration, setDuration] = useState('1h')
|
||||||
|
const [dropDowndata, setDropDownData] = useState({});
|
||||||
|
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||||
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchZoneData = async () => {
|
const fetchZoneData = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
console.log('dropdown data:', response.data);
|
// console.log("dropdown data:", response.data);
|
||||||
setDropDownData(response.data)
|
setDropDownData(response.data);
|
||||||
} else {
|
} else {
|
||||||
console.log('Unexpected response:', response);
|
console.log("Unexpected response:", response);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('There was an error!', error);
|
console.error("There was an error!", error);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
fetchZoneData();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {console.log(selections);
|
|
||||||
},[selections])
|
|
||||||
|
|
||||||
const handleSelect = (inputKey: string, selectedData: {name: string, fields: string} | null) => {
|
|
||||||
setSelections(prev => {
|
|
||||||
if (selectedData === null) {
|
|
||||||
const newSelections = {...prev};
|
|
||||||
delete newSelections[inputKey];
|
|
||||||
return newSelections;
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
...prev,
|
|
||||||
[inputKey]: selectedData
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
fetchZoneData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
useEffect(() => {
|
||||||
<>
|
const fetchSavedInputes = async () => {
|
||||||
<div className="inputs-wrapper">
|
if (selectedChartId.id !== "") {
|
||||||
{[...Array(3)].map((_, index) => {
|
try {
|
||||||
const inputKey = `input${index+1}`;
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`);
|
||||||
return (
|
if (response.status === 200) {
|
||||||
<div key={index} className="datas">
|
setSelections(response.data.Data.measurements)
|
||||||
<div className="datas__label">Input {index+1}</div>
|
setDuration(response.data.Data.duration)
|
||||||
<div className="datas__class">
|
setWidgetName(response.data.widgetName)
|
||||||
<MultiLevelDropdown
|
} else {
|
||||||
data={dropDowndata}
|
console.log("Unexpected response:", response);
|
||||||
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
}
|
||||||
onUnselect={() => handleSelect(inputKey, null)}
|
} catch (error) {
|
||||||
selectedValue={selections[inputKey]}
|
console.error("There was an error!", error);
|
||||||
/>
|
}
|
||||||
<div className="icon">
|
}
|
||||||
<AddIcon />
|
}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PieChartInput
|
fetchSavedInputes();
|
||||||
|
|
||||||
|
}, [selectedChartId.id]);
|
||||||
|
|
||||||
|
// Sync Zustand state when component mounts
|
||||||
|
useEffect(() => {
|
||||||
|
setMeasurements(selections);
|
||||||
|
updateDuration(duration);
|
||||||
|
updateName(widgetName);
|
||||||
|
}, [selections, duration, widgetName]);
|
||||||
|
|
||||||
|
|
||||||
|
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, {
|
||||||
|
organization: organization,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
widget: {
|
||||||
|
id: selectedChartId.id,
|
||||||
|
panel: selectedChartId.panel,
|
||||||
|
widgetName: inputName,
|
||||||
|
Data: {
|
||||||
|
measurements: inputMeasurement,
|
||||||
|
duration: inputDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any);
|
||||||
|
if (response.status === 200) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||||
|
|
||||||
|
// async() => {
|
||||||
|
const newSelections = { ...selections };
|
||||||
|
if (selectedData === null) {
|
||||||
|
delete newSelections[inputKey];
|
||||||
|
} else {
|
||||||
|
newSelections[inputKey] = selectedData;
|
||||||
|
}
|
||||||
|
// setMeasurements(newSelections); // Update Zustand store
|
||||||
|
console.log(newSelections);
|
||||||
|
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||||
|
setSelections(newSelections);
|
||||||
|
}
|
||||||
|
// sendInputes(newSelections, duration); // Send data to server
|
||||||
|
// return newSelections;
|
||||||
|
// };
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectDuration = async (option: string) => {
|
||||||
|
if (await sendInputes(selections, option, widgetName)) {
|
||||||
|
setDuration(option);
|
||||||
|
}
|
||||||
|
// setDuration(option);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNameChange = async (name:any) => {
|
||||||
|
console.log('name change requested',name);
|
||||||
|
|
||||||
|
if (await sendInputes(selections, duration, name)) {
|
||||||
|
setWidgetName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="inputs-wrapper">
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Title</div>
|
||||||
|
<RenameInput value={selectedChartId?.title || "untited"} onRename={handleNameChange}/>
|
||||||
|
</div>
|
||||||
|
{[...Array(2)].map((_, index) => {
|
||||||
|
const inputKey = `input${index + 1}`;
|
||||||
|
return (
|
||||||
|
<div key={index} className="datas">
|
||||||
|
<div className="datas__label">Input {index + 1}</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<MultiLevelDropdown
|
||||||
|
data={dropDowndata}
|
||||||
|
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||||
|
onUnselect={() => handleSelect(inputKey, null)}
|
||||||
|
selectedValue={selections[inputKey]} // Load from Zustand
|
||||||
|
/>
|
||||||
|
<div className="icon">
|
||||||
|
<AddIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Duration</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<RegularDropDown
|
||||||
|
header={duration}
|
||||||
|
options={["1h", "2h", "12h"]}
|
||||||
|
onSelect={handleSelectDuration}
|
||||||
|
search={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PieChartInput;
|
|
@ -0,0 +1,171 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||||
|
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||||
|
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||||
|
import useChartStore from "../../../../../store/useChartStore";
|
||||||
|
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
|
||||||
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||||
|
|
||||||
|
type Props = {};
|
||||||
|
|
||||||
|
const Progress1Input = (props: Props) => {
|
||||||
|
const [widgetName, setWidgetName] = useState('Widget');
|
||||||
|
const { setMeasurements, updateDuration, updateName } = useChartStore();
|
||||||
|
const [duration, setDuration] = useState('1h')
|
||||||
|
const [dropDowndata, setDropDownData] = useState({});
|
||||||
|
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||||
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchZoneData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
// console.log("dropdown data:", response.data);
|
||||||
|
setDropDownData(response.data);
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchZoneData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchSavedInputes = async () => {
|
||||||
|
if (selectedChartId.id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setSelections(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setWidgetName(response.data.widgetName)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchSavedInputes();
|
||||||
|
|
||||||
|
}, [selectedChartId.id]);
|
||||||
|
|
||||||
|
// Sync Zustand state when component mounts
|
||||||
|
useEffect(() => {
|
||||||
|
setMeasurements(selections);
|
||||||
|
updateDuration(duration);
|
||||||
|
updateName(widgetName);
|
||||||
|
}, [selections, duration, widgetName]);
|
||||||
|
|
||||||
|
|
||||||
|
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, {
|
||||||
|
organization: organization,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
widget: {
|
||||||
|
id: selectedChartId.id,
|
||||||
|
panel: selectedChartId.panel,
|
||||||
|
widgetName: inputName,
|
||||||
|
Data: {
|
||||||
|
measurements: inputMeasurement,
|
||||||
|
duration: inputDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any);
|
||||||
|
if (response.status === 200) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||||
|
|
||||||
|
// async() => {
|
||||||
|
const newSelections = { ...selections };
|
||||||
|
if (selectedData === null) {
|
||||||
|
delete newSelections[inputKey];
|
||||||
|
} else {
|
||||||
|
newSelections[inputKey] = selectedData;
|
||||||
|
}
|
||||||
|
// setMeasurements(newSelections); // Update Zustand store
|
||||||
|
console.log(newSelections);
|
||||||
|
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||||
|
setSelections(newSelections);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectDuration = async (option: string) => {
|
||||||
|
if (await sendInputes(selections, option, widgetName)) {
|
||||||
|
setDuration(option);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNameChange = async (name:any) => {
|
||||||
|
if (await sendInputes(selections, duration, name)) {
|
||||||
|
setWidgetName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="inputs-wrapper">
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Title</div>
|
||||||
|
<RenameInput value={selectedChartId?.title || "untited"} onRename={handleNameChange}/>
|
||||||
|
</div>
|
||||||
|
{[...Array(1)].map((_, index) => {
|
||||||
|
const inputKey = `input${index + 1}`;
|
||||||
|
return (
|
||||||
|
<div key={index} className="datas">
|
||||||
|
<div className="datas__label">Input {index + 1}</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<MultiLevelDropdown
|
||||||
|
data={dropDowndata}
|
||||||
|
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||||
|
onUnselect={() => handleSelect(inputKey, null)}
|
||||||
|
selectedValue={selections[inputKey]} // Load from Zustand
|
||||||
|
/>
|
||||||
|
<div className="icon">
|
||||||
|
<AddIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{/* <div>
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Duration</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<RegularDropDown
|
||||||
|
header={duration}
|
||||||
|
options={["1h", "2h", "12h"]}
|
||||||
|
onSelect={handleSelectDuration}
|
||||||
|
search={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> */}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Progress1Input;
|
|
@ -0,0 +1,171 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||||
|
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||||
|
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||||
|
import useChartStore from "../../../../../store/useChartStore";
|
||||||
|
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
|
||||||
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||||
|
|
||||||
|
type Props = {};
|
||||||
|
|
||||||
|
const Progress2Input = (props: Props) => {
|
||||||
|
const [widgetName, setWidgetName] = useState('Widget');
|
||||||
|
const { setMeasurements, updateDuration, updateName } = useChartStore();
|
||||||
|
const [duration, setDuration] = useState('1h')
|
||||||
|
const [dropDowndata, setDropDownData] = useState({});
|
||||||
|
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||||
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchZoneData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
// console.log("dropdown data:", response.data);
|
||||||
|
setDropDownData(response.data);
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchZoneData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchSavedInputes = async () => {
|
||||||
|
if (selectedChartId.id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setSelections(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setWidgetName(response.data.widgetName)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchSavedInputes();
|
||||||
|
|
||||||
|
}, [selectedChartId.id]);
|
||||||
|
|
||||||
|
// Sync Zustand state when component mounts
|
||||||
|
useEffect(() => {
|
||||||
|
setMeasurements(selections);
|
||||||
|
updateDuration(duration);
|
||||||
|
updateName(widgetName);
|
||||||
|
}, [selections, duration, widgetName]);
|
||||||
|
|
||||||
|
|
||||||
|
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, {
|
||||||
|
organization: organization,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
widget: {
|
||||||
|
id: selectedChartId.id,
|
||||||
|
panel: selectedChartId.panel,
|
||||||
|
widgetName: inputName,
|
||||||
|
Data: {
|
||||||
|
measurements: inputMeasurement,
|
||||||
|
duration: inputDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any);
|
||||||
|
if (response.status === 200) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||||
|
|
||||||
|
// async() => {
|
||||||
|
const newSelections = { ...selections };
|
||||||
|
if (selectedData === null) {
|
||||||
|
delete newSelections[inputKey];
|
||||||
|
} else {
|
||||||
|
newSelections[inputKey] = selectedData;
|
||||||
|
}
|
||||||
|
// setMeasurements(newSelections); // Update Zustand store
|
||||||
|
console.log(newSelections);
|
||||||
|
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||||
|
setSelections(newSelections);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectDuration = async (option: string) => {
|
||||||
|
if (await sendInputes(selections, option, widgetName)) {
|
||||||
|
setDuration(option);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNameChange = async (name:any) => {
|
||||||
|
if (await sendInputes(selections, duration, name)) {
|
||||||
|
setWidgetName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="inputs-wrapper">
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Title</div>
|
||||||
|
<RenameInput value={selectedChartId?.title || "untited"} onRename={handleNameChange}/>
|
||||||
|
</div>
|
||||||
|
{[...Array(2)].map((_, index) => {
|
||||||
|
const inputKey = `input${index + 1}`;
|
||||||
|
return (
|
||||||
|
<div key={index} className="datas">
|
||||||
|
<div className="datas__label">Input {index + 1}</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<MultiLevelDropdown
|
||||||
|
data={dropDowndata}
|
||||||
|
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||||
|
onUnselect={() => handleSelect(inputKey, null)}
|
||||||
|
selectedValue={selections[inputKey]} // Load from Zustand
|
||||||
|
/>
|
||||||
|
<div className="icon">
|
||||||
|
<AddIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{/* <div>
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Duration</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<RegularDropDown
|
||||||
|
header={duration}
|
||||||
|
options={["1h", "2h", "12h"]}
|
||||||
|
onSelect={handleSelectDuration}
|
||||||
|
search={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> */}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Progress2Input;
|
|
@ -0,0 +1,178 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||||
|
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||||
|
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||||
|
import useChartStore from "../../../../../store/useChartStore";
|
||||||
|
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
|
||||||
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||||
|
|
||||||
|
type Props = {};
|
||||||
|
|
||||||
|
const WarehouseThroughputInputComponent = (props: Props) => {
|
||||||
|
const [widgetName, setWidgetName] = useState('Widget');
|
||||||
|
const { setFlotingMeasurements, updateFlotingDuration, updateHeader } = useChartStore();
|
||||||
|
const [duration, setDuration] = useState('1h')
|
||||||
|
const [dropDowndata, setDropDownData] = useState({});
|
||||||
|
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||||
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchZoneData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
// console.log("dropdown data:", response.data);
|
||||||
|
setDropDownData(response.data);
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchZoneData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchSavedInputes = async () => {
|
||||||
|
if (selectedChartId.id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
console.log(response.data);
|
||||||
|
|
||||||
|
setSelections(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setWidgetName(response.data.header)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchSavedInputes();
|
||||||
|
|
||||||
|
}, [selectedChartId.id]);
|
||||||
|
|
||||||
|
// Sync Zustand state when component mounts
|
||||||
|
useEffect(() => {
|
||||||
|
setFlotingMeasurements(selections);
|
||||||
|
updateFlotingDuration(duration);
|
||||||
|
updateHeader(widgetName);
|
||||||
|
}, [selections, duration, widgetName]);
|
||||||
|
|
||||||
|
|
||||||
|
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/floatwidget/save`, {
|
||||||
|
organization: organization,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
widget: {
|
||||||
|
id: selectedChartId.id,
|
||||||
|
header: inputName,
|
||||||
|
Data: {
|
||||||
|
measurements: inputMeasurement,
|
||||||
|
duration: inputDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any);
|
||||||
|
if (response.status === 200) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||||
|
|
||||||
|
// async() => {
|
||||||
|
const newSelections = { ...selections };
|
||||||
|
if (selectedData === null) {
|
||||||
|
delete newSelections[inputKey];
|
||||||
|
} else {
|
||||||
|
newSelections[inputKey] = selectedData;
|
||||||
|
}
|
||||||
|
// setMeasurements(newSelections); // Update Zustand store
|
||||||
|
console.log(newSelections);
|
||||||
|
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||||
|
setSelections(newSelections);
|
||||||
|
}
|
||||||
|
// sendInputes(newSelections, duration); // Send data to server
|
||||||
|
// return newSelections;
|
||||||
|
// };
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectDuration = async (option: string) => {
|
||||||
|
if (await sendInputes(selections, option, widgetName)) {
|
||||||
|
setDuration(option);
|
||||||
|
}
|
||||||
|
// setDuration(option);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNameChange = async (name:any) => {
|
||||||
|
console.log('name change requested',name);
|
||||||
|
|
||||||
|
if (await sendInputes(selections, duration, name)) {
|
||||||
|
setWidgetName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="inputs-wrapper">
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Title</div>
|
||||||
|
<RenameInput value={selectedChartId?.header || "untited"} onRename={handleNameChange}/>
|
||||||
|
</div>
|
||||||
|
{[...Array(1)].map((_, index) => {
|
||||||
|
const inputKey = `input${index + 1}`;
|
||||||
|
return (
|
||||||
|
<div key={index} className="datas">
|
||||||
|
<div className="datas__label">Input {index + 1}</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<MultiLevelDropdown
|
||||||
|
data={dropDowndata}
|
||||||
|
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||||
|
onUnselect={() => handleSelect(inputKey, null)}
|
||||||
|
selectedValue={selections[inputKey]} // Load from Zustand
|
||||||
|
/>
|
||||||
|
<div className="icon">
|
||||||
|
<AddIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Duration</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<RegularDropDown
|
||||||
|
header={duration}
|
||||||
|
options={["1h", "2h", "12h"]}
|
||||||
|
onSelect={handleSelectDuration}
|
||||||
|
search={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WarehouseThroughputInputComponent;
|
|
@ -0,0 +1,165 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||||
|
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||||
|
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||||
|
import useChartStore from "../../../../../store/useChartStore";
|
||||||
|
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
|
||||||
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||||
|
|
||||||
|
type Props = {};
|
||||||
|
|
||||||
|
const Widget2InputCard3D = (props: Props) => {
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
const [widgetName, setWidgetName] = useState("untited");
|
||||||
|
const { setMeasurements, updateDuration, updateName } = useChartStore();
|
||||||
|
const [duration, setDuration] = useState('1h')
|
||||||
|
const [dropDowndata, setDropDownData] = useState({});
|
||||||
|
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||||
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
console.log(selectedChartId);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchZoneData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
// console.log("dropdown data:", response.data);
|
||||||
|
setDropDownData(response.data);
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchZoneData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchSavedInputes = async () => {
|
||||||
|
if (selectedChartId.id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${selectedChartId.id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setSelections(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setWidgetName(response.data.widgetName)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchSavedInputes();
|
||||||
|
|
||||||
|
}, [selectedChartId.id]);
|
||||||
|
|
||||||
|
// Sync Zustand state when component mounts
|
||||||
|
useEffect(() => {
|
||||||
|
setMeasurements(selections);
|
||||||
|
updateDuration(duration);
|
||||||
|
updateName(widgetName);
|
||||||
|
}, [selections, duration, widgetName]);
|
||||||
|
|
||||||
|
|
||||||
|
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/3dwidget/save`, {
|
||||||
|
organization: organization,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
widget: {
|
||||||
|
id: selectedChartId.id,
|
||||||
|
widgetName: inputName,
|
||||||
|
Data: {
|
||||||
|
measurements: inputMeasurement,
|
||||||
|
duration: inputDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any);
|
||||||
|
if (response.status === 200) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||||
|
|
||||||
|
// async() => {
|
||||||
|
const newSelections = { ...selections };
|
||||||
|
if (selectedData === null) {
|
||||||
|
delete newSelections[inputKey];
|
||||||
|
} else {
|
||||||
|
newSelections[inputKey] = selectedData;
|
||||||
|
}
|
||||||
|
// setMeasurements(newSelections); // Update Zustand store
|
||||||
|
console.log(newSelections);
|
||||||
|
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||||
|
setSelections(newSelections);
|
||||||
|
}
|
||||||
|
// sendInputes(newSelections, duration); // Send data to server
|
||||||
|
// return newSelections;
|
||||||
|
// };
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectDuration = async (option: string) => {
|
||||||
|
if (await sendInputes(selections, option, widgetName)) {
|
||||||
|
setDuration(option);
|
||||||
|
}
|
||||||
|
// setDuration(option);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNameChange = async (name:any) => {
|
||||||
|
console.log('name change requested',name);
|
||||||
|
|
||||||
|
if (await sendInputes(selections, duration, name)) {
|
||||||
|
setWidgetName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="inputs-wrapper">
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Title</div>
|
||||||
|
<RenameInput value={widgetName} onRename={handleNameChange}/>
|
||||||
|
</div>
|
||||||
|
{[...Array(2)].map((_, index) => {
|
||||||
|
const inputKey = `input${index + 1}`;
|
||||||
|
return (
|
||||||
|
<div key={index} className="datas">
|
||||||
|
<div className="datas__label">Input {index + 1}</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<MultiLevelDropdown
|
||||||
|
data={dropDowndata}
|
||||||
|
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||||
|
onUnselect={() => handleSelect(inputKey, null)}
|
||||||
|
selectedValue={selections[inputKey]} // Load from Zustand
|
||||||
|
/>
|
||||||
|
<div className="icon">
|
||||||
|
<AddIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Widget2InputCard3D;
|
|
@ -0,0 +1,158 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||||
|
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||||
|
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||||
|
import useChartStore from "../../../../../store/useChartStore";
|
||||||
|
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
|
||||||
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||||
|
|
||||||
|
const Widget3InputCard3D = () => {
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
const [widgetName, setWidgetName] = useState("untited");
|
||||||
|
const { setMeasurements, updateDuration, updateName } = useChartStore();
|
||||||
|
const [duration, setDuration] = useState('1h')
|
||||||
|
const [dropDowndata, setDropDownData] = useState({});
|
||||||
|
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||||
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
console.log(selectedChartId);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchZoneData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
// console.log("dropdown data:", response.data);
|
||||||
|
setDropDownData(response.data);
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchZoneData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchSavedInputes = async () => {
|
||||||
|
if (selectedChartId.id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${selectedChartId.id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setSelections(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setWidgetName(response.data.widgetName)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchSavedInputes();
|
||||||
|
|
||||||
|
}, [selectedChartId.id]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMeasurements(selections);
|
||||||
|
updateDuration(duration);
|
||||||
|
updateName(widgetName);
|
||||||
|
}, [selections, duration, widgetName]);
|
||||||
|
|
||||||
|
|
||||||
|
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/3dwidget/save`, {
|
||||||
|
organization: organization,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
widget: {
|
||||||
|
id: selectedChartId.id,
|
||||||
|
widgetName: inputName,
|
||||||
|
Data: {
|
||||||
|
measurements: inputMeasurement,
|
||||||
|
duration: inputDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any);
|
||||||
|
if (response.status === 200) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||||
|
|
||||||
|
// async() => {
|
||||||
|
const newSelections = { ...selections };
|
||||||
|
if (selectedData === null) {
|
||||||
|
delete newSelections[inputKey];
|
||||||
|
} else {
|
||||||
|
newSelections[inputKey] = selectedData;
|
||||||
|
}
|
||||||
|
// setMeasurements(newSelections); // Update Zustand store
|
||||||
|
console.log(newSelections);
|
||||||
|
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||||
|
setSelections(newSelections);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectDuration = async (option: string) => {
|
||||||
|
if (await sendInputes(selections, option, widgetName)) {
|
||||||
|
setDuration(option);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNameChange = async (name:any) => {
|
||||||
|
console.log('name change requested',name);
|
||||||
|
|
||||||
|
if (await sendInputes(selections, duration, name)) {
|
||||||
|
setWidgetName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="inputs-wrapper">
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Title</div>
|
||||||
|
<RenameInput value={widgetName} onRename={handleNameChange}/>
|
||||||
|
</div>
|
||||||
|
{[...Array(7)].map((_, index) => {
|
||||||
|
const inputKey = `input${index + 1}`;
|
||||||
|
return (
|
||||||
|
<div key={index} className="datas">
|
||||||
|
<div className="datas__label">Input {index + 1}</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<MultiLevelDropdown
|
||||||
|
data={dropDowndata}
|
||||||
|
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||||
|
onUnselect={() => handleSelect(inputKey, null)}
|
||||||
|
selectedValue={selections[inputKey]} // Load from Zustand
|
||||||
|
/>
|
||||||
|
<div className="icon">
|
||||||
|
<AddIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Widget3InputCard3D;
|
|
@ -0,0 +1,178 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||||
|
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||||
|
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||||
|
import useChartStore from "../../../../../store/useChartStore";
|
||||||
|
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
|
||||||
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||||
|
|
||||||
|
type Props = {};
|
||||||
|
|
||||||
|
const Widget4InputCard3D = (props: Props) => {
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
const [widgetName, setWidgetName] = useState("untited");
|
||||||
|
const { setMeasurements, updateDuration, updateName } = useChartStore();
|
||||||
|
const [duration, setDuration] = useState('1h')
|
||||||
|
const [dropDowndata, setDropDownData] = useState({});
|
||||||
|
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||||
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
console.log(selectedChartId);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchZoneData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
// console.log("dropdown data:", response.data);
|
||||||
|
setDropDownData(response.data);
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchZoneData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchSavedInputes = async () => {
|
||||||
|
if (selectedChartId.id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${selectedChartId.id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setSelections(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setWidgetName(response.data.widgetName)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchSavedInputes();
|
||||||
|
|
||||||
|
}, [selectedChartId.id]);
|
||||||
|
|
||||||
|
// Sync Zustand state when component mounts
|
||||||
|
useEffect(() => {
|
||||||
|
setMeasurements(selections);
|
||||||
|
updateDuration(duration);
|
||||||
|
updateName(widgetName);
|
||||||
|
}, [selections, duration, widgetName]);
|
||||||
|
|
||||||
|
|
||||||
|
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/3dwidget/save`, {
|
||||||
|
organization: organization,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
widget: {
|
||||||
|
id: selectedChartId.id,
|
||||||
|
widgetName: inputName,
|
||||||
|
Data: {
|
||||||
|
measurements: inputMeasurement,
|
||||||
|
duration: inputDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any);
|
||||||
|
if (response.status === 200) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||||
|
|
||||||
|
// async() => {
|
||||||
|
const newSelections = { ...selections };
|
||||||
|
if (selectedData === null) {
|
||||||
|
delete newSelections[inputKey];
|
||||||
|
} else {
|
||||||
|
newSelections[inputKey] = selectedData;
|
||||||
|
}
|
||||||
|
// setMeasurements(newSelections); // Update Zustand store
|
||||||
|
console.log(newSelections);
|
||||||
|
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||||
|
setSelections(newSelections);
|
||||||
|
}
|
||||||
|
// sendInputes(newSelections, duration); // Send data to server
|
||||||
|
// return newSelections;
|
||||||
|
// };
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectDuration = async (option: string) => {
|
||||||
|
if (await sendInputes(selections, option, widgetName)) {
|
||||||
|
setDuration(option);
|
||||||
|
}
|
||||||
|
// setDuration(option);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNameChange = async (name:any) => {
|
||||||
|
console.log('name change requested',name);
|
||||||
|
|
||||||
|
if (await sendInputes(selections, duration, name)) {
|
||||||
|
setWidgetName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="inputs-wrapper">
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Title</div>
|
||||||
|
<RenameInput value={widgetName} onRename={handleNameChange}/>
|
||||||
|
</div>
|
||||||
|
{[...Array(1)].map((_, index) => {
|
||||||
|
const inputKey = `input${index + 1}`;
|
||||||
|
return (
|
||||||
|
<div key={index} className="datas">
|
||||||
|
<div className="datas__label">Input {index + 1}</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<MultiLevelDropdown
|
||||||
|
data={dropDowndata}
|
||||||
|
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||||
|
onUnselect={() => handleSelect(inputKey, null)}
|
||||||
|
selectedValue={selections[inputKey]} // Load from Zustand
|
||||||
|
/>
|
||||||
|
<div className="icon">
|
||||||
|
<AddIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="datas">
|
||||||
|
<div className="datas__label">Duration</div>
|
||||||
|
<div className="datas__class">
|
||||||
|
<RegularDropDown
|
||||||
|
header={duration}
|
||||||
|
options={["1h", "2h", "12h"]}
|
||||||
|
onSelect={handleSelectDuration}
|
||||||
|
search={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Widget4InputCard3D;
|
|
@ -4,6 +4,7 @@ import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons";
|
||||||
import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown";
|
import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||||
import LineGrapInput from "../IotInputCards/LineGrapInput";
|
import LineGrapInput from "../IotInputCards/LineGrapInput";
|
||||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||||
|
import InputSelecterComponent from "../IotInputCards/InputSelecterComponent";
|
||||||
|
|
||||||
// Define the data structure for demonstration purposes
|
// Define the data structure for demonstration purposes
|
||||||
const DATA_STRUCTURE = {
|
const DATA_STRUCTURE = {
|
||||||
|
@ -118,7 +119,7 @@ const Data = () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// console.log("selectedChartId", selectedChartId);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dataSideBar">
|
<div className="dataSideBar">
|
||||||
|
@ -133,8 +134,7 @@ const Data = () => {
|
||||||
{
|
{
|
||||||
chartDataGroups[selectedChartId?.id] &&
|
chartDataGroups[selectedChartId?.id] &&
|
||||||
<>
|
<>
|
||||||
<div className="sideBarHeader">2D Widget Input</div>
|
<InputSelecterComponent />
|
||||||
<LineGrapInput />
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import RenderOverlay from "./Overlay";
|
import RenderOverlay from "./Overlay";
|
||||||
import { ArrowIcon, CloseIcon } from "../icons/ExportCommonIcons";
|
import { ArrowIcon, CloseIcon } from "../icons/ExportCommonIcons";
|
||||||
import { AccessOption, User } from "../../types/users";
|
import { AccessOption, User } from "../../types/users";
|
||||||
import RegularDropDown from "../ui/inputs/RegularDropDown";
|
import RegularDropDown from "../ui/inputs/RegularDropDown";
|
||||||
import { access } from "fs";
|
import { access } from "fs";
|
||||||
import MultiEmailInvite from "../ui/inputs/MultiEmailInvite";
|
import MultiEmailInvite from "../ui/inputs/MultiEmailInvite";
|
||||||
|
import { useActiveUsers } from "../../store/store";
|
||||||
|
|
||||||
interface UserListTemplateProps {
|
interface UserListTemplateProps {
|
||||||
user: User;
|
user: User;
|
||||||
|
@ -57,6 +58,10 @@ interface CollaborateProps {
|
||||||
const CollaborationPopup: React.FC<CollaborateProps> = ({
|
const CollaborationPopup: React.FC<CollaborateProps> = ({
|
||||||
setUserManagement,
|
setUserManagement,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { activeUsers } = useActiveUsers();
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("activeUsers: ", activeUsers);
|
||||||
|
}, [activeUsers]);
|
||||||
const userName = localStorage.getItem("userName") || "Anonymous";
|
const userName = localStorage.getItem("userName") || "Anonymous";
|
||||||
const users = [
|
const users = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
CleanPannel,
|
CleanPannel,
|
||||||
EyeIcon,
|
EyeIcon,
|
||||||
|
@ -6,6 +6,8 @@ import {
|
||||||
} from "../../icons/RealTimeVisulationIcons";
|
} from "../../icons/RealTimeVisulationIcons";
|
||||||
import { panelData } from "../../../services/realTimeVisulization/zoneData/panel";
|
import { panelData } from "../../../services/realTimeVisulization/zoneData/panel";
|
||||||
import { AddIcon } from "../../icons/ExportCommonIcons";
|
import { AddIcon } from "../../icons/ExportCommonIcons";
|
||||||
|
import { deletePanelApi } from "../../../services/realTimeVisulization/zoneData/deletePanel";
|
||||||
|
import { useSocketStore } from "../../../store/store";
|
||||||
|
|
||||||
// Define the type for `Side`
|
// Define the type for `Side`
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
|
@ -16,7 +18,6 @@ interface ButtonsProps {
|
||||||
zoneName: string;
|
zoneName: string;
|
||||||
activeSides: Side[];
|
activeSides: Side[];
|
||||||
panelOrder: Side[];
|
panelOrder: Side[];
|
||||||
|
|
||||||
lockedPanels: Side[];
|
lockedPanels: Side[];
|
||||||
zoneId: string;
|
zoneId: string;
|
||||||
zoneViewPortTarget: number[];
|
zoneViewPortTarget: number[];
|
||||||
|
@ -34,7 +35,7 @@ interface ButtonsProps {
|
||||||
zoneName: string;
|
zoneName: string;
|
||||||
activeSides: Side[];
|
activeSides: Side[];
|
||||||
panelOrder: Side[];
|
panelOrder: Side[];
|
||||||
|
|
||||||
lockedPanels: Side[];
|
lockedPanels: Side[];
|
||||||
zoneId: string;
|
zoneId: string;
|
||||||
zoneViewPortTarget: number[];
|
zoneViewPortTarget: number[];
|
||||||
|
@ -58,6 +59,9 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
setHiddenPanels,
|
setHiddenPanels,
|
||||||
hiddenPanels,
|
hiddenPanels,
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
|
const { visualizationSocket } = useSocketStore();
|
||||||
|
|
||||||
// Local state to track hidden panels
|
// Local state to track hidden panels
|
||||||
|
|
||||||
// Function to toggle lock/unlock a panel
|
// Function to toggle lock/unlock a panel
|
||||||
|
@ -103,9 +107,13 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to handle "+" button click
|
// Function to handle "+" button click
|
||||||
const handlePlusButtonClick = (side: Side) => {
|
const handlePlusButtonClick = async (side: Side) => {
|
||||||
if (selectedZone.activeSides.includes(side)) {
|
if (selectedZone.activeSides.includes(side)) {
|
||||||
// If the panel is already active, remove all widgets and close the panel
|
// Panel already exists: Remove widgets from that side and update activeSides
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value
|
||||||
|
|
||||||
|
// Remove all widgets associated with the side and update active sides
|
||||||
const cleanedWidgets = selectedZone.widgets.filter(
|
const cleanedWidgets = selectedZone.widgets.filter(
|
||||||
(widget) => widget.panel !== side
|
(widget) => widget.panel !== side
|
||||||
);
|
);
|
||||||
|
@ -118,44 +126,68 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
panelOrder: newActiveSides,
|
panelOrder: newActiveSides,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Delete the selectedZone state
|
let deletePanel = {
|
||||||
|
organization: organization,
|
||||||
|
panelName: side,
|
||||||
|
zoneId: selectedZone.zoneId
|
||||||
|
}
|
||||||
|
if (visualizationSocket) {
|
||||||
|
visualizationSocket.emit("v2:viz-panel:delete", deletePanel)
|
||||||
|
}
|
||||||
setSelectedZone(updatedZone);
|
setSelectedZone(updatedZone);
|
||||||
|
|
||||||
|
// API call to delete the panel
|
||||||
|
// try {
|
||||||
|
// const response = await deletePanelApi(selectedZone.zoneId, side, organization);
|
||||||
|
//
|
||||||
|
// if (response.message === "Panel deleted successfully") {
|
||||||
|
// } else {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// } catch (error) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
} else {
|
} else {
|
||||||
const updatePanelData = async () => {
|
// Panel does not exist: Create panel
|
||||||
try {
|
try {
|
||||||
// Get email and organization safely
|
// Get email and organization safely with a default fallback
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg"; // Fallback value
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
|
||||||
// Prevent duplicate side entries
|
// Prevent duplicate side entries
|
||||||
const newActiveSides = selectedZone.activeSides.includes(side)
|
const newActiveSides = selectedZone.activeSides.includes(side)
|
||||||
? [...selectedZone.activeSides]
|
? [...selectedZone.activeSides]
|
||||||
: [...selectedZone.activeSides, side];
|
: [...selectedZone.activeSides, side];
|
||||||
|
|
||||||
const updatedZone = {
|
const updatedZone = {
|
||||||
...selectedZone,
|
...selectedZone,
|
||||||
activeSides: newActiveSides,
|
activeSides: newActiveSides,
|
||||||
panelOrder: newActiveSides,
|
panelOrder: newActiveSides,
|
||||||
};
|
};
|
||||||
|
let addPanel = {
|
||||||
// API call
|
organization: organization,
|
||||||
const response = await panelData(organization, selectedZone.zoneId, newActiveSides);
|
zoneId: selectedZone.zoneId,
|
||||||
|
panelOrder: newActiveSides
|
||||||
|
|
||||||
// Update state
|
|
||||||
|
|
||||||
setSelectedZone(updatedZone);
|
|
||||||
} catch (error) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
if (visualizationSocket) {
|
||||||
|
visualizationSocket.emit("v2:viz-panel:add", addPanel)
|
||||||
|
}
|
||||||
|
setSelectedZone(updatedZone);
|
||||||
|
// API call to create panels
|
||||||
|
// const response = await panelData(organization, selectedZone.zoneId, newActiveSides);
|
||||||
|
//
|
||||||
|
|
||||||
updatePanelData(); // Call the async function
|
// if (response.message === "Panels created successfully") {
|
||||||
|
// } else {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import React, { useEffect, useRef, useState, useCallback } from "react";
|
import React, { useEffect, useRef, useState, useCallback } from "react";
|
||||||
import { Widget } from "../../../store/useWidgetStore";
|
import { useWidgetStore, Widget } from "../../../store/useWidgetStore";
|
||||||
import { MoveArrowLeft, MoveArrowRight } from "../../icons/SimulationIcons";
|
import { MoveArrowLeft, MoveArrowRight } from "../../icons/SimulationIcons";
|
||||||
import { InfoIcon } from "../../icons/ExportCommonIcons";
|
import { InfoIcon } from "../../icons/ExportCommonIcons";
|
||||||
import { useDroppedObjectsStore, useFloatingWidget } from "../../../store/useDroppedObjectsStore";
|
import {
|
||||||
|
useDroppedObjectsStore,
|
||||||
|
useFloatingWidget,
|
||||||
|
} from "../../../store/useDroppedObjectsStore";
|
||||||
import { getSelect2dZoneData } from "../../../services/realTimeVisulization/zoneData/getSelect2dZoneData";
|
import { getSelect2dZoneData } from "../../../services/realTimeVisulization/zoneData/getSelect2dZoneData";
|
||||||
import { getFloatingZoneData } from "../../../services/realTimeVisulization/zoneData/getFloatingData";
|
import { getFloatingZoneData } from "../../../services/realTimeVisulization/zoneData/getFloatingData";
|
||||||
import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData";
|
import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData";
|
||||||
|
@ -63,14 +66,15 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||||
selectedZone,
|
selectedZone,
|
||||||
setSelectedZone,
|
setSelectedZone,
|
||||||
}) => {
|
}) => {
|
||||||
// Refs
|
// Ref for the container element
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const scrollContainerRef = useRef<HTMLDivElement | null>(null);
|
const scrollContainerRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
// State to track overflow visibility
|
// State to track overflow visibility
|
||||||
const [showLeftArrow, setShowLeftArrow] = useState(false);
|
const [showLeftArrow, setShowLeftArrow] = useState(false);
|
||||||
const [showRightArrow, setShowRightArrow] = useState(false);
|
const [showRightArrow, setShowRightArrow] = useState(false);
|
||||||
const { floatingWidget, setFloatingWidget } = useFloatingWidget();
|
const { floatingWidget, setFloatingWidget } = useFloatingWidget()
|
||||||
|
const{setSelectedChartId}=useWidgetStore()
|
||||||
|
|
||||||
// Function to calculate overflow state
|
// Function to calculate overflow state
|
||||||
const updateOverflowState = useCallback(() => {
|
const updateOverflowState = useCallback(() => {
|
||||||
|
@ -147,13 +151,15 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||||
if (selectedZone?.zoneId === zoneId) {
|
if (selectedZone?.zoneId === zoneId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
setSelectedChartId(null)
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
let response = await getSelect2dZoneData(zoneId, organization);
|
let response = await getSelect2dZoneData(zoneId, organization);
|
||||||
console.log('response: ', response);
|
|
||||||
let res = await getFloatingZoneData(zoneId, organization);
|
let res = await getFloatingZoneData(zoneId, organization);
|
||||||
|
|
||||||
setFloatingWidget(res);
|
setFloatingWidget(res);
|
||||||
|
// Set the selected zone in the store
|
||||||
useDroppedObjectsStore.getState().setZone(zoneName, zoneId);
|
useDroppedObjectsStore.getState().setZone(zoneName, zoneId);
|
||||||
if (Array.isArray(res)) {
|
if (Array.isArray(res)) {
|
||||||
res.forEach((val) => {
|
res.forEach((val) => {
|
||||||
|
|
|
@ -5,6 +5,8 @@ import BarGraphComponent from "../realTimeVis/charts/BarGraphComponent";
|
||||||
import LineGraphComponent from "../realTimeVis/charts/LineGraphComponent";
|
import LineGraphComponent from "../realTimeVis/charts/LineGraphComponent";
|
||||||
import DoughnutGraphComponent from "../realTimeVis/charts/DoughnutGraphComponent";
|
import DoughnutGraphComponent from "../realTimeVis/charts/DoughnutGraphComponent";
|
||||||
import PolarAreaGraphComponent from "../realTimeVis/charts/PolarAreaGraphComponent";
|
import PolarAreaGraphComponent from "../realTimeVis/charts/PolarAreaGraphComponent";
|
||||||
|
import ProgressCard1 from "../realTimeVis/charts/ProgressCard1";
|
||||||
|
import ProgressCard2 from "../realTimeVis/charts/ProgressCard2";
|
||||||
import {
|
import {
|
||||||
DeleteIcon,
|
DeleteIcon,
|
||||||
DublicateIcon,
|
DublicateIcon,
|
||||||
|
@ -13,6 +15,8 @@ import {
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { duplicateWidgetApi } from "../../../services/realTimeVisulization/zoneData/duplicateWidget";
|
import { duplicateWidgetApi } from "../../../services/realTimeVisulization/zoneData/duplicateWidget";
|
||||||
import { deleteWidgetApi } from "../../../services/realTimeVisulization/zoneData/deleteWidgetApi";
|
import { deleteWidgetApi } from "../../../services/realTimeVisulization/zoneData/deleteWidgetApi";
|
||||||
|
import { useClickOutside } from "./functions/handleWidgetsOuterClick";
|
||||||
|
import { useSocketStore } from "../../../store/store";
|
||||||
|
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
|
|
||||||
|
@ -69,6 +73,7 @@ export const DraggableWidget = ({
|
||||||
openKebabId: string | null;
|
openKebabId: string | null;
|
||||||
setOpenKebabId: (id: string | null) => void;
|
setOpenKebabId: (id: string | null) => void;
|
||||||
}) => {
|
}) => {
|
||||||
|
const { visualizationSocket } = useSocketStore();
|
||||||
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||||
const [panelDimensions, setPanelDimensions] = useState<{
|
const [panelDimensions, setPanelDimensions] = useState<{
|
||||||
[side in Side]?: { width: number; height: number };
|
[side in Side]?: { width: number; height: number };
|
||||||
|
@ -79,30 +84,48 @@ export const DraggableWidget = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const chartWidget = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const isPanelHidden = hiddenPanels.includes(widget.panel);
|
const isPanelHidden = hiddenPanels.includes(widget.panel);
|
||||||
|
|
||||||
const deleteSelectedChart = async () => {
|
const deleteSelectedChart = async () => {
|
||||||
try {
|
try {
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
const response = await deleteWidgetApi(widget.id, organization);
|
let deleteWidget = {
|
||||||
if (response?.message === "Widget deleted successfully") {
|
zoneId: selectedZone.zoneId,
|
||||||
const updatedWidgets = selectedZone.widgets.filter(
|
widgetID: widget.id,
|
||||||
(w: Widget) => w.id !== widget.id
|
organization: organization
|
||||||
);
|
|
||||||
setSelectedZone((prevZone: any) => ({
|
|
||||||
...prevZone,
|
|
||||||
widgets: updatedWidgets,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
if (visualizationSocket) {
|
||||||
|
visualizationSocket.emit("v2:viz-widget:delete", deleteWidget)
|
||||||
|
}
|
||||||
|
const updatedWidgets = selectedZone.widgets.filter(
|
||||||
|
(w: Widget) => w.id !== widget.id
|
||||||
|
);
|
||||||
|
console.log('updatedWidgets: ', updatedWidgets);
|
||||||
|
setSelectedZone((prevZone: any) => ({
|
||||||
|
...prevZone,
|
||||||
|
widgets: updatedWidgets,
|
||||||
|
}));
|
||||||
|
setOpenKebabId(null);
|
||||||
|
|
||||||
|
// const response = await deleteWidgetApi(widget.id, organization);
|
||||||
|
// if (response?.message === "Widget deleted successfully") {
|
||||||
|
// const updatedWidgets = selectedZone.widgets.filter(
|
||||||
|
// (w: Widget) => w.id !== widget.id
|
||||||
|
// );
|
||||||
|
// setSelectedZone((prevZone: any) => ({
|
||||||
|
// ...prevZone,
|
||||||
|
// widgets: updatedWidgets,
|
||||||
|
// }));
|
||||||
|
// }
|
||||||
|
} catch (error) {
|
||||||
} finally {
|
} finally {
|
||||||
setOpenKebabId(null);
|
setOpenKebabId(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const getCurrentWidgetCount = (panel: Side) =>
|
const getCurrentWidgetCount = (panel: Side) =>
|
||||||
selectedZone.widgets.filter((w) => w.panel === panel).length;
|
selectedZone.widgets.filter((w) => w.panel === panel).length;
|
||||||
|
|
||||||
|
@ -140,7 +163,11 @@ export const DraggableWidget = ({
|
||||||
id: `${widget.id}-copy-${Date.now()}`,
|
id: `${widget.id}-copy-${Date.now()}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await duplicateWidgetApi(selectedZone.zoneId, organization, duplicatedWidget);
|
const response = await duplicateWidgetApi(
|
||||||
|
selectedZone.zoneId,
|
||||||
|
organization,
|
||||||
|
duplicatedWidget
|
||||||
|
);
|
||||||
|
|
||||||
if (response?.message === "Widget created successfully") {
|
if (response?.message === "Widget created successfully") {
|
||||||
setSelectedZone((prevZone: any) => ({
|
setSelectedZone((prevZone: any) => ({
|
||||||
|
@ -149,13 +176,11 @@ export const DraggableWidget = ({
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
setOpenKebabId(null);
|
setOpenKebabId(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleKebabClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
const handleKebabClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (openKebabId === widget.id) {
|
if (openKebabId === widget.id) {
|
||||||
|
@ -203,23 +228,31 @@ export const DraggableWidget = ({
|
||||||
onReorder(fromIndex, toIndex); // Call the reorder function passed as a prop
|
onReorder(fromIndex, toIndex); // Call the reorder function passed as a prop
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
console.log("widget.type", widget.type);
|
||||||
|
|
||||||
|
// useClickOutside(chartWidget, () => {
|
||||||
|
// setSelectedChartId(null);
|
||||||
|
// });
|
||||||
|
|
||||||
|
console.log('isPanelHidden: ', isPanelHidden);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
draggable
|
draggable
|
||||||
key={widget.id}
|
key={widget.id}
|
||||||
className={`chart-container ${selectedChartId?.id === widget.id && "activeChart"
|
className={`chart-container ${
|
||||||
}`}
|
selectedChartId?.id === widget.id && "activeChart"
|
||||||
|
}`}
|
||||||
onPointerDown={handlePointerDown}
|
onPointerDown={handlePointerDown}
|
||||||
onDragStart={handleDragStart}
|
onDragStart={handleDragStart}
|
||||||
onDragEnter={handleDragEnter}
|
onDragEnter={handleDragEnter}
|
||||||
onDragOver={handleDragOver}
|
onDragOver={handleDragOver}
|
||||||
onDrop={handleDrop}
|
onDrop={handleDrop}
|
||||||
style={{
|
style={{
|
||||||
opacity: isPanelHidden ? 0 : 1,
|
|
||||||
pointerEvents: isPanelHidden ? "none" : "auto",
|
pointerEvents: isPanelHidden ? "none" : "auto",
|
||||||
}}
|
}}
|
||||||
|
ref={chartWidget}
|
||||||
|
onClick={() => setSelectedChartId(widget)}
|
||||||
>
|
>
|
||||||
{/* Kebab Icon */}
|
{/* Kebab Icon */}
|
||||||
<div className="icon kebab" onClick={handleKebabClick}>
|
<div className="icon kebab" onClick={handleKebabClick}>
|
||||||
|
@ -230,8 +263,9 @@ export const DraggableWidget = ({
|
||||||
{openKebabId === widget.id && (
|
{openKebabId === widget.id && (
|
||||||
<div className="kebab-options" ref={widgetRef}>
|
<div className="kebab-options" ref={widgetRef}>
|
||||||
<div
|
<div
|
||||||
className={`edit btn ${isPanelFull(widget.panel) ? "btn-blur" : ""
|
className={`edit btn ${
|
||||||
}`}
|
isPanelFull(widget.panel) ? "btn-blur" : ""
|
||||||
|
}`}
|
||||||
onClick={isPanelFull(widget.panel) ? undefined : duplicateWidget}
|
onClick={isPanelFull(widget.panel) ? undefined : duplicateWidget}
|
||||||
>
|
>
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
|
@ -249,9 +283,12 @@ export const DraggableWidget = ({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Render charts based on widget type */}
|
{/* Render charts based on widget type */}
|
||||||
|
|
||||||
{widget.type === "progress" && (
|
{widget.type === "progress 1" && (
|
||||||
<ProgressCard title={widget.title} data={widget.data} />
|
<ProgressCard1 title={widget.title} id={widget.id} />
|
||||||
|
)}
|
||||||
|
{widget.type === "progress 2" && (
|
||||||
|
<ProgressCard2 title={widget.title} id={widget.id} />
|
||||||
)}
|
)}
|
||||||
{widget.type === "line" && (
|
{widget.type === "line" && (
|
||||||
<LineGraphComponent
|
<LineGraphComponent
|
||||||
|
@ -260,14 +297,6 @@ export const DraggableWidget = ({
|
||||||
title={widget.title}
|
title={widget.title}
|
||||||
fontSize={widget.fontSize}
|
fontSize={widget.fontSize}
|
||||||
fontWeight={widget.fontWeight}
|
fontWeight={widget.fontWeight}
|
||||||
// data={{
|
|
||||||
// measurements: [
|
|
||||||
// { name: "testDevice", fields: "powerConsumption" },
|
|
||||||
// { name: "furnace", fields: "powerConsumption" },
|
|
||||||
// ],
|
|
||||||
// interval: 1000,
|
|
||||||
// duration: "1h",
|
|
||||||
// }}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{widget.type === "bar" && (
|
{widget.type === "bar" && (
|
||||||
|
@ -277,14 +306,6 @@ export const DraggableWidget = ({
|
||||||
title={widget.title}
|
title={widget.title}
|
||||||
fontSize={widget.fontSize}
|
fontSize={widget.fontSize}
|
||||||
fontWeight={widget.fontWeight}
|
fontWeight={widget.fontWeight}
|
||||||
// data={{
|
|
||||||
// measurements: [
|
|
||||||
// { name: "testDevice", fields: "powerConsumption" },
|
|
||||||
// { name: "furnace", fields: "powerConsumption" },
|
|
||||||
// ],
|
|
||||||
// interval: 1000,
|
|
||||||
// duration: "1h",
|
|
||||||
// }}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{widget.type === "pie" && (
|
{widget.type === "pie" && (
|
||||||
|
@ -294,14 +315,6 @@ export const DraggableWidget = ({
|
||||||
title={widget.title}
|
title={widget.title}
|
||||||
fontSize={widget.fontSize}
|
fontSize={widget.fontSize}
|
||||||
fontWeight={widget.fontWeight}
|
fontWeight={widget.fontWeight}
|
||||||
// data={{
|
|
||||||
// measurements: [
|
|
||||||
// { name: "testDevice", fields: "powerConsumption" },
|
|
||||||
// { name: "furnace", fields: "powerConsumption" },
|
|
||||||
// ],
|
|
||||||
// interval: 1000,
|
|
||||||
// duration: "1h",
|
|
||||||
// }}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{widget.type === "doughnut" && (
|
{widget.type === "doughnut" && (
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useThree } from "@react-three/fiber";
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useAsset3dWidget, useWidgetSubOption } from "../../../store/store";
|
import { useAsset3dWidget, useWidgetSubOption } from "../../../store/store";
|
||||||
|
@ -16,25 +15,29 @@ import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zone
|
||||||
import { use3DWidget } from "../../../store/useDroppedObjectsStore";
|
import { use3DWidget } from "../../../store/useDroppedObjectsStore";
|
||||||
|
|
||||||
export default function Dropped3dWidgets() {
|
export default function Dropped3dWidgets() {
|
||||||
const { widgetSelect } = useAsset3dWidget();
|
const { widgetSelect } = useAsset3dWidget();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { raycaster, gl, scene }: ThreeState = useThree();
|
const { raycaster, gl, scene }: ThreeState = useThree();
|
||||||
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
||||||
const { selectedZone } = useSelectedZoneStore(); // Get the currently active zone
|
const { selectedZone } = useSelectedZoneStore(); // Get the currently active zone
|
||||||
// 🔥 Store widget data (id, type, position) based on the selected zone
|
// 🔥 Store widget data (id, type, position) based on the selected zone
|
||||||
const [zoneWidgetData, setZoneWidgetData] = useState<
|
const [zoneWidgetData, setZoneWidgetData] = useState<
|
||||||
Record<string, { id: string; type: string; position: [number, number, number] }[]>
|
Record<
|
||||||
>({});
|
string,
|
||||||
const { setWidgets3D } = use3DWidget()
|
{ id: string; type: string; position: [number, number, number] }[]
|
||||||
useEffect(() => {
|
>
|
||||||
if (activeModule !== "visualization") return
|
>({});
|
||||||
if (selectedZone.zoneName === "") return;
|
const { setWidgets3D } = use3DWidget();
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeModule !== "visualization") return;
|
||||||
|
if (selectedZone.zoneName === "") return;
|
||||||
|
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
|
||||||
async function get3dWidgetData() {
|
async function get3dWidgetData() {
|
||||||
let result = await get3dWidgetZoneData(selectedZone.zoneId, organization);
|
let result = await get3dWidgetZoneData(selectedZone.zoneId, organization);
|
||||||
|
console.log('result: ', result);
|
||||||
setWidgets3D(result)
|
setWidgets3D(result)
|
||||||
// Ensure the extracted data has id, type, and position correctly mapped
|
// Ensure the extracted data has id, type, and position correctly mapped
|
||||||
const formattedWidgets = result.map((widget: any) => ({
|
const formattedWidgets = result.map((widget: any) => ({
|
||||||
|
@ -43,98 +46,108 @@ export default function Dropped3dWidgets() {
|
||||||
position: widget.position,
|
position: widget.position,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
setZoneWidgetData((prev) => ({
|
setZoneWidgetData((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[selectedZone.zoneId]: formattedWidgets,
|
[selectedZone.zoneId]: formattedWidgets,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
get3dWidgetData();
|
get3dWidgetData();
|
||||||
|
}, [selectedZone.zoneId, activeModule]);
|
||||||
|
// useEffect(() => {
|
||||||
|
// // ✅ Set data only for the selected zone, keeping existing state structure
|
||||||
|
// setZoneWidgetData((prev) => ({
|
||||||
|
// ...prev,
|
||||||
|
// [selectedZone.zoneId]: [
|
||||||
|
// {
|
||||||
|
// "id": "1743322674626-50mucpb1c",
|
||||||
|
// "type": "ui-Widget 1",
|
||||||
|
// "position": [120.94655021768133, 4.142360029666558, 124.39283546121099]
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": "1743322682086-je2h9x33v",
|
||||||
|
// "type": "ui-Widget 2",
|
||||||
|
// "position": [131.28751045879255, 0.009999999999970264, 133.92059801984362]
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }));
|
||||||
|
// }, [selectedZone.zoneId]); // ✅ Only update when the zone changes
|
||||||
|
|
||||||
}, [selectedZone.zoneId,activeModule]);
|
useEffect(() => {
|
||||||
// useEffect(() => {
|
if (activeModule !== "visualization") return;
|
||||||
// // ✅ Set data only for the selected zone, keeping existing state structure
|
if (widgetSubOption === "Floating") return;
|
||||||
// setZoneWidgetData((prev) => ({
|
if (selectedZone.zoneName === "") return;
|
||||||
// ...prev,
|
const canvasElement = gl.domElement;
|
||||||
// [selectedZone.zoneId]: [
|
const onDrop = async (event: DragEvent) => {
|
||||||
// {
|
event.preventDefault(); // Prevent default browser behavior
|
||||||
// "id": "1743322674626-50mucpb1c",
|
const email = localStorage.getItem("email") || "";
|
||||||
// "type": "ui-Widget 1",
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
// "position": [120.94655021768133, 4.142360029666558, 124.39283546121099]
|
if (!widgetSelect.startsWith("ui")) return;
|
||||||
// },
|
const group1 = scene.getObjectByName("itemsGroup");
|
||||||
// {
|
if (!group1) return;
|
||||||
// "id": "1743322682086-je2h9x33v",
|
const intersects = raycaster
|
||||||
// "type": "ui-Widget 2",
|
.intersectObjects(scene.children, true)
|
||||||
// "position": [131.28751045879255, 0.009999999999970264, 133.92059801984362]
|
.filter(
|
||||||
// }
|
(intersect) =>
|
||||||
// ]
|
!intersect.object.name.includes("Roof") &&
|
||||||
// }));
|
!intersect.object.name.includes("agv-collider") &&
|
||||||
// }, [selectedZone.zoneId]); // ✅ Only update when the zone changes
|
!intersect.object.name.includes("MeasurementReference") &&
|
||||||
|
!intersect.object.userData.isPathObject &&
|
||||||
|
!(intersect.object.type === "GridHelper")
|
||||||
|
);
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
const { x, y, z } = intersects[0].point;
|
||||||
|
|
||||||
useEffect(() => {
|
// ✅ Explicitly define position as a tuple
|
||||||
if (activeModule !== "visualization") return;
|
const newWidget: {
|
||||||
if (widgetSubOption === "Floating") return;
|
id: string;
|
||||||
if (selectedZone.zoneName === "") return
|
type: string;
|
||||||
const canvasElement = gl.domElement;
|
position: [number, number, number];
|
||||||
const onDrop = async (event: DragEvent) => {
|
} = {
|
||||||
event.preventDefault(); // Prevent default browser behavior
|
id: generateUniqueId(),
|
||||||
const email = localStorage.getItem("email") || "";
|
type: widgetSelect,
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
position: [x, y, z], // Ensures TypeScript recognizes it as a tuple
|
||||||
if (!widgetSelect.startsWith("ui")) return;
|
|
||||||
const group1 = scene.getObjectByName("itemsGroup");
|
|
||||||
if (!group1) return;
|
|
||||||
const intersects = raycaster.intersectObjects(scene.children, true).filter(
|
|
||||||
(intersect) =>
|
|
||||||
!intersect.object.name.includes("Roof") &&
|
|
||||||
!intersect.object.name.includes("agv-collider") &&
|
|
||||||
!intersect.object.name.includes("MeasurementReference") &&
|
|
||||||
!intersect.object.userData.isPathObject &&
|
|
||||||
!(intersect.object.type === "GridHelper")
|
|
||||||
);
|
|
||||||
if (intersects.length > 0) {
|
|
||||||
const { x, y, z } = intersects[0].point;
|
|
||||||
|
|
||||||
// ✅ Explicitly define position as a tuple
|
|
||||||
const newWidget: { id: string; type: string; position: [number, number, number] } = {
|
|
||||||
id: generateUniqueId(),
|
|
||||||
type: widgetSelect,
|
|
||||||
position: [x, y, z], // Ensures TypeScript recognizes it as a tuple
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget)
|
|
||||||
|
|
||||||
|
|
||||||
// ✅ Store widgets uniquely for each zone
|
|
||||||
setZoneWidgetData((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[selectedZone.zoneId]: [...(prev[selectedZone.zoneId] || []), newWidget],
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let response = await adding3dWidgets(
|
||||||
|
selectedZone.zoneId,
|
||||||
|
organization,
|
||||||
|
newWidget
|
||||||
|
);
|
||||||
|
|
||||||
canvasElement.addEventListener("drop", onDrop);
|
// ✅ Store widgets uniquely for each zone
|
||||||
return () => {
|
setZoneWidgetData((prev) => ({
|
||||||
canvasElement.removeEventListener("drop", onDrop);
|
...prev,
|
||||||
};
|
[selectedZone.zoneId]: [
|
||||||
}, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption]);
|
...(prev[selectedZone.zoneId] || []),
|
||||||
|
newWidget,
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Get widgets for the currently active zone
|
canvasElement.addEventListener("drop", onDrop);
|
||||||
const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || [];
|
return () => {
|
||||||
|
canvasElement.removeEventListener("drop", onDrop);
|
||||||
|
};
|
||||||
|
}, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption]);
|
||||||
|
|
||||||
|
// Get widgets for the currently active zone
|
||||||
|
const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{activeZoneWidgets.map(({ id, type, position }) => {
|
{activeZoneWidgets.map(({ id, type, position }) => {
|
||||||
|
console.log('Typeeeeeeeeeeee',type);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "ui-Widget 1":
|
case "ui-Widget 1":
|
||||||
return <ProductionCapacity key={id} position={position} />;
|
return <ProductionCapacity key={id} id={id} type={type} position={position} />;
|
||||||
case "ui-Widget 2":
|
case "ui-Widget 2":
|
||||||
return <ReturnOfInvestment key={id} position={position} />;
|
return <ReturnOfInvestment key={id} id={id} type={type} position={position} />;
|
||||||
case "ui-Widget 3":
|
case "ui-Widget 3":
|
||||||
return <StateWorking key={id} position={position} />;
|
return <StateWorking key={id} id={id} type={type} position={position} />;
|
||||||
case "ui-Widget 4":
|
case "ui-Widget 4":
|
||||||
return <Throughput key={id} position={position} />;
|
return <Throughput key={id} id={id} type={type} position={position} />;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -142,6 +155,3 @@ export default function Dropped3dWidgets() {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import { WalletIcon } from "../../icons/3dChartIcons";
|
import { WalletIcon } from "../../icons/3dChartIcons";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
|
@ -21,6 +20,9 @@ import TotalCardComponent from "../realTimeVis/floating/TotalCardComponent";
|
||||||
import WarehouseThroughputComponent from "../realTimeVis/floating/WarehouseThroughputComponent";
|
import WarehouseThroughputComponent from "../realTimeVis/floating/WarehouseThroughputComponent";
|
||||||
import FleetEfficiencyComponent from "../realTimeVis/floating/FleetEfficiencyComponent";
|
import FleetEfficiencyComponent from "../realTimeVis/floating/FleetEfficiencyComponent";
|
||||||
import { useWidgetStore } from "../../../store/useWidgetStore";
|
import { useWidgetStore } from "../../../store/useWidgetStore";
|
||||||
|
import { useClickOutside } from "./functions/handleWidgetsOuterClick";
|
||||||
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
|
import { useSelectedZoneStore } from "../../../store/useZoneStore";
|
||||||
interface DraggingState {
|
interface DraggingState {
|
||||||
zone: string;
|
zone: string;
|
||||||
index: number;
|
index: number;
|
||||||
|
@ -43,19 +45,24 @@ interface DraggingState {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const DroppedObjects: React.FC = () => {
|
const DroppedObjects: React.FC = () => {
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const zones = useDroppedObjectsStore((state) => state.zones);
|
const zones = useDroppedObjectsStore((state) => state.zones);
|
||||||
const [openKebabId, setOpenKebabId] = useState<string | null>(null);
|
const [openKebabId, setOpenKebabId] = useState<string | null>(null);
|
||||||
const updateObjectPosition = useDroppedObjectsStore(
|
const updateObjectPosition = useDroppedObjectsStore(
|
||||||
(state) => state.updateObjectPosition
|
(state) => state.updateObjectPosition
|
||||||
);
|
);
|
||||||
|
const { setSelectedZone, selectedZone } = useSelectedZoneStore();
|
||||||
|
|
||||||
const deleteObject = useDroppedObjectsStore((state) => state.deleteObject);
|
const deleteObject = useDroppedObjectsStore((state) => state.deleteObject);
|
||||||
|
|
||||||
const duplicateObject = useDroppedObjectsStore((state) => state.duplicateObject);
|
const duplicateObject = useDroppedObjectsStore(
|
||||||
|
(state) => state.duplicateObject
|
||||||
|
);
|
||||||
const [draggingIndex, setDraggingIndex] = useState<DraggingState | null>(
|
const [draggingIndex, setDraggingIndex] = useState<DraggingState | null>(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
const [offset, setOffset] = useState<[number, number] | null>(null);
|
const [offset, setOffset] = useState<[number, number] | null>(null);
|
||||||
const { setSelectedChartId } = useWidgetStore();
|
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||||
const [activeEdges, setActiveEdges] = useState<{
|
const [activeEdges, setActiveEdges] = useState<{
|
||||||
vertical: "top" | "bottom";
|
vertical: "top" | "bottom";
|
||||||
horizontal: "left" | "right";
|
horizontal: "left" | "right";
|
||||||
|
@ -68,6 +75,13 @@ const DroppedObjects: React.FC = () => {
|
||||||
} | null>(null); // State to track the current position during drag
|
} | null>(null); // State to track the current position during drag
|
||||||
const animationRef = useRef<number | null>(null);
|
const animationRef = useRef<number | null>(null);
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
|
const chartWidget = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
// useClickOutside(chartWidget, () => {
|
||||||
|
// setSelectedChartId(null);
|
||||||
|
// });
|
||||||
|
const kebabRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
|
||||||
// Clean up animation frame on unmount
|
// Clean up animation frame on unmount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -77,13 +91,28 @@ const DroppedObjects: React.FC = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
|
if (kebabRef.current && !kebabRef.current.contains(event.target as Node)) {
|
||||||
|
setOpenKebabId(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add event listener when component mounts
|
||||||
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
|
|
||||||
|
// Clean up event listener when component unmounts
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("mousedown", handleClickOutside);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const zoneEntries = Object.entries(zones);
|
const zoneEntries = Object.entries(zones);
|
||||||
if (zoneEntries.length === 0) return null;
|
if (zoneEntries.length === 0) return null;
|
||||||
const [zoneName, zone] = zoneEntries[0];
|
const [zoneName, zone] = zoneEntries[0];
|
||||||
|
|
||||||
function handleDuplicate(zoneName: string, index: number) {
|
function handleDuplicate(zoneName: string, index: number) {
|
||||||
setOpenKebabId(null)
|
setOpenKebabId(null);
|
||||||
duplicateObject(zoneName, index); // Call the duplicateObject method from the store
|
duplicateObject(zoneName, index); // Call the duplicateObject method from the store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,19 +122,20 @@ const DroppedObjects: React.FC = () => {
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
|
||||||
let res = await deleteFloatingWidgetApi(id, organization);
|
let res = await deleteFloatingWidgetApi(id, organization);
|
||||||
console.log('res: ', res);
|
|
||||||
|
|
||||||
if (res.message === "FloatingWidget deleted successfully") {
|
if (res.message === "FloatingWidget deleted successfully") {
|
||||||
deleteObject(zoneName, index); // Call the deleteObject method from the store
|
deleteObject(zoneName, id, index); // Call the deleteObject method from the store
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {}
|
||||||
console.error("Error deleting floating widget:", error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const handlePointerDown = (event: React.PointerEvent, index: number) => {
|
const handlePointerDown = (event: React.PointerEvent, index: number) => {
|
||||||
|
if ((event.target as HTMLElement).closest(".kebab-options") || (event.target as HTMLElement).closest(".kebab")) {
|
||||||
|
return; // Prevent dragging when clicking on the kebab menu or its options
|
||||||
|
}
|
||||||
const obj = zone.objects[index];
|
const obj = zone.objects[index];
|
||||||
|
const element = event.currentTarget as HTMLElement;
|
||||||
|
element.setPointerCapture(event.pointerId);
|
||||||
const container = document.getElementById("real-time-vis-canvas");
|
const container = document.getElementById("real-time-vis-canvas");
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
|
@ -145,11 +175,150 @@ const DroppedObjects: React.FC = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
setOffset([offsetY, offsetX]);
|
setOffset([offsetY, offsetX]);
|
||||||
|
|
||||||
|
// Add native event listeners for smoother tracking
|
||||||
|
const handlePointerMoveNative = (e: PointerEvent) => {
|
||||||
|
if (!draggingIndex || !offset) return;
|
||||||
|
if (isPlaying === true) return;
|
||||||
|
|
||||||
|
const rect = container.getBoundingClientRect();
|
||||||
|
const relativeX = e.clientX - rect.left;
|
||||||
|
const relativeY = e.clientY - rect.top;
|
||||||
|
|
||||||
|
// Use requestAnimationFrame for smooth updates
|
||||||
|
animationRef.current = requestAnimationFrame(() => {
|
||||||
|
// Dynamically determine the current position strategy
|
||||||
|
const newPositionStrategy = determinePosition(
|
||||||
|
rect,
|
||||||
|
relativeX,
|
||||||
|
relativeY
|
||||||
|
);
|
||||||
|
const [activeProp1, activeProp2] =
|
||||||
|
getActiveProperties(newPositionStrategy);
|
||||||
|
|
||||||
|
// Update active edges for distance lines
|
||||||
|
const vertical = activeProp1 === "top" ? "top" : "bottom";
|
||||||
|
const horizontal = activeProp2 === "left" ? "left" : "right";
|
||||||
|
setActiveEdges({ vertical, horizontal });
|
||||||
|
|
||||||
|
// Calculate new position based on the active properties
|
||||||
|
let newY = 0;
|
||||||
|
let newX = 0;
|
||||||
|
|
||||||
|
if (activeProp1 === "top") {
|
||||||
|
newY = relativeY - offset[0];
|
||||||
|
} else {
|
||||||
|
newY = rect.height - (relativeY + offset[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeProp2 === "left") {
|
||||||
|
newX = relativeX - offset[1];
|
||||||
|
} else {
|
||||||
|
newX = rect.width - (relativeX + offset[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply boundaries
|
||||||
|
newX = Math.max(0, Math.min(rect.width - 50, newX));
|
||||||
|
newY = Math.max(0, Math.min(rect.height - 50, newY));
|
||||||
|
|
||||||
|
// Create new position object
|
||||||
|
const newPosition = {
|
||||||
|
...newPositionStrategy,
|
||||||
|
[activeProp1]: newY,
|
||||||
|
[activeProp2]: newX,
|
||||||
|
// Clear opposite properties
|
||||||
|
[activeProp1 === "top" ? "bottom" : "top"]: "auto",
|
||||||
|
[activeProp2 === "left" ? "right" : "left"]: "auto",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update the current position state for DistanceLines
|
||||||
|
setCurrentPosition(newPosition);
|
||||||
|
updateObjectPosition(zoneName, draggingIndex.index, newPosition);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePointerUpNative = async (e: PointerEvent) => {
|
||||||
|
// Clean up native event listeners
|
||||||
|
element.removeEventListener("pointermove", handlePointerMoveNative);
|
||||||
|
element.removeEventListener("pointerup", handlePointerUpNative);
|
||||||
|
element.releasePointerCapture(e.pointerId);
|
||||||
|
|
||||||
|
if (!draggingIndex || !offset) return;
|
||||||
|
|
||||||
|
const rect = container.getBoundingClientRect();
|
||||||
|
const relativeX = e.clientX - rect.left;
|
||||||
|
const relativeY = e.clientY - rect.top;
|
||||||
|
|
||||||
|
// Determine final position strategy
|
||||||
|
const finalPosition = determinePosition(rect, relativeX, relativeY);
|
||||||
|
const [activeProp1, activeProp2] = getActiveProperties(finalPosition);
|
||||||
|
|
||||||
|
// Calculate final position
|
||||||
|
let finalY = 0;
|
||||||
|
let finalX = 0;
|
||||||
|
|
||||||
|
if (activeProp1 === "top") {
|
||||||
|
finalY = relativeY - offset[0];
|
||||||
|
} else {
|
||||||
|
finalY = rect.height - (relativeY + offset[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeProp2 === "left") {
|
||||||
|
finalX = relativeX - offset[1];
|
||||||
|
} else {
|
||||||
|
finalX = rect.width - (relativeX + offset[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply boundaries
|
||||||
|
finalX = Math.max(0, Math.min(rect.width - 50, finalX));
|
||||||
|
finalY = Math.max(0, Math.min(rect.height - 50, finalY));
|
||||||
|
|
||||||
|
const boundedPosition = {
|
||||||
|
...finalPosition,
|
||||||
|
[activeProp1]: finalY,
|
||||||
|
[activeProp2]: finalX,
|
||||||
|
[activeProp1 === "top" ? "bottom" : "top"]: "auto",
|
||||||
|
[activeProp2 === "left" ? "right" : "left"]: "auto",
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Save to backend
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
const response = await addingFloatingWidgets(
|
||||||
|
zone.zoneId,
|
||||||
|
organization,
|
||||||
|
{
|
||||||
|
...zone.objects[draggingIndex.index],
|
||||||
|
position: boundedPosition,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.message === "Widget updated successfully") {
|
||||||
|
updateObjectPosition(zoneName, draggingIndex.index, boundedPosition);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
} finally {
|
||||||
|
setDraggingIndex(null);
|
||||||
|
setOffset(null);
|
||||||
|
setActiveEdges(null);
|
||||||
|
setCurrentPosition(null);
|
||||||
|
|
||||||
|
if (animationRef.current) {
|
||||||
|
cancelAnimationFrame(animationRef.current);
|
||||||
|
animationRef.current = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add native event listeners
|
||||||
|
element.addEventListener("pointermove", handlePointerMoveNative);
|
||||||
|
element.addEventListener("pointerup", handlePointerUpNative);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePointerMove = (event: React.PointerEvent) => {
|
const handlePointerMove = (event: React.PointerEvent) => {
|
||||||
if (!draggingIndex || !offset) return;
|
if (!draggingIndex || !offset) return;
|
||||||
|
if (isPlaying === true) return;
|
||||||
const container = document.getElementById("real-time-vis-canvas");
|
const container = document.getElementById("real-time-vis-canvas");
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
|
@ -198,18 +367,21 @@ const DroppedObjects: React.FC = () => {
|
||||||
|
|
||||||
// Update the current position state for DistanceLines
|
// Update the current position state for DistanceLines
|
||||||
setCurrentPosition(newPosition);
|
setCurrentPosition(newPosition);
|
||||||
|
// Update position immediately without animation frame
|
||||||
|
updateObjectPosition(zoneName, draggingIndex.index, newPosition);
|
||||||
|
|
||||||
if (!animationRef.current) {
|
// if (!animationRef.current) {
|
||||||
animationRef.current = requestAnimationFrame(() => {
|
// animationRef.current = requestAnimationFrame(() => {
|
||||||
updateObjectPosition(zoneName, draggingIndex.index, newPosition);
|
// updateObjectPosition(zoneName, draggingIndex.index, newPosition);
|
||||||
animationRef.current = null;
|
// animationRef.current = null;
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePointerUp = async (event: React.PointerEvent<HTMLDivElement>) => {
|
const handlePointerUp = async (event: React.PointerEvent<HTMLDivElement>) => {
|
||||||
try {
|
try {
|
||||||
if (!draggingIndex || !offset) return;
|
if (!draggingIndex || !offset) return;
|
||||||
|
if (isPlaying === true) return;
|
||||||
|
|
||||||
const container = document.getElementById("real-time-vis-canvas");
|
const container = document.getElementById("real-time-vis-canvas");
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
@ -218,11 +390,11 @@ const DroppedObjects: React.FC = () => {
|
||||||
const relativeX = event.clientX - rect.left;
|
const relativeX = event.clientX - rect.left;
|
||||||
const relativeY = event.clientY - rect.top;
|
const relativeY = event.clientY - rect.top;
|
||||||
|
|
||||||
// Only now determine the final position strategy
|
// Determine final position strategy
|
||||||
const finalPosition = determinePosition(rect, relativeX, relativeY);
|
const finalPosition = determinePosition(rect, relativeX, relativeY);
|
||||||
const [activeProp1, activeProp2] = getActiveProperties(finalPosition);
|
const [activeProp1, activeProp2] = getActiveProperties(finalPosition);
|
||||||
|
|
||||||
// Calculate final position using the new strategy
|
// Calculate final position
|
||||||
let finalY = 0;
|
let finalY = 0;
|
||||||
let finalX = 0;
|
let finalX = 0;
|
||||||
|
|
||||||
|
@ -246,6 +418,9 @@ const DroppedObjects: React.FC = () => {
|
||||||
...finalPosition,
|
...finalPosition,
|
||||||
[activeProp1]: finalY,
|
[activeProp1]: finalY,
|
||||||
[activeProp2]: finalX,
|
[activeProp2]: finalX,
|
||||||
|
// Clear opposite properties
|
||||||
|
[activeProp1 === "top" ? "bottom" : "top"]: "auto",
|
||||||
|
[activeProp2 === "left" ? "right" : "left"]: "auto",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Save to backend
|
// Save to backend
|
||||||
|
@ -255,22 +430,35 @@ const DroppedObjects: React.FC = () => {
|
||||||
...zone.objects[draggingIndex.index],
|
...zone.objects[draggingIndex.index],
|
||||||
position: boundedPosition,
|
position: boundedPosition,
|
||||||
});
|
});
|
||||||
|
console.log('response: ', response);
|
||||||
|
|
||||||
if (response.message === "Widget updated successfully") {
|
if (response.message === "Widget updated successfully") {
|
||||||
updateObjectPosition(zoneName, draggingIndex.index, boundedPosition);
|
updateObjectPosition(zoneName, draggingIndex.index, boundedPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up
|
// // Clean up
|
||||||
|
// setDraggingIndex(null);
|
||||||
|
// setOffset(null);
|
||||||
|
// setActiveEdges(null); // Clear active edges
|
||||||
|
// setCurrentPosition(null); // Reset current position
|
||||||
|
// if (animationRef.current) {
|
||||||
|
// cancelAnimationFrame(animationRef.current);
|
||||||
|
// animationRef.current = null;
|
||||||
|
// }
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in handlePointerUp:", error);
|
||||||
|
} finally {
|
||||||
|
// Clean up regardless of success or failure
|
||||||
setDraggingIndex(null);
|
setDraggingIndex(null);
|
||||||
setOffset(null);
|
setOffset(null);
|
||||||
setActiveEdges(null); // Clear active edges
|
setActiveEdges(null);
|
||||||
setCurrentPosition(null); // Reset current position
|
setCurrentPosition(null);
|
||||||
|
|
||||||
|
// Cancel any pending animation frame
|
||||||
if (animationRef.current) {
|
if (animationRef.current) {
|
||||||
cancelAnimationFrame(animationRef.current);
|
cancelAnimationFrame(animationRef.current);
|
||||||
animationRef.current = null;
|
animationRef.current = null;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
console.error("Error in handlePointerUp:", error);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -279,66 +467,6 @@ const DroppedObjects: React.FC = () => {
|
||||||
setOpenKebabId((prevId) => (prevId === id ? null : id));
|
setOpenKebabId((prevId) => (prevId === id ? null : id));
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderObjectContent = (obj: any) => {
|
|
||||||
switch (obj.className) {
|
|
||||||
case "floating total-card":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="header-wrapper">
|
|
||||||
<div className="header">{obj.header}</div>
|
|
||||||
<div className="data-values">
|
|
||||||
<div className="value">{obj.value}</div>
|
|
||||||
<div className="per">{obj.per}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="icon">
|
|
||||||
<WalletIcon />
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "warehouseThroughput floating":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="header">
|
|
||||||
<h2>Warehouse Throughput</h2>
|
|
||||||
<p>
|
|
||||||
<span>(+5) more</span> in 2025
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="lineGraph" style={{ height: "100%" }}>
|
|
||||||
{/* <Line data={lineGraphData} options={lineGraphOptions} /> */}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "fleetEfficiency floating":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h2 className="header">Fleet Efficiency</h2>
|
|
||||||
<div className="progressContainer">
|
|
||||||
<div className="progress">
|
|
||||||
<div className="barOverflow">
|
|
||||||
<div
|
|
||||||
className="bar"
|
|
||||||
style={{ transform: `rotate(${obj.value}deg)` }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="scaleLabels">
|
|
||||||
<span>0%</span>
|
|
||||||
<div className="centerText">
|
|
||||||
<div className="percentage">{obj.per}%</div>
|
|
||||||
<div className="status">Optimal</div>
|
|
||||||
</div>
|
|
||||||
<span>100%</span>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onPointerMove={handlePointerMove}
|
onPointerMove={handlePointerMove}
|
||||||
|
@ -348,29 +476,48 @@ const DroppedObjects: React.FC = () => {
|
||||||
{zone.objects.map((obj, index) => (
|
{zone.objects.map((obj, index) => (
|
||||||
<div
|
<div
|
||||||
key={`${zoneName}-${index}`}
|
key={`${zoneName}-${index}`}
|
||||||
className={obj.className}
|
className={`${obj.className} ${
|
||||||
|
selectedChartId?.id === obj.id && "activeChart"
|
||||||
|
}`}
|
||||||
|
ref={chartWidget}
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top:
|
top:
|
||||||
typeof obj.position.top === "number"
|
typeof obj.position.top === "number"
|
||||||
? `${obj.position.top}px`
|
? `calc(${obj.position.top}px + ${
|
||||||
|
isPlaying && selectedZone.activeSides.includes("top")
|
||||||
|
? 90
|
||||||
|
: 0
|
||||||
|
}px)`
|
||||||
: "auto",
|
: "auto",
|
||||||
left:
|
left:
|
||||||
typeof obj.position.left === "number"
|
typeof obj.position.left === "number"
|
||||||
? `${obj.position.left}px`
|
? `calc(${obj.position.left}px + ${
|
||||||
|
isPlaying && selectedZone.activeSides.includes("left")
|
||||||
|
? 90
|
||||||
|
: 0
|
||||||
|
}px)`
|
||||||
: "auto",
|
: "auto",
|
||||||
right:
|
right:
|
||||||
typeof obj.position.right === "number"
|
typeof obj.position.right === "number"
|
||||||
? `${obj.position.right}px`
|
? `calc(${obj.position.right}px + ${
|
||||||
|
isPlaying && selectedZone.activeSides.includes("right")
|
||||||
|
? 90
|
||||||
|
: 0
|
||||||
|
}px)`
|
||||||
: "auto",
|
: "auto",
|
||||||
bottom:
|
bottom:
|
||||||
typeof obj.position.bottom === "number"
|
typeof obj.position.bottom === "number"
|
||||||
? `${obj.position.bottom}px`
|
? `calc(${obj.position.bottom}px + ${
|
||||||
|
isPlaying && selectedZone.activeSides.includes("bottom")
|
||||||
|
? 90
|
||||||
|
: 0
|
||||||
|
}px)`
|
||||||
: "auto",
|
: "auto",
|
||||||
}}
|
}}
|
||||||
onPointerDown={(event) => handlePointerDown(event, index)}
|
onPointerDown={(event) => {
|
||||||
onClick={() => {
|
setSelectedChartId(obj);
|
||||||
setSelectedChartId(obj)
|
handlePointerDown(event, index);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{obj.className === "floating total-card" ? (
|
{obj.className === "floating total-card" ? (
|
||||||
|
@ -379,7 +526,7 @@ const DroppedObjects: React.FC = () => {
|
||||||
</>
|
</>
|
||||||
) : obj.className === "warehouseThroughput floating" ? (
|
) : obj.className === "warehouseThroughput floating" ? (
|
||||||
<>
|
<>
|
||||||
<WarehouseThroughputComponent />
|
<WarehouseThroughputComponent object={obj}/>
|
||||||
</>
|
</>
|
||||||
) : obj.className === "fleetEfficiency floating" ? (
|
) : obj.className === "fleetEfficiency floating" ? (
|
||||||
<>
|
<>
|
||||||
|
@ -388,12 +535,16 @@ const DroppedObjects: React.FC = () => {
|
||||||
) : null}
|
) : null}
|
||||||
<div
|
<div
|
||||||
className="icon kebab"
|
className="icon kebab"
|
||||||
onClick={(event) => handleKebabClick(obj.id, event)}
|
ref={kebabRef}
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
handleKebabClick(obj.id, event)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<KebabIcon />
|
<KebabIcon />
|
||||||
</div>
|
</div>
|
||||||
{openKebabId === obj.id && (
|
{openKebabId === obj.id && (
|
||||||
<div className="kebab-options">
|
<div className="kebab-options" ref={kebabRef}>
|
||||||
<div className="dublicate btn" onClick={(event) => {
|
<div className="dublicate btn" onClick={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
handleDuplicate(zoneName, index); // Call the duplicate handler
|
handleDuplicate(zoneName, index); // Call the duplicate handler
|
||||||
|
@ -403,10 +554,13 @@ const DroppedObjects: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="label">Duplicate</div>
|
<div className="label">Duplicate</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="edit btn" onClick={(event) => {
|
<div
|
||||||
event.stopPropagation();
|
className="edit btn"
|
||||||
handleDelete(zoneName, obj.id, index); // Call the delete handler
|
onClick={(event) => {
|
||||||
}}>
|
event.stopPropagation();
|
||||||
|
handleDelete(zoneName, obj.id, index); // Call the delete handler
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
</div>
|
</div>
|
||||||
|
@ -414,11 +568,13 @@ const DroppedObjects: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{/* Render DistanceLines component during drag */}
|
{/* Render DistanceLines component during drag */}
|
||||||
{draggingIndex !== null &&
|
{isPlaying === false &&
|
||||||
|
draggingIndex !== null &&
|
||||||
activeEdges !== null &&
|
activeEdges !== null &&
|
||||||
currentPosition !== null && (
|
currentPosition !== null && (
|
||||||
<DistanceLines
|
<DistanceLines
|
||||||
|
@ -451,4 +607,4 @@ const DroppedObjects: React.FC = () => {
|
||||||
|
|
||||||
export default DroppedObjects;
|
export default DroppedObjects;
|
||||||
|
|
||||||
|
// always place the mousePointer in the same point in the floatingCard even in pointerMove
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
import { DraggableWidget } from "./DraggableWidget";
|
import { DraggableWidget } from "./DraggableWidget";
|
||||||
import { arrayMove } from "@dnd-kit/sortable";
|
import { arrayMove } from "@dnd-kit/sortable";
|
||||||
import { addingWidgets } from "../../../services/realTimeVisulization/zoneData/addWidgets";
|
import { addingWidgets } from "../../../services/realTimeVisulization/zoneData/addWidgets";
|
||||||
|
import { useAsset3dWidget, useSocketStore } from "../../../store/store";
|
||||||
|
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ interface PanelProps {
|
||||||
lockedPanels: Side[];
|
lockedPanels: Side[];
|
||||||
zoneId: string;
|
zoneId: string;
|
||||||
zoneViewPortTarget: number[];
|
zoneViewPortTarget: number[];
|
||||||
zoneViewPortPosition: number[]
|
zoneViewPortPosition: number[];
|
||||||
widgets: Widget[];
|
widgets: Widget[];
|
||||||
};
|
};
|
||||||
setSelectedZone: React.Dispatch<
|
setSelectedZone: React.Dispatch<
|
||||||
|
@ -36,7 +37,7 @@ interface PanelProps {
|
||||||
lockedPanels: Side[];
|
lockedPanels: Side[];
|
||||||
zoneId: string;
|
zoneId: string;
|
||||||
zoneViewPortTarget: number[];
|
zoneViewPortTarget: number[];
|
||||||
zoneViewPortPosition: number[]
|
zoneViewPortPosition: number[];
|
||||||
widgets: Widget[];
|
widgets: Widget[];
|
||||||
}>
|
}>
|
||||||
>;
|
>;
|
||||||
|
@ -53,6 +54,7 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
hiddenPanels,
|
hiddenPanels,
|
||||||
setZonesData,
|
setZonesData,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
|
||||||
const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({});
|
const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({});
|
||||||
const [panelDimensions, setPanelDimensions] = useState<{
|
const [panelDimensions, setPanelDimensions] = useState<{
|
||||||
[side in Side]?: { width: number; height: number };
|
[side in Side]?: { width: number; height: number };
|
||||||
|
@ -60,6 +62,7 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
const [openKebabId, setOpenKebabId] = useState<string | null>(null);
|
const [openKebabId, setOpenKebabId] = useState<string | null>(null);
|
||||||
|
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const { visualizationSocket } = useSocketStore();
|
||||||
|
|
||||||
const getPanelStyle = useMemo(
|
const getPanelStyle = useMemo(
|
||||||
() => (side: Side) => {
|
() => (side: Side) => {
|
||||||
|
@ -75,8 +78,9 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
case "top":
|
case "top":
|
||||||
case "bottom":
|
case "bottom":
|
||||||
return {
|
return {
|
||||||
width: `calc(100% - ${(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0)
|
width: `calc(100% - ${
|
||||||
}px)`,
|
(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0)
|
||||||
|
}px)`,
|
||||||
height: `${panelSize - 2}px`,
|
height: `${panelSize - 2}px`,
|
||||||
left: leftActive ? `${panelSize}px` : "0",
|
left: leftActive ? `${panelSize}px` : "0",
|
||||||
right: rightActive ? `${panelSize}px` : "0",
|
right: rightActive ? `${panelSize}px` : "0",
|
||||||
|
@ -86,8 +90,9 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
case "right":
|
case "right":
|
||||||
return {
|
return {
|
||||||
width: `${panelSize - 2}px`,
|
width: `${panelSize - 2}px`,
|
||||||
height: `calc(100% - ${(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0)
|
height: `calc(100% - ${
|
||||||
}px)`,
|
(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0)
|
||||||
|
}px)`,
|
||||||
top: topActive ? `${panelSize}px` : "0",
|
top: topActive ? `${panelSize}px` : "0",
|
||||||
bottom: bottomActive ? `${panelSize}px` : "0",
|
bottom: bottomActive ? `${panelSize}px` : "0",
|
||||||
[side]: "0",
|
[side]: "0",
|
||||||
|
@ -100,7 +105,6 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleDrop = (e: React.DragEvent, panel: Side) => {
|
const handleDrop = (e: React.DragEvent, panel: Side) => {
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const { draggedAsset } = useWidgetStore.getState();
|
const { draggedAsset } = useWidgetStore.getState();
|
||||||
if (!draggedAsset) return;
|
if (!draggedAsset) return;
|
||||||
|
@ -110,7 +114,6 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
const maxCapacity = calculatePanelCapacity(panel);
|
const maxCapacity = calculatePanelCapacity(panel);
|
||||||
|
|
||||||
if (currentWidgetsCount >= maxCapacity) return;
|
if (currentWidgetsCount >= maxCapacity) return;
|
||||||
|
|
||||||
addWidgetToPanel(draggedAsset, panel);
|
addWidgetToPanel(draggedAsset, panel);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,24 +144,39 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
// while dublicate check this and add
|
// while dublicate check this and add
|
||||||
const addWidgetToPanel = async (asset: any, panel: Side) => {
|
const addWidgetToPanel = async (asset: any, panel: Side) => {
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0]
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
const newWidget = {
|
const newWidget = {
|
||||||
...asset,
|
...asset,
|
||||||
id: generateUniqueId(),
|
id: generateUniqueId(),
|
||||||
panel,
|
panel,
|
||||||
};
|
};
|
||||||
try {
|
let addWidget = {
|
||||||
let response = await addingWidgets(selectedZone.zoneId, organization, newWidget);
|
organization: organization,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
if (response.message === "Widget created successfully") {
|
widget: newWidget
|
||||||
setSelectedZone((prev) => ({
|
|
||||||
...prev,
|
|
||||||
widgets: [...prev.widgets, newWidget],
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error adding widget:", error);
|
|
||||||
}
|
}
|
||||||
|
console.log('newWidget: ', newWidget);
|
||||||
|
console.log('addWidget: ', addWidget);
|
||||||
|
if (visualizationSocket) {
|
||||||
|
visualizationSocket.emit("v2:viz-widget:add", addWidget)
|
||||||
|
}
|
||||||
|
setSelectedZone((prev) => ({
|
||||||
|
...prev,
|
||||||
|
widgets: [...prev.widgets, newWidget],
|
||||||
|
}));
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// let response = await addingWidgets(selectedZone.zoneId, organization, newWidget);
|
||||||
|
|
||||||
|
// if (response.message === "Widget created successfully") {
|
||||||
|
// setSelectedZone((prev) => ({
|
||||||
|
// ...prev,
|
||||||
|
// widgets: [...prev.widgets, newWidget],
|
||||||
|
// }));
|
||||||
|
// }
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error("Error adding widget:", error);
|
||||||
|
// }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -191,7 +209,6 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => {
|
const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => {
|
||||||
if (!selectedZone) return; // Ensure selectedZone is not null
|
if (!selectedZone) return; // Ensure selectedZone is not null
|
||||||
|
|
||||||
|
|
||||||
setSelectedZone((prev) => {
|
setSelectedZone((prev) => {
|
||||||
if (!prev) return prev; // Ensure prev is not null
|
if (!prev) return prev; // Ensure prev is not null
|
||||||
|
|
||||||
|
@ -218,7 +235,9 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
{selectedZone.activeSides.map((side) => (
|
{selectedZone.activeSides.map((side) => (
|
||||||
<div
|
<div
|
||||||
key={side}
|
key={side}
|
||||||
className={`panel ${side}-panel absolute ${isPlaying && ""}`}
|
className={`panel ${side}-panel absolute ${isPlaying ? "" : ""} ${
|
||||||
|
hiddenPanels.includes(side) ? "hidePanel" : ""
|
||||||
|
}`}
|
||||||
style={getPanelStyle(side)}
|
style={getPanelStyle(side)}
|
||||||
onDrop={(e) => handleDrop(e, side)}
|
onDrop={(e) => handleDrop(e, side)}
|
||||||
onDragOver={(e) => e.preventDefault()}
|
onDragOver={(e) => e.preventDefault()}
|
||||||
|
|
|
@ -7,10 +7,11 @@ import DisplayZone from "./DisplayZone";
|
||||||
import Scene from "../../../modules/scene/scene";
|
import Scene from "../../../modules/scene/scene";
|
||||||
import useModuleStore from "../../../store/useModuleStore";
|
import useModuleStore from "../../../store/useModuleStore";
|
||||||
|
|
||||||
import DroppedObjects from "./DroppedFloatingWidgets";
|
|
||||||
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
|
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
|
||||||
import {
|
import {
|
||||||
useAsset3dWidget,
|
useAsset3dWidget,
|
||||||
|
useSocketStore,
|
||||||
useWidgetSubOption,
|
useWidgetSubOption,
|
||||||
useZones,
|
useZones,
|
||||||
} from "../../../store/store";
|
} from "../../../store/store";
|
||||||
|
@ -18,6 +19,10 @@ import { getZone2dData } from "../../../services/realTimeVisulization/zoneData/g
|
||||||
import { generateUniqueId } from "../../../functions/generateUniqueId";
|
import { generateUniqueId } from "../../../functions/generateUniqueId";
|
||||||
import { determinePosition } from "./functions/determinePosition";
|
import { determinePosition } from "./functions/determinePosition";
|
||||||
import { addingFloatingWidgets } from "../../../services/realTimeVisulization/zoneData/addFloatingWidgets";
|
import { addingFloatingWidgets } from "../../../services/realTimeVisulization/zoneData/addFloatingWidgets";
|
||||||
|
import SocketRealTimeViz from "../../../modules/visualization/realTimeVizSocket.dev";
|
||||||
|
import RenderOverlay from "../../templates/Overlay";
|
||||||
|
import ConfirmationPopup from "../../layout/confirmationPopup/ConfirmationPopup";
|
||||||
|
import DroppedObjects from "./DroppedFloatingWidgets";
|
||||||
|
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
|
|
||||||
|
@ -51,11 +56,15 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
const [zonesData, setZonesData] = useState<FormattedZoneData>({});
|
const [zonesData, setZonesData] = useState<FormattedZoneData>({});
|
||||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||||
const { zones } = useZones();
|
const { zones } = useZones();
|
||||||
|
|
||||||
|
const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false);
|
||||||
|
|
||||||
const [floatingWidgets, setFloatingWidgets] = useState<
|
const [floatingWidgets, setFloatingWidgets] = useState<
|
||||||
Record<string, { zoneName: string; zoneId: string; objects: any[] }>
|
Record<string, { zoneName: string; zoneId: string; objects: any[] }>
|
||||||
>({});
|
>({});
|
||||||
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
|
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
|
||||||
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
||||||
|
const { visualizationSocket } = useSocketStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function GetZoneData() {
|
async function GetZoneData() {
|
||||||
|
@ -84,9 +93,7 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
setZonesData(formattedData);
|
setZonesData(formattedData);
|
||||||
} catch (error) {
|
} catch (error) {}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GetZoneData();
|
GetZoneData();
|
||||||
|
@ -132,12 +139,13 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
const relativeX = event.clientX - canvasRect.left;
|
const relativeX = event.clientX - canvasRect.left;
|
||||||
const relativeY = event.clientY - canvasRect.top;
|
const relativeY = event.clientY - canvasRect.top;
|
||||||
|
|
||||||
|
const newPosition = determinePosition(canvasRect, relativeX, relativeY)
|
||||||
|
console.log('newPosition: ', newPosition);
|
||||||
const newObject = {
|
const newObject = {
|
||||||
...droppedData,
|
...droppedData,
|
||||||
id: generateUniqueId(),
|
id: generateUniqueId(),
|
||||||
position: determinePosition(canvasRect, relativeX, relativeY),
|
position: determinePosition(canvasRect, relativeX, relativeY),
|
||||||
};
|
};
|
||||||
console.log('newObject: ', newObject);
|
|
||||||
|
|
||||||
let response = await addingFloatingWidgets(
|
let response = await addingFloatingWidgets(
|
||||||
selectedZone.zoneId,
|
selectedZone.zoneId,
|
||||||
|
@ -174,7 +182,7 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -188,6 +196,20 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
|
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{/* <RenderOverlay>
|
||||||
|
<EditWidgetOption
|
||||||
|
options={["Dublicate", "Vertical Move", "Horizontal Move", "Delete"]}
|
||||||
|
/>
|
||||||
|
</RenderOverlay> */}
|
||||||
|
{openConfirmationPopup && (
|
||||||
|
<RenderOverlay>
|
||||||
|
<ConfirmationPopup
|
||||||
|
message={"Are you sure want to delete?"}
|
||||||
|
onConfirm={() => console.log("confirm")}
|
||||||
|
onCancel={() => setOpenConfirmationPopup(false)}
|
||||||
|
/>
|
||||||
|
</RenderOverlay>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
className="scene-container"
|
className="scene-container"
|
||||||
style={{
|
style={{
|
||||||
|
@ -202,6 +224,7 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
<Scene />
|
<Scene />
|
||||||
</div>
|
</div>
|
||||||
{activeModule === "visualization" && selectedZone.zoneName !== "" && <DroppedObjects />}
|
{activeModule === "visualization" && selectedZone.zoneName !== "" && <DroppedObjects />}
|
||||||
|
{activeModule === "visualization" && <SocketRealTimeViz />}
|
||||||
{/* <DroppedObjects /> */}
|
{/* <DroppedObjects /> */}
|
||||||
{activeModule === "visualization" && (
|
{activeModule === "visualization" && (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,69 +1,3 @@
|
||||||
// export function determinePosition(
|
|
||||||
// canvasRect: DOMRect,
|
|
||||||
// relativeX: number,
|
|
||||||
// relativeY: number
|
|
||||||
// ): {
|
|
||||||
// top: number | "auto";
|
|
||||||
// left: number | "auto";
|
|
||||||
// right: number | "auto";
|
|
||||||
// bottom: number | "auto";
|
|
||||||
// } {
|
|
||||||
// // Calculate the midpoints of the canvas
|
|
||||||
// const centerX = canvasRect.width / 2;
|
|
||||||
// const centerY = canvasRect.height / 2;
|
|
||||||
|
|
||||||
// // Initialize position with default values
|
|
||||||
// let position: {
|
|
||||||
// top: number | "auto";
|
|
||||||
// left: number | "auto";
|
|
||||||
// right: number | "auto";
|
|
||||||
// bottom: number | "auto";
|
|
||||||
// };
|
|
||||||
|
|
||||||
// if (relativeY < centerY) {
|
|
||||||
// // Top half
|
|
||||||
// if (relativeX < centerX) {
|
|
||||||
// // Left side
|
|
||||||
// position = {
|
|
||||||
// top: relativeY,
|
|
||||||
// left: relativeX,
|
|
||||||
// right: "auto",
|
|
||||||
// bottom: "auto",
|
|
||||||
// };
|
|
||||||
// } else {
|
|
||||||
// // Right side
|
|
||||||
// position = {
|
|
||||||
// top: relativeY,
|
|
||||||
// right: canvasRect.width - relativeX,
|
|
||||||
// left: "auto",
|
|
||||||
// bottom: "auto",
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// // Bottom half
|
|
||||||
// if (relativeX < centerX) {
|
|
||||||
// // Left side
|
|
||||||
// position = {
|
|
||||||
// bottom: canvasRect.height - relativeY,
|
|
||||||
// left: relativeX,
|
|
||||||
// right: "auto",
|
|
||||||
// top: "auto",
|
|
||||||
// };
|
|
||||||
// } else {
|
|
||||||
// // Right side
|
|
||||||
// position = {
|
|
||||||
// bottom: canvasRect.height - relativeY,
|
|
||||||
// right: canvasRect.width - relativeX,
|
|
||||||
// left: "auto",
|
|
||||||
// top: "auto",
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return position;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function determinePosition(
|
export function determinePosition(
|
||||||
canvasRect: DOMRect,
|
canvasRect: DOMRect,
|
||||||
|
@ -87,36 +21,36 @@ export function determinePosition(
|
||||||
|
|
||||||
if (relativeY < centerY) {
|
if (relativeY < centerY) {
|
||||||
if (relativeX < centerX) {
|
if (relativeX < centerX) {
|
||||||
console.log("Top-left");
|
|
||||||
position = {
|
position = {
|
||||||
top: relativeY,
|
top: relativeY - 41.5,
|
||||||
left: relativeX,
|
left: relativeX - 125,
|
||||||
right: "auto",
|
right: "auto",
|
||||||
bottom: "auto",
|
bottom: "auto",
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
console.log("Top-right");
|
|
||||||
position = {
|
position = {
|
||||||
top: relativeY,
|
top: relativeY - 41.5,
|
||||||
right: canvasRect.width - relativeX,
|
right: canvasRect.width - relativeX - 125,
|
||||||
left: "auto",
|
left: "auto",
|
||||||
bottom: "auto",
|
bottom: "auto",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (relativeX < centerX) {
|
if (relativeX < centerX) {
|
||||||
console.log("Bottom-left");
|
|
||||||
position = {
|
position = {
|
||||||
bottom: canvasRect.height - relativeY,
|
bottom: canvasRect.height - relativeY - 41.5,
|
||||||
left: relativeX,
|
left: relativeX - 125,
|
||||||
right: "auto",
|
right: "auto",
|
||||||
top: "auto",
|
top: "auto",
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
console.log("Bottom-right");
|
|
||||||
position = {
|
position = {
|
||||||
bottom: canvasRect.height - relativeY,
|
bottom: canvasRect.height - relativeY - 41.5,
|
||||||
right: canvasRect.width - relativeX,
|
right: canvasRect.width - relativeX - 125,
|
||||||
left: "auto",
|
left: "auto",
|
||||||
top: "auto",
|
top: "auto",
|
||||||
};
|
};
|
||||||
|
@ -124,4 +58,4 @@ export function determinePosition(
|
||||||
}
|
}
|
||||||
|
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
export const useClickOutside = (
|
||||||
|
ref: React.RefObject<HTMLElement>,
|
||||||
|
callback: () => void
|
||||||
|
) => {
|
||||||
|
useEffect(() => {
|
||||||
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
|
if (ref.current && !event.composedPath().includes(ref.current)) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("mousedown", handleClickOutside);
|
||||||
|
};
|
||||||
|
}, [ref, callback]);
|
||||||
|
};
|
|
@ -8,6 +8,7 @@ interface InputToggleProps {
|
||||||
onChange?: (value: number) => void; // Function to handle toggle clicks
|
onChange?: (value: number) => void; // Function to handle toggle clicks
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
value?: number;
|
value?: number;
|
||||||
|
onPointerUp?: (value: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputRange: React.FC<InputToggleProps> = ({
|
const InputRange: React.FC<InputToggleProps> = ({
|
||||||
|
@ -17,9 +18,10 @@ const InputRange: React.FC<InputToggleProps> = ({
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
disabled,
|
disabled,
|
||||||
value = 5,
|
value,
|
||||||
|
onPointerUp,
|
||||||
}) => {
|
}) => {
|
||||||
const [rangeValue, setRangeValue] = useState<number>(value);
|
const [rangeValue, setRangeValue] = useState<number>(value ? value : 5);
|
||||||
|
|
||||||
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
|
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||||
const newValue = parseInt(e.target.value); // Parse the value to an integer
|
const newValue = parseInt(e.target.value); // Parse the value to an integer
|
||||||
|
@ -31,8 +33,22 @@ const InputRange: React.FC<InputToggleProps> = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRangeValue(value);
|
value && setRangeValue(value);
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
function handlePointerUp(e: React.PointerEvent<HTMLInputElement>) {
|
||||||
|
const newValue = parseInt(e.currentTarget.value, 10); // Parse value correctly
|
||||||
|
|
||||||
|
if (onPointerUp) {
|
||||||
|
onPointerUp(newValue); // Call the callback function if it exists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handlekey(e: React.KeyboardEvent<HTMLInputElement>) {
|
||||||
|
const newValue = parseInt(e.currentTarget.value, 10); // Parse value correctly
|
||||||
|
|
||||||
|
if (onPointerUp) {
|
||||||
|
onPointerUp(newValue); // Call the callback function if it exists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="input-range-container">
|
<div className="input-range-container">
|
||||||
|
@ -52,6 +68,7 @@ const InputRange: React.FC<InputToggleProps> = ({
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
value={rangeValue}
|
value={rangeValue}
|
||||||
|
onPointerUp={handlePointerUp}
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
|
@ -61,6 +78,12 @@ const InputRange: React.FC<InputToggleProps> = ({
|
||||||
value={rangeValue}
|
value={rangeValue}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
onKeyUp={(e) => {
|
||||||
|
if (e.key === "ArrowUp" || e.key === "ArrowDown") {
|
||||||
|
console.log("e.key: ", e.key);
|
||||||
|
handlekey(e);
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface EditWidgetOptionProps {
|
||||||
|
options: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({ options }) => {
|
||||||
|
return (
|
||||||
|
<div className="editWidgetOptions-wrapper">
|
||||||
|
<div className="editWidgetOptions">
|
||||||
|
{options.map((option, index) => (
|
||||||
|
<div className="option" key={index}>
|
||||||
|
{option}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditWidgetOption;
|
|
@ -0,0 +1,105 @@
|
||||||
|
import { StockIncreseIcon } from "../../../icons/RealTimeVisulationIcons";
|
||||||
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
|
import { Line } from "react-chartjs-2";
|
||||||
|
import io from "socket.io-client";
|
||||||
|
import useChartStore from "../../../../store/useChartStore";
|
||||||
|
import { useWidgetStore } from "../../../../store/useWidgetStore";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const ProgressCard1 = ({ id,title,}: {
|
||||||
|
id: string,
|
||||||
|
title: string;
|
||||||
|
}) => {
|
||||||
|
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||||
|
const [measurements, setmeasurements] = useState<any>({});
|
||||||
|
const [duration, setDuration] = useState("1h")
|
||||||
|
const [name, setName] = useState(title)
|
||||||
|
const [value, setValue] = useState<any>('')
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const socket = io(`http://${iotApiUrl}`);
|
||||||
|
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||||
|
|
||||||
|
const inputData = {
|
||||||
|
measurements,
|
||||||
|
duration,
|
||||||
|
interval: 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const startStream = () => {
|
||||||
|
socket.emit("lastInput", inputData);
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.on("connect", startStream);
|
||||||
|
|
||||||
|
socket.on("lastOutput", (response) => {
|
||||||
|
const responseData = response.input1;
|
||||||
|
setValue(responseData);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.off("lastOutput");
|
||||||
|
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
}, [measurements, duration]);
|
||||||
|
|
||||||
|
const fetchSavedInputes = async() => {
|
||||||
|
|
||||||
|
if (id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setmeasurements(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setName(response.data.widgetName)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedChartId?.id === id) {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,[chartMeasurements, chartDuration, widgetName])
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="chart progressBar">
|
||||||
|
<div className="header">{name}</div>
|
||||||
|
<div className="stock">
|
||||||
|
<span className="stock-item">
|
||||||
|
<span className="stockValues">
|
||||||
|
<div className="value">{value}</div>
|
||||||
|
<div className="key">Units</div>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
<div className="stock-description">{
|
||||||
|
measurements ? `${measurements?.input1?.fields}` : 'description'}</div>
|
||||||
|
</span>
|
||||||
|
<div className="icon">
|
||||||
|
<StockIncreseIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProgressCard1;
|
|
@ -0,0 +1,125 @@
|
||||||
|
import { StockIncreseIcon } from "../../../icons/RealTimeVisulationIcons";
|
||||||
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
|
import { Line } from "react-chartjs-2";
|
||||||
|
import io from "socket.io-client";
|
||||||
|
import useChartStore from "../../../../store/useChartStore";
|
||||||
|
import { useWidgetStore } from "../../../../store/useWidgetStore";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const ProgressCard2 = ({ id,title,}: {
|
||||||
|
id: string,
|
||||||
|
title: string;
|
||||||
|
}) => {
|
||||||
|
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||||
|
const [measurements, setmeasurements] = useState<any>({});
|
||||||
|
const [duration, setDuration] = useState("1h")
|
||||||
|
const [name, setName] = useState(title)
|
||||||
|
const [value1, setValue1] = useState<any>('')
|
||||||
|
const [value2, setValue2] = useState<any>('')
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||||
|
|
||||||
|
const socket = io(`http://${iotApiUrl}`);
|
||||||
|
|
||||||
|
const inputData = {
|
||||||
|
measurements,
|
||||||
|
duration,
|
||||||
|
interval: 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const startStream = () => {
|
||||||
|
socket.emit("lastInput", inputData);
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.on("connect", startStream);
|
||||||
|
|
||||||
|
socket.on("lastOutput", (response) => {
|
||||||
|
const responseData1 = response.input1;
|
||||||
|
const responseData2 = response.input2;
|
||||||
|
setValue1(responseData1);
|
||||||
|
setValue2(responseData2);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.off("lastOutput");
|
||||||
|
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
}, [measurements, duration]);
|
||||||
|
|
||||||
|
const fetchSavedInputes = async() => {
|
||||||
|
|
||||||
|
if (id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setmeasurements(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setName(response.data.widgetName)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedChartId?.id === id) {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,[chartMeasurements, chartDuration, widgetName])
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="chart progressBar">
|
||||||
|
<div className="header">{name}</div>
|
||||||
|
|
||||||
|
<div className="stock">
|
||||||
|
<span className="stock-item">
|
||||||
|
<span className="stockValues">
|
||||||
|
<div className="value">{value1}</div>
|
||||||
|
<div className="key">Units</div>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
<div className="stock-description">{
|
||||||
|
measurements ? `${measurements?.input1?.fields}` : 'description'}</div>
|
||||||
|
</span>
|
||||||
|
<div className="icon">
|
||||||
|
<StockIncreseIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="stock">
|
||||||
|
<span className="stock-item">
|
||||||
|
<span className="stockValues">
|
||||||
|
<div className="value">{value2}</div>
|
||||||
|
<div className="key">Units</div>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
<div className="stock-description">{
|
||||||
|
measurements ? `${measurements?.input2?.fields}` : 'description'}</div>
|
||||||
|
</span>
|
||||||
|
<div className="icon">
|
||||||
|
<StockIncreseIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProgressCard2;
|
|
@ -1,8 +1,8 @@
|
||||||
const FleetEfficiency = () => {
|
const FleetEfficiency = () => {
|
||||||
const progress = 75; // Example progress value (0-100)
|
const progress = 50; // Example progress value (0-100)
|
||||||
|
|
||||||
// Calculate the rotation angle for the progress bar
|
// Calculate the rotation angle for the progress bar
|
||||||
const rotationAngle = -90 + progress * 3.6; // Progress starts from the left (-90°)
|
const rotationAngle = 45 + progress * 1.8;
|
||||||
|
|
||||||
const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
|
const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
|
||||||
const rect = event.currentTarget.getBoundingClientRect(); // Get position
|
const rect = event.currentTarget.getBoundingClientRect(); // Get position
|
||||||
|
|
|
@ -1,19 +1,99 @@
|
||||||
import React from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
|
import { Line } from 'react-chartjs-2'
|
||||||
|
import useChartStore from '../../../../store/useChartStore';
|
||||||
|
import { useWidgetStore } from '../../../../store/useWidgetStore';
|
||||||
|
import axios from 'axios';
|
||||||
|
import io from "socket.io-client";
|
||||||
|
|
||||||
type Props = {}
|
const FleetEfficiencyComponent = ({object}: any) => {
|
||||||
|
const [ progress, setProgress ] = useState<any>(0)
|
||||||
|
const [measurements, setmeasurements] = useState<any>({});
|
||||||
|
const [duration, setDuration] = useState("1h")
|
||||||
|
const [name, setName] = useState(object.header ? object.header : '')
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
const { header, flotingDuration, flotingMeasurements } = useChartStore();
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
|
||||||
const FleetEfficiencyComponent = ({
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
object
|
|
||||||
}: any) => {
|
// Calculate the rotation angle for the progress bar
|
||||||
|
const rotationAngle = 45 + progress * 1.8;
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||||
|
|
||||||
|
const socket = io(`http://${iotApiUrl}`);
|
||||||
|
|
||||||
|
const inputData = {
|
||||||
|
measurements,
|
||||||
|
duration,
|
||||||
|
interval: 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const startStream = () => {
|
||||||
|
socket.emit("lastInput", inputData);
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.on("connect", startStream);
|
||||||
|
|
||||||
|
socket.on("lastOutput", (response) => {
|
||||||
|
const responseData = response.input1;
|
||||||
|
console.log(responseData);
|
||||||
|
|
||||||
|
if (typeof responseData === "number") {
|
||||||
|
console.log("It's a number!");
|
||||||
|
setProgress(responseData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.off("lastOutput");
|
||||||
|
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
}, [measurements, duration, iotApiUrl]);
|
||||||
|
|
||||||
|
const fetchSavedInputes = async() => {
|
||||||
|
|
||||||
|
if (object?.id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setmeasurements(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setName(response.data.header)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedChartId?.id === object?.id) {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,[header, flotingDuration, flotingMeasurements])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h2 className="header">Fleet Efficiency</h2>
|
<h2 className="header">{name}</h2>
|
||||||
<div className="progressContainer">
|
<div className="progressContainer">
|
||||||
<div className="progress">
|
<div className="progress">
|
||||||
<div className="barOverflow">
|
<div className="barOverflow">
|
||||||
<div
|
<div
|
||||||
className="bar"
|
className="bar"
|
||||||
style={{ transform: `rotate(${object.value}deg)` }}
|
style={{ transform: `rotate(${rotationAngle}deg)` }}
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,7 +101,7 @@ const FleetEfficiencyComponent = ({
|
||||||
<div className="scaleLabels">
|
<div className="scaleLabels">
|
||||||
<span>0%</span>
|
<span>0%</span>
|
||||||
<div className="centerText">
|
<div className="centerText">
|
||||||
<div className="percentage">{object.per}%</div>
|
<div className="percentage">{progress}%</div>
|
||||||
<div className="status">Optimal</div>
|
<div className="status">Optimal</div>
|
||||||
</div>
|
</div>
|
||||||
<span>100%</span>
|
<span>100%</span>
|
||||||
|
|
|
@ -1,21 +1,95 @@
|
||||||
import React from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { WalletIcon } from '../../../icons/3dChartIcons'
|
import { Line } from 'react-chartjs-2'
|
||||||
|
import useChartStore from '../../../../store/useChartStore';
|
||||||
import { useWidgetStore } from '../../../../store/useWidgetStore';
|
import { useWidgetStore } from '../../../../store/useWidgetStore';
|
||||||
|
import axios from 'axios';
|
||||||
|
import io from "socket.io-client";
|
||||||
|
import { WalletIcon } from '../../../icons/3dChartIcons';
|
||||||
|
|
||||||
|
|
||||||
const TotalCardComponent = ({
|
const TotalCardComponent = ({
|
||||||
object
|
object
|
||||||
}: any) => {
|
}: any) => {
|
||||||
|
|
||||||
const { setSelectedChartId } =
|
const [ progress, setProgress ] = useState<any>(0)
|
||||||
useWidgetStore();
|
const [measurements, setmeasurements] = useState<any>({});
|
||||||
|
const [duration, setDuration] = useState("1h")
|
||||||
|
const [name, setName] = useState(object.header ? object.header : '')
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
const { header, flotingDuration, flotingMeasurements } = useChartStore();
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||||
|
|
||||||
|
const socket = io(`http://${iotApiUrl}`);
|
||||||
|
|
||||||
|
const inputData = {
|
||||||
|
measurements,
|
||||||
|
duration,
|
||||||
|
interval: 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const startStream = () => {
|
||||||
|
socket.emit("lastInput", inputData);
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.on("connect", startStream);
|
||||||
|
|
||||||
|
socket.on("lastOutput", (response) => {
|
||||||
|
const responseData = response.input1;
|
||||||
|
|
||||||
|
if (typeof responseData === "number") {
|
||||||
|
setProgress(responseData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.off("lastOutput");
|
||||||
|
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
}, [measurements, duration, iotApiUrl]);
|
||||||
|
|
||||||
|
const fetchSavedInputes = async() => {
|
||||||
|
|
||||||
|
if (object?.id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setmeasurements(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setName(response.data.header)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedChartId?.id === object?.id) {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,[header, flotingDuration, flotingMeasurements])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="header-wrapper" onClick={() => {
|
<div className="header-wrapper" >
|
||||||
setSelectedChartId(object.id)
|
<div className="header">{name}</div>
|
||||||
}}>
|
|
||||||
<div className="header">{object.header}</div>
|
|
||||||
<div className="data-values">
|
<div className="data-values">
|
||||||
<div className="value">{object.value}</div>
|
<div className="value">{progress}</div>
|
||||||
<div className="per">{object.per}</div>
|
<div className="per">{object.per}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import React, { useState } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { Line } from 'react-chartjs-2'
|
import { Line } from 'react-chartjs-2'
|
||||||
|
import useChartStore from '../../../../store/useChartStore';
|
||||||
|
import { useWidgetStore } from '../../../../store/useWidgetStore';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import io from "socket.io-client";
|
||||||
|
|
||||||
const WarehouseThroughputComponent = ({
|
const WarehouseThroughputComponent = ({
|
||||||
object
|
object
|
||||||
|
@ -8,6 +11,17 @@ const WarehouseThroughputComponent = ({
|
||||||
|
|
||||||
const [measurements, setmeasurements] = useState<any>({});
|
const [measurements, setmeasurements] = useState<any>({});
|
||||||
const [duration, setDuration] = useState("1h")
|
const [duration, setDuration] = useState("1h")
|
||||||
|
const [name, setName] = useState(object.header ? object.header : '')
|
||||||
|
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
|
||||||
|
labels: [],
|
||||||
|
datasets: [],
|
||||||
|
});
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]
|
||||||
|
const { header, flotingDuration, flotingMeasurements } = useChartStore();
|
||||||
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
|
||||||
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
|
||||||
const lineGraphData = {
|
const lineGraphData = {
|
||||||
labels: [
|
labels: [
|
||||||
|
@ -95,35 +109,94 @@ const WarehouseThroughputComponent = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// const fetchSavedInputes = async() => {
|
useEffect(() => {
|
||||||
|
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||||
|
|
||||||
|
const socket = io(`http://${iotApiUrl}`);
|
||||||
|
|
||||||
|
const inputData = {
|
||||||
|
measurements,
|
||||||
|
duration,
|
||||||
|
interval: 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const startStream = () => {
|
||||||
|
socket.emit("lineInput", inputData);
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.on("connect", startStream);
|
||||||
|
|
||||||
|
socket.on("lineOutput", (response) => {
|
||||||
|
const responseData = response.data;
|
||||||
|
|
||||||
|
// Extract timestamps and values
|
||||||
|
const labels = responseData.time;
|
||||||
|
const datasets = Object.keys(measurements).map((key) => {
|
||||||
|
const measurement = measurements[key];
|
||||||
|
const datasetKey = `${measurement.name}.${measurement.fields}`;
|
||||||
|
return {
|
||||||
|
label: datasetKey,
|
||||||
|
data: responseData[datasetKey]?.values ?? [],
|
||||||
|
borderColor: "#6f42c1", // Use the desired color for the line (purple)
|
||||||
|
backgroundColor: "rgba(111, 66, 193, 0.2)", // Use a semi-transparent purple for the fill
|
||||||
|
borderWidth: 2, // Line thickness
|
||||||
|
fill: true, // Enable fill for this dataset
|
||||||
|
pointRadius: 0, // Remove dots at each data point
|
||||||
|
tension: 0.5, // Smooth interpolation for the line
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setChartData({ labels, datasets });
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.off("lineOutput");
|
||||||
|
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
}, [measurements, duration, iotApiUrl]);
|
||||||
|
|
||||||
|
const fetchSavedInputes = async() => {
|
||||||
|
|
||||||
|
if (object?.id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setmeasurements(response.data.Data.measurements)
|
||||||
|
setDuration(response.data.Data.duration)
|
||||||
|
setName(response.data.header)
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedChartId?.id === object?.id) {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,[header, flotingDuration, flotingMeasurements])
|
||||||
|
|
||||||
// if (object.id !== "") {
|
|
||||||
// try {
|
|
||||||
// const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}/api/v2/WidgetData/${id}/${organization}`);
|
|
||||||
// if (response.status === 200) {
|
|
||||||
// setmeasurements(response.data.Data.measurements)
|
|
||||||
// setDuration(response.data.Data.duration)
|
|
||||||
// setName(response.data.widgetName)
|
|
||||||
// } else {
|
|
||||||
// console.log("Unexpected response:", response);
|
|
||||||
// }
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error("There was an error!", error);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<h2>Warehouse Throughput</h2>
|
<h2>{name}</h2>
|
||||||
<p>
|
{/* <p>
|
||||||
<span>(+5) more</span> in 2025
|
<span>(+5) more</span> in 2025
|
||||||
</p>
|
</p> */}
|
||||||
</div>
|
</div>
|
||||||
<div className="lineGraph" style={{ height: "100%" }}>
|
<div className="lineGraph" style={{ height: "100%" }}>
|
||||||
<Line data={lineGraphData} options={lineGraphOptions} />
|
<Line data={ Object.keys(measurements).length > 0 ? chartData : lineGraphData} options={lineGraphOptions} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,10 +1,26 @@
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useActiveTool, useAsset3dWidget, useCamMode, useDeletableFloorItem, useDeleteModels, useFloorItems, useLoadingProgress, useRenderDistance, useselectedFloorItem, useSelectedItem, useSocketStore, useToggleView, useTransformMode } from "../../../store/store";
|
import {
|
||||||
|
useActiveTool,
|
||||||
|
useAsset3dWidget,
|
||||||
|
useCamMode,
|
||||||
|
useDeletableFloorItem,
|
||||||
|
useDeleteModels,
|
||||||
|
useFloorItems,
|
||||||
|
useLoadingProgress,
|
||||||
|
useRenderDistance,
|
||||||
|
useselectedFloorItem,
|
||||||
|
useSelectedItem,
|
||||||
|
useSocketStore,
|
||||||
|
useToggleView,
|
||||||
|
useTransformMode,
|
||||||
|
} from "../../../store/store";
|
||||||
import assetVisibility from "../geomentries/assets/assetVisibility";
|
import assetVisibility from "../geomentries/assets/assetVisibility";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import * as Types from "../../../types/world/worldTypes";
|
import * as Types from "../../../types/world/worldTypes";
|
||||||
import assetManager, { cancelOngoingTasks } from "../geomentries/assets/assetManager";
|
import assetManager, {
|
||||||
|
cancelOngoingTasks,
|
||||||
|
} from "../geomentries/assets/assetManager";
|
||||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||||
import DeletableHoveredFloorItems from "../geomentries/assets/deletableHoveredFloorItems";
|
import DeletableHoveredFloorItems from "../geomentries/assets/deletableHoveredFloorItems";
|
||||||
|
@ -14,318 +30,405 @@ import addAssetModel from "../geomentries/assets/addAssetModel";
|
||||||
import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
|
import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
|
||||||
import useModuleStore from "../../../store/useModuleStore";
|
import useModuleStore from "../../../store/useModuleStore";
|
||||||
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
|
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
|
||||||
const assetManagerWorker = new Worker(new URL('../../../services/factoryBuilder/webWorkers/assetManagerWorker.js', import.meta.url));
|
const assetManagerWorker = new Worker(
|
||||||
const gltfLoaderWorker = new Worker(new URL('../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js', import.meta.url));
|
new URL(
|
||||||
|
"../../../services/factoryBuilder/webWorkers/assetManagerWorker.js",
|
||||||
|
import.meta.url
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const gltfLoaderWorker = new Worker(
|
||||||
|
new URL(
|
||||||
|
"../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js",
|
||||||
|
import.meta.url
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane }: any) => {
|
const FloorItemsGroup = ({
|
||||||
const state: Types.ThreeState = useThree();
|
itemsGroup,
|
||||||
const { raycaster, controls }: any = state;
|
hoveredDeletableFloorItem,
|
||||||
const { renderDistance } = useRenderDistance();
|
AttachedObject,
|
||||||
const { toggleView } = useToggleView();
|
floorGroup,
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
tempLoader,
|
||||||
const { camMode } = useCamMode();
|
isTempLoader,
|
||||||
const { deleteModels } = useDeleteModels();
|
plane,
|
||||||
const { setDeletableFloorItem } = useDeletableFloorItem();
|
}: any) => {
|
||||||
const { transformMode } = useTransformMode();
|
const state: Types.ThreeState = useThree();
|
||||||
const { setselectedFloorItem } = useselectedFloorItem();
|
const { raycaster, controls }: any = state;
|
||||||
const { activeTool } = useActiveTool();
|
const { renderDistance } = useRenderDistance();
|
||||||
const { selectedItem, setSelectedItem } = useSelectedItem();
|
const { toggleView } = useToggleView();
|
||||||
const { setLoadingProgress } = useLoadingProgress();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
const { activeModule } = useModuleStore();
|
const { camMode } = useCamMode();
|
||||||
const { socket } = useSocketStore();
|
const { deleteModels } = useDeleteModels();
|
||||||
const loader = new GLTFLoader();
|
const { setDeletableFloorItem } = useDeletableFloorItem();
|
||||||
const dracoLoader = new DRACOLoader();
|
const { transformMode } = useTransformMode();
|
||||||
|
const { setselectedFloorItem } = useselectedFloorItem();
|
||||||
|
const { activeTool } = useActiveTool();
|
||||||
|
const { selectedItem, setSelectedItem } = useSelectedItem();
|
||||||
|
const { setLoadingProgress } = useLoadingProgress();
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
const loader = new GLTFLoader();
|
||||||
|
const dracoLoader = new DRACOLoader();
|
||||||
|
|
||||||
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
dracoLoader.setDecoderPath(
|
||||||
loader.setDRACOLoader(dracoLoader);
|
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
||||||
|
);
|
||||||
|
loader.setDRACOLoader(dracoLoader);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const email = localStorage.getItem('email');
|
const email = localStorage.getItem("email");
|
||||||
const organization = (email!.split("@")[1]).split(".")[0];
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
let totalAssets = 0;
|
let totalAssets = 0;
|
||||||
let loadedAssets = 0;
|
let loadedAssets = 0;
|
||||||
|
|
||||||
const updateLoadingProgress = (progress: number) => {
|
const updateLoadingProgress = (progress: number) => {
|
||||||
if (progress < 100) {
|
if (progress < 100) {
|
||||||
setLoadingProgress(progress);
|
setLoadingProgress(progress);
|
||||||
} else if (progress === 100) {
|
} else if (progress === 100) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setLoadingProgress(100);
|
setLoadingProgress(100);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setLoadingProgress(0);
|
setLoadingProgress(0);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
getFloorAssets(organization).then((data) => {
|
getFloorAssets(organization).then((data) => {
|
||||||
const uniqueItems = (data as Types.FloorItems).filter((item, index, self) =>
|
const uniqueItems = (data as Types.FloorItems).filter(
|
||||||
index === self.findIndex((t) => t.modelfileID === item.modelfileID)
|
(item, index, self) =>
|
||||||
);
|
index === self.findIndex((t) => t.modelfileID === item.modelfileID)
|
||||||
totalAssets = uniqueItems.length;
|
);
|
||||||
if (totalAssets === 0) {
|
totalAssets = uniqueItems.length;
|
||||||
updateLoadingProgress(100);
|
if (totalAssets === 0) {
|
||||||
return;
|
updateLoadingProgress(100);
|
||||||
}
|
return;
|
||||||
gltfLoaderWorker.postMessage({ floorItems: data });
|
}
|
||||||
|
gltfLoaderWorker.postMessage({ floorItems: data });
|
||||||
|
});
|
||||||
|
|
||||||
|
gltfLoaderWorker.onmessage = async (event) => {
|
||||||
|
if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
|
||||||
|
const blobUrl = URL.createObjectURL(event.data.modelBlob);
|
||||||
|
|
||||||
|
loader.load(blobUrl, (gltf) => {
|
||||||
|
URL.revokeObjectURL(blobUrl);
|
||||||
|
THREE.Cache.remove(blobUrl);
|
||||||
|
THREE.Cache.add(event.data.modelID, gltf);
|
||||||
|
|
||||||
|
loadedAssets++;
|
||||||
|
const progress = Math.round((loadedAssets / totalAssets) * 100);
|
||||||
|
updateLoadingProgress(progress);
|
||||||
|
|
||||||
|
if (loadedAssets === totalAssets) {
|
||||||
|
loadInitialFloorItems(itemsGroup, setFloorItems);
|
||||||
|
updateLoadingProgress(100);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
gltfLoaderWorker.onmessage = async (event) => {
|
useEffect(() => {
|
||||||
if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
|
assetManagerWorker.onmessage = async (event) => {
|
||||||
const blobUrl = URL.createObjectURL(event.data.modelBlob);
|
cancelOngoingTasks(); // Cancel the ongoing process
|
||||||
|
await assetManager(event.data, itemsGroup, loader);
|
||||||
|
};
|
||||||
|
}, [assetManagerWorker]);
|
||||||
|
|
||||||
loader.load(blobUrl, (gltf) => {
|
useEffect(() => {
|
||||||
URL.revokeObjectURL(blobUrl);
|
if (toggleView) return;
|
||||||
THREE.Cache.remove(blobUrl);
|
|
||||||
THREE.Cache.add(event.data.modelID, gltf);
|
|
||||||
|
|
||||||
loadedAssets++;
|
const uuids: string[] = [];
|
||||||
const progress = Math.round((loadedAssets / totalAssets) * 100);
|
itemsGroup.current?.children.forEach((child: any) => {
|
||||||
updateLoadingProgress(progress);
|
uuids.push(child.uuid);
|
||||||
|
});
|
||||||
|
const cameraPosition = state.camera.position;
|
||||||
|
|
||||||
if (loadedAssets === totalAssets) {
|
assetManagerWorker.postMessage({
|
||||||
loadInitialFloorItems(itemsGroup, setFloorItems);
|
floorItems,
|
||||||
updateLoadingProgress(100);
|
cameraPosition,
|
||||||
}
|
uuids,
|
||||||
});
|
renderDistance,
|
||||||
}
|
});
|
||||||
};
|
}, [camMode, renderDistance]);
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
assetManagerWorker.onmessage = async (event) => {
|
const controls: any = state.controls;
|
||||||
cancelOngoingTasks(); // Cancel the ongoing process
|
const camera: any = state.camera;
|
||||||
await assetManager(event.data, itemsGroup, loader);
|
|
||||||
};
|
|
||||||
}, [assetManagerWorker]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
if (controls) {
|
||||||
if (toggleView) return
|
let intervalId: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
|
const handleChange = () => {
|
||||||
|
if (toggleView) return;
|
||||||
|
|
||||||
const uuids: string[] = [];
|
const uuids: string[] = [];
|
||||||
itemsGroup.current?.children.forEach((child: any) => {
|
itemsGroup.current?.children.forEach((child: any) => {
|
||||||
uuids.push(child.uuid);
|
uuids.push(child.uuid);
|
||||||
});
|
});
|
||||||
const cameraPosition = state.camera.position;
|
const cameraPosition = camera.position;
|
||||||
|
|
||||||
assetManagerWorker.postMessage({ floorItems, cameraPosition, uuids, renderDistance });
|
assetManagerWorker.postMessage({
|
||||||
}, [camMode, renderDistance]);
|
floorItems,
|
||||||
|
cameraPosition,
|
||||||
|
uuids,
|
||||||
|
renderDistance,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const startInterval = () => {
|
||||||
const controls: any = state.controls;
|
if (!intervalId) {
|
||||||
const camera: any = state.camera;
|
intervalId = setInterval(handleChange, 50);
|
||||||
|
|
||||||
if (controls) {
|
|
||||||
let intervalId: NodeJS.Timeout | null = null;
|
|
||||||
|
|
||||||
const handleChange = () => {
|
|
||||||
if (toggleView) return
|
|
||||||
|
|
||||||
const uuids: string[] = [];
|
|
||||||
itemsGroup.current?.children.forEach((child: any) => {
|
|
||||||
uuids.push(child.uuid);
|
|
||||||
});
|
|
||||||
const cameraPosition = camera.position;
|
|
||||||
|
|
||||||
assetManagerWorker.postMessage({ floorItems, cameraPosition, uuids, renderDistance });
|
|
||||||
};
|
|
||||||
|
|
||||||
const startInterval = () => {
|
|
||||||
if (!intervalId) {
|
|
||||||
intervalId = setInterval(handleChange, 50);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const stopInterval = () => {
|
|
||||||
handleChange();
|
|
||||||
if (intervalId) {
|
|
||||||
clearInterval(intervalId);
|
|
||||||
intervalId = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
controls.addEventListener('rest', handleChange);
|
|
||||||
controls.addEventListener('rest', stopInterval);
|
|
||||||
controls.addEventListener('control', startInterval);
|
|
||||||
controls.addEventListener('controlend', stopInterval);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
controls.removeEventListener('rest', handleChange);
|
|
||||||
controls.removeEventListener('rest', stopInterval);
|
|
||||||
controls.removeEventListener('control', startInterval);
|
|
||||||
controls.removeEventListener('controlend', stopInterval);
|
|
||||||
if (intervalId) {
|
|
||||||
clearInterval(intervalId);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}, [state.controls, floorItems, toggleView, renderDistance]);
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const stopInterval = () => {
|
||||||
const canvasElement = state.gl.domElement;
|
handleChange();
|
||||||
let drag = false;
|
if (intervalId) {
|
||||||
let isLeftMouseDown = false;
|
clearInterval(intervalId);
|
||||||
|
intervalId = null;
|
||||||
const onMouseDown = (evt: any) => {
|
|
||||||
if (evt.button === 0) {
|
|
||||||
isLeftMouseDown = true;
|
|
||||||
drag = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseMove = () => {
|
|
||||||
if (isLeftMouseDown) {
|
|
||||||
drag = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseUp = async (evt: any) => {
|
|
||||||
if (controls) {
|
|
||||||
(controls as any).enabled = true;
|
|
||||||
}
|
|
||||||
if (evt.button === 0) {
|
|
||||||
isLeftMouseDown = false;
|
|
||||||
if (drag) return;
|
|
||||||
|
|
||||||
if (deleteModels) {
|
|
||||||
DeleteFloorItems(itemsGroup, hoveredDeletableFloorItem, setFloorItems, socket);
|
|
||||||
}
|
|
||||||
const Mode = transformMode;
|
|
||||||
|
|
||||||
if (Mode !== null || activeTool === "cursor") {
|
|
||||||
if (!itemsGroup.current) return;
|
|
||||||
let intersects = raycaster.intersectObjects(itemsGroup.current.children, true);
|
|
||||||
if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
|
|
||||||
// let currentObject = intersects[0].object;
|
|
||||||
|
|
||||||
// while (currentObject) {
|
|
||||||
// if (currentObject.name === "Scene") {
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// currentObject = currentObject.parent as THREE.Object3D;
|
|
||||||
// }
|
|
||||||
// if (currentObject) {
|
|
||||||
// AttachedObject.current = currentObject as any;
|
|
||||||
// setselectedFloorItem(AttachedObject.current!);
|
|
||||||
// }
|
|
||||||
} else {
|
|
||||||
const target = controls.getTarget(new THREE.Vector3());
|
|
||||||
await controls.setTarget(target.x, 0, target.z, true);
|
|
||||||
setselectedFloorItem(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDblClick = async (evt: any) => {
|
|
||||||
if (evt.button === 0) {
|
|
||||||
isLeftMouseDown = false;
|
|
||||||
if (drag) return;
|
|
||||||
|
|
||||||
const Mode = transformMode;
|
|
||||||
|
|
||||||
if (Mode !== null || activeTool === "cursor") {
|
|
||||||
if (!itemsGroup.current) return;
|
|
||||||
let intersects = raycaster.intersectObjects(itemsGroup.current.children, true);
|
|
||||||
if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
|
|
||||||
let currentObject = intersects[0].object;
|
|
||||||
|
|
||||||
while (currentObject) {
|
|
||||||
if (currentObject.name === "Scene") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
currentObject = currentObject.parent as THREE.Object3D;
|
|
||||||
}
|
|
||||||
if (currentObject) {
|
|
||||||
AttachedObject.current = currentObject as any;
|
|
||||||
// controls.fitToSphere(AttachedObject.current!, true);
|
|
||||||
|
|
||||||
const bbox = new THREE.Box3().setFromObject(AttachedObject.current);
|
|
||||||
const size = bbox.getSize(new THREE.Vector3());
|
|
||||||
const center = bbox.getCenter(new THREE.Vector3());
|
|
||||||
|
|
||||||
const front = new THREE.Vector3(0, 0, 1);
|
|
||||||
AttachedObject.current.localToWorld(front);
|
|
||||||
front.sub(AttachedObject.current.position).normalize();
|
|
||||||
|
|
||||||
const distance = Math.max(size.x, size.y, size.z) * 2;
|
|
||||||
const newPosition = center.clone().addScaledVector(front, distance);
|
|
||||||
|
|
||||||
controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true);
|
|
||||||
controls.setTarget(center.x, center.y, center.z, true);
|
|
||||||
controls.fitToBox(AttachedObject.current!, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5 });
|
|
||||||
|
|
||||||
setselectedFloorItem(AttachedObject.current!);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const target = controls.getTarget(new THREE.Vector3());
|
|
||||||
await controls.setTarget(target.x, 0, target.z, true);
|
|
||||||
setselectedFloorItem(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const onDrop = (event: any) => {
|
controls.addEventListener("rest", handleChange);
|
||||||
|
controls.addEventListener("rest", stopInterval);
|
||||||
|
controls.addEventListener("control", startInterval);
|
||||||
|
controls.addEventListener("controlend", stopInterval);
|
||||||
|
|
||||||
if (!event.dataTransfer?.files[0]) return;
|
return () => {
|
||||||
|
controls.removeEventListener("rest", handleChange);
|
||||||
if (selectedItem.id !== "" && event.dataTransfer?.files[0]) {
|
controls.removeEventListener("rest", stopInterval);
|
||||||
addAssetModel(raycaster, state.camera, state.pointer, floorGroup, setFloorItems, itemsGroup, isTempLoader, tempLoader, socket, selectedItem, setSelectedItem, plane);
|
controls.removeEventListener("control", startInterval);
|
||||||
}
|
controls.removeEventListener("controlend", stopInterval);
|
||||||
|
if (intervalId) {
|
||||||
|
clearInterval(intervalId);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [state.controls, floorItems, toggleView, renderDistance]);
|
||||||
|
|
||||||
const onDragOver = (event: any) => {
|
useEffect(() => {
|
||||||
event.preventDefault();
|
const canvasElement = state.gl.domElement;
|
||||||
};
|
let drag = false;
|
||||||
|
let isLeftMouseDown = false;
|
||||||
|
|
||||||
if (activeModule === "builder") {
|
const onMouseDown = (evt: any) => {
|
||||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
if (evt.button === 0) {
|
||||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
isLeftMouseDown = true;
|
||||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
drag = false;
|
||||||
canvasElement.addEventListener("dblclick", onDblClick);
|
}
|
||||||
canvasElement.addEventListener("drop", onDrop);
|
};
|
||||||
canvasElement.addEventListener("dragover", onDragOver);
|
|
||||||
} else {
|
|
||||||
if (controls) {
|
|
||||||
const target = controls.getTarget(new THREE.Vector3());
|
|
||||||
controls.setTarget(target.x, 0, target.z, true);
|
|
||||||
setselectedFloorItem(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
const onMouseMove = () => {
|
||||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
if (isLeftMouseDown) {
|
||||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
drag = true;
|
||||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
}
|
||||||
canvasElement.removeEventListener("dblclick", onDblClick);
|
};
|
||||||
canvasElement.removeEventListener("drop", onDrop);
|
|
||||||
canvasElement.removeEventListener("dragover", onDragOver);
|
|
||||||
};
|
|
||||||
}, [deleteModels, transformMode, controls, selectedItem, state.camera, state.pointer, activeTool, activeModule]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
const onMouseUp = async (evt: any) => {
|
||||||
// console.log('floorItems: ', floorItems);
|
if (controls) {
|
||||||
}, [floorItems])
|
(controls as any).enabled = true;
|
||||||
|
}
|
||||||
|
if (evt.button === 0) {
|
||||||
|
isLeftMouseDown = false;
|
||||||
|
if (drag) return;
|
||||||
|
|
||||||
useFrame(() => {
|
|
||||||
if (controls)
|
|
||||||
assetVisibility(itemsGroup, state.camera.position, renderDistance);
|
|
||||||
if (deleteModels) {
|
if (deleteModels) {
|
||||||
DeletableHoveredFloorItems(state, itemsGroup, hoveredDeletableFloorItem, setDeletableFloorItem);
|
DeleteFloorItems(
|
||||||
} else if (!deleteModels) {
|
itemsGroup,
|
||||||
if (hoveredDeletableFloorItem.current) {
|
hoveredDeletableFloorItem,
|
||||||
hoveredDeletableFloorItem.current = undefined;
|
setFloorItems,
|
||||||
setDeletableFloorItem(null);
|
socket
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
})
|
const Mode = transformMode;
|
||||||
|
|
||||||
return (
|
if (Mode !== null || activeTool === "cursor") {
|
||||||
<group ref={itemsGroup} name="itemsGroup">
|
if (!itemsGroup.current) return;
|
||||||
</group>
|
let intersects = raycaster.intersectObjects(
|
||||||
)
|
itemsGroup.current.children,
|
||||||
}
|
true
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
intersects.length > 0 &&
|
||||||
|
intersects[0]?.object?.parent?.parent?.position &&
|
||||||
|
intersects[0]?.object?.parent?.parent?.scale &&
|
||||||
|
intersects[0]?.object?.parent?.parent?.rotation
|
||||||
|
) {
|
||||||
|
// let currentObject = intersects[0].object;
|
||||||
|
// while (currentObject) {
|
||||||
|
// if (currentObject.name === "Scene") {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// currentObject = currentObject.parent as THREE.Object3D;
|
||||||
|
// }
|
||||||
|
// if (currentObject) {
|
||||||
|
// AttachedObject.current = currentObject as any;
|
||||||
|
// setselectedFloorItem(AttachedObject.current!);
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
const target = controls.getTarget(new THREE.Vector3());
|
||||||
|
await controls.setTarget(target.x, 0, target.z, true);
|
||||||
|
setselectedFloorItem(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default FloorItemsGroup;
|
const onDblClick = async (evt: any) => {
|
||||||
|
if (evt.button === 0) {
|
||||||
|
isLeftMouseDown = false;
|
||||||
|
if (drag) return;
|
||||||
|
|
||||||
|
const Mode = transformMode;
|
||||||
|
|
||||||
|
if (Mode !== null || activeTool === "cursor") {
|
||||||
|
if (!itemsGroup.current) return;
|
||||||
|
let intersects = raycaster.intersectObjects(
|
||||||
|
itemsGroup.current.children,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
intersects.length > 0 &&
|
||||||
|
intersects[0]?.object?.parent?.parent?.position &&
|
||||||
|
intersects[0]?.object?.parent?.parent?.scale &&
|
||||||
|
intersects[0]?.object?.parent?.parent?.rotation
|
||||||
|
) {
|
||||||
|
let currentObject = intersects[0].object;
|
||||||
|
|
||||||
|
while (currentObject) {
|
||||||
|
if (currentObject.name === "Scene") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
currentObject = currentObject.parent as THREE.Object3D;
|
||||||
|
}
|
||||||
|
if (currentObject) {
|
||||||
|
AttachedObject.current = currentObject as any;
|
||||||
|
// controls.fitToSphere(AttachedObject.current!, true);
|
||||||
|
|
||||||
|
const bbox = new THREE.Box3().setFromObject(
|
||||||
|
AttachedObject.current
|
||||||
|
);
|
||||||
|
const size = bbox.getSize(new THREE.Vector3());
|
||||||
|
const center = bbox.getCenter(new THREE.Vector3());
|
||||||
|
|
||||||
|
const front = new THREE.Vector3(0, 0, 1);
|
||||||
|
AttachedObject.current.localToWorld(front);
|
||||||
|
front.sub(AttachedObject.current.position).normalize();
|
||||||
|
|
||||||
|
const distance = Math.max(size.x, size.y, size.z) * 2;
|
||||||
|
const newPosition = center
|
||||||
|
.clone()
|
||||||
|
.addScaledVector(front, distance);
|
||||||
|
|
||||||
|
controls.setPosition(
|
||||||
|
newPosition.x,
|
||||||
|
newPosition.y,
|
||||||
|
newPosition.z,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
controls.setTarget(center.x, center.y, center.z, true);
|
||||||
|
controls.fitToBox(AttachedObject.current!, true, {
|
||||||
|
cover: true,
|
||||||
|
paddingTop: 5,
|
||||||
|
paddingLeft: 5,
|
||||||
|
paddingBottom: 5,
|
||||||
|
paddingRight: 5,
|
||||||
|
});
|
||||||
|
|
||||||
|
setselectedFloorItem(AttachedObject.current!);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const target = controls.getTarget(new THREE.Vector3());
|
||||||
|
await controls.setTarget(target.x, 0, target.z, true);
|
||||||
|
setselectedFloorItem(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDrop = (event: any) => {
|
||||||
|
if (!event.dataTransfer?.files[0]) return;
|
||||||
|
|
||||||
|
if (selectedItem.id !== "" && event.dataTransfer?.files[0]) {
|
||||||
|
addAssetModel(
|
||||||
|
raycaster,
|
||||||
|
state.camera,
|
||||||
|
state.pointer,
|
||||||
|
floorGroup,
|
||||||
|
setFloorItems,
|
||||||
|
itemsGroup,
|
||||||
|
isTempLoader,
|
||||||
|
tempLoader,
|
||||||
|
socket,
|
||||||
|
selectedItem,
|
||||||
|
setSelectedItem,
|
||||||
|
plane
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDragOver = (event: any) => {
|
||||||
|
event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (activeModule === "builder") {
|
||||||
|
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.addEventListener("dblclick", onDblClick);
|
||||||
|
canvasElement.addEventListener("drop", onDrop);
|
||||||
|
canvasElement.addEventListener("dragover", onDragOver);
|
||||||
|
} else {
|
||||||
|
if (controls) {
|
||||||
|
const target = controls.getTarget(new THREE.Vector3());
|
||||||
|
controls.setTarget(target.x, 0, target.z, true);
|
||||||
|
setselectedFloorItem(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.removeEventListener("dblclick", onDblClick);
|
||||||
|
canvasElement.removeEventListener("drop", onDrop);
|
||||||
|
canvasElement.removeEventListener("dragover", onDragOver);
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
deleteModels,
|
||||||
|
transformMode,
|
||||||
|
controls,
|
||||||
|
selectedItem,
|
||||||
|
state.camera,
|
||||||
|
state.pointer,
|
||||||
|
activeTool,
|
||||||
|
activeModule,
|
||||||
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {}, [floorItems]);
|
||||||
|
|
||||||
|
useFrame(() => {
|
||||||
|
if (controls)
|
||||||
|
assetVisibility(itemsGroup, state.camera.position, renderDistance);
|
||||||
|
if (deleteModels) {
|
||||||
|
DeletableHoveredFloorItems(
|
||||||
|
state,
|
||||||
|
itemsGroup,
|
||||||
|
hoveredDeletableFloorItem,
|
||||||
|
setDeletableFloorItem
|
||||||
|
);
|
||||||
|
} else if (!deleteModels) {
|
||||||
|
if (hoveredDeletableFloorItem.current) {
|
||||||
|
hoveredDeletableFloorItem.current = undefined;
|
||||||
|
setDeletableFloorItem(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return <group ref={itemsGroup} name="itemsGroup"></group>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FloorItemsGroup;
|
||||||
|
|
|
@ -57,7 +57,6 @@ const FilterSearch: React.FC<ModelsProps> = ({
|
||||||
const filteredModel = filteredModels?.filter((model) =>
|
const filteredModel = filteredModels?.filter((model) =>
|
||||||
model.filename.toLowerCase().includes(val.toLowerCase())
|
model.filename.toLowerCase().includes(val.toLowerCase())
|
||||||
);
|
);
|
||||||
|
|
||||||
setModels(filteredModel);
|
setModels(filteredModel);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ const MarketPlace = () => {
|
||||||
const filteredAssets = async () => {
|
const filteredAssets = async () => {
|
||||||
try {
|
try {
|
||||||
const filt = await getAssetImages("67d934ad0f42a1fdadb19aa6");
|
const filt = await getAssetImages("67d934ad0f42a1fdadb19aa6");
|
||||||
|
|
||||||
setModels(filt.items);
|
setModels(filt.items);
|
||||||
setFilteredModels(filt.items);
|
setFilteredModels(filt.items);
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
|
@ -1,22 +1,52 @@
|
||||||
import { useToggleView } from '../../../store/store';
|
import { useTileDistance, useToggleView } from "../../../store/store";
|
||||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||||
|
|
||||||
const Ground = ({ grid, plane }: any) => {
|
const Ground = ({ grid, plane }: any) => {
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const savedTheme: string | null = localStorage.getItem('theme');
|
const savedTheme: string | null = localStorage.getItem("theme");
|
||||||
|
const { planeValue, gridValue } = useTileDistance();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<mesh name="Ground">
|
||||||
<mesh name="Ground">
|
<mesh
|
||||||
<mesh ref={grid} name="Grid" position={!toggleView ? CONSTANTS.gridConfig.position3D : CONSTANTS.gridConfig.position2D}>
|
ref={grid}
|
||||||
<gridHelper args={[CONSTANTS.gridConfig.size, CONSTANTS.gridConfig.divisions, CONSTANTS.gridConfig.primaryColor, CONSTANTS.gridConfig.secondaryColor]} />
|
name="Grid"
|
||||||
</mesh>
|
position={
|
||||||
<mesh ref={plane} rotation-x={CONSTANTS.planeConfig.rotation} position={!toggleView ? CONSTANTS.planeConfig.position3D : CONSTANTS.planeConfig.position2D} name="Plane" receiveShadow>
|
!toggleView
|
||||||
<planeGeometry args={[CONSTANTS.planeConfig.width, CONSTANTS.planeConfig.height]} />
|
? CONSTANTS.gridConfig.position3D
|
||||||
<meshBasicMaterial color={CONSTANTS.planeConfig.color} />
|
: CONSTANTS.gridConfig.position2D
|
||||||
</mesh>
|
}
|
||||||
</mesh>
|
>
|
||||||
)
|
<gridHelper
|
||||||
}
|
args={[
|
||||||
|
gridValue.size,
|
||||||
|
gridValue.divisions,
|
||||||
|
// CONSTANTS.gridConfig.size,
|
||||||
|
// CONSTANTS.gridConfig.divisions,
|
||||||
|
CONSTANTS.gridConfig.primaryColor,
|
||||||
|
CONSTANTS.gridConfig.secondaryColor,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
<mesh
|
||||||
|
ref={plane}
|
||||||
|
rotation-x={CONSTANTS.planeConfig.rotation}
|
||||||
|
position={
|
||||||
|
!toggleView
|
||||||
|
? CONSTANTS.planeConfig.position3D
|
||||||
|
: CONSTANTS.planeConfig.position2D
|
||||||
|
}
|
||||||
|
name="Plane"
|
||||||
|
receiveShadow
|
||||||
|
>
|
||||||
|
<planeGeometry
|
||||||
|
args={[planeValue.width, planeValue.height]}
|
||||||
|
// args={[CONSTANTS.planeConfig.width, CONSTANTS.planeConfig.height]}
|
||||||
|
/>
|
||||||
|
<meshBasicMaterial color={CONSTANTS.planeConfig.color} />
|
||||||
|
</mesh>
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default Ground;
|
export default Ground;
|
||||||
|
|
|
@ -1,9 +1,22 @@
|
||||||
import { useRef, useEffect} from 'react';
|
import { useRef, useEffect } from "react";
|
||||||
import { useThree } from '@react-three/fiber';
|
import { useThree } from "@react-three/fiber";
|
||||||
import * as THREE from 'three';
|
import * as THREE from "three";
|
||||||
import { useAzimuth, useElevation, useShadows, useSunPosition, useFloorItems, useWallItems } from '../../../store/store';
|
import {
|
||||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
useAzimuth,
|
||||||
const shadowWorker = new Worker(new URL('../../../services/factoryBuilder/webWorkers/shadowWorker', import.meta.url));
|
useElevation,
|
||||||
|
useShadows,
|
||||||
|
useSunPosition,
|
||||||
|
useFloorItems,
|
||||||
|
useWallItems,
|
||||||
|
useTileDistance,
|
||||||
|
} from "../../../store/store";
|
||||||
|
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||||
|
const shadowWorker = new Worker(
|
||||||
|
new URL(
|
||||||
|
"../../../services/factoryBuilder/webWorkers/shadowWorker",
|
||||||
|
import.meta.url
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
export default function Shadows() {
|
export default function Shadows() {
|
||||||
const { shadows, setShadows } = useShadows();
|
const { shadows, setShadows } = useShadows();
|
||||||
|
@ -15,6 +28,7 @@ export default function Shadows() {
|
||||||
const { azimuth, setAzimuth } = useAzimuth();
|
const { azimuth, setAzimuth } = useAzimuth();
|
||||||
const { floorItems } = useFloorItems();
|
const { floorItems } = useFloorItems();
|
||||||
const { wallItems } = useWallItems();
|
const { wallItems } = useWallItems();
|
||||||
|
const { planeValue } = useTileDistance();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
gl.shadowMap.enabled = true;
|
gl.shadowMap.enabled = true;
|
||||||
|
@ -48,9 +62,9 @@ export default function Shadows() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (controls && shadows) {
|
if (controls && shadows) {
|
||||||
updateShadows();
|
updateShadows();
|
||||||
(controls as any).addEventListener('update', updateShadows);
|
(controls as any).addEventListener("update", updateShadows);
|
||||||
return () => {
|
return () => {
|
||||||
(controls as any).removeEventListener('update', updateShadows);
|
(controls as any).removeEventListener("update", updateShadows);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [controls, elevation, azimuth, shadows]);
|
}, [controls, elevation, azimuth, shadows]);
|
||||||
|
@ -75,10 +89,24 @@ export default function Shadows() {
|
||||||
shadow-normalBias={CONSTANTS.shadowConfig.shadownormalBias}
|
shadow-normalBias={CONSTANTS.shadowConfig.shadownormalBias}
|
||||||
/>
|
/>
|
||||||
<object3D ref={targetRef} />
|
<object3D ref={targetRef} />
|
||||||
<mesh position={CONSTANTS.shadowConfig.shadowMaterialPosition} rotation={CONSTANTS.shadowConfig.shadowMaterialRotation} receiveShadow>
|
<mesh
|
||||||
<planeGeometry args={[CONSTANTS.planeConfig.width, CONSTANTS.planeConfig.height]} />
|
position={CONSTANTS.shadowConfig.shadowMaterialPosition}
|
||||||
<shadowMaterial opacity={CONSTANTS.shadowConfig.shadowMaterialOpacity} transparent />
|
rotation={CONSTANTS.shadowConfig.shadowMaterialRotation}
|
||||||
|
receiveShadow
|
||||||
|
>
|
||||||
|
{/* <planeGeometry
|
||||||
|
args={[CONSTANTS.planeConfig.width, CONSTANTS.planeConfig.height]}
|
||||||
|
/>
|
||||||
|
<shadowMaterial
|
||||||
|
opacity={CONSTANTS.shadowConfig.shadowMaterialOpacity}
|
||||||
|
transparent
|
||||||
|
/> */}
|
||||||
|
<planeGeometry args={[planeValue.width, planeValue.height]} />
|
||||||
|
<shadowMaterial
|
||||||
|
opacity={CONSTANTS.shadowConfig.shadowMaterialOpacity}
|
||||||
|
transparent
|
||||||
|
/>
|
||||||
</mesh>
|
</mesh>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@ import {
|
||||||
useWalls,
|
useWalls,
|
||||||
useToolMode,
|
useToolMode,
|
||||||
useRefTextUpdate,
|
useRefTextUpdate,
|
||||||
|
useRenderDistance,
|
||||||
|
useLimitDistance,
|
||||||
} from "../../../store/store";
|
} from "../../../store/store";
|
||||||
|
|
||||||
////////// 3D Function Imports //////////
|
////////// 3D Function Imports //////////
|
||||||
|
@ -118,6 +120,8 @@ export default function World() {
|
||||||
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
|
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
|
||||||
const { wallVisibility, setWallVisibility } = useWallVisibility();
|
const { wallVisibility, setWallVisibility } = useWallVisibility();
|
||||||
const { shadows, setShadows } = useShadows();
|
const { shadows, setShadows } = useShadows();
|
||||||
|
const { renderDistance, setRenderDistance } = useRenderDistance();
|
||||||
|
const { limitDistance, setLimitDistance } = useLimitDistance();
|
||||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||||
const { walls, setWalls } = useWalls();
|
const { walls, setWalls } = useWalls();
|
||||||
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
|
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
|
||||||
|
@ -202,6 +206,8 @@ export default function World() {
|
||||||
setRoofVisibility(visibility.roofVisibility);
|
setRoofVisibility(visibility.roofVisibility);
|
||||||
setWallVisibility(visibility.wallVisibility);
|
setWallVisibility(visibility.wallVisibility);
|
||||||
setShadows(visibility.shadowVisibility);
|
setShadows(visibility.shadowVisibility);
|
||||||
|
setRenderDistance(visibility.renderDistance);
|
||||||
|
setLimitDistance(visibility.limitDistance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchVisibility();
|
fetchVisibility();
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { useSocketStore } from "../../store/store";
|
||||||
|
import { useSelectedZoneStore } from "../../store/useZoneStore";
|
||||||
|
|
||||||
|
export default function SocketRealTimeViz() {
|
||||||
|
const { visualizationSocket } = useSocketStore();
|
||||||
|
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||||
|
useEffect(() => {
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
if (visualizationSocket) {
|
||||||
|
//add panel response
|
||||||
|
visualizationSocket.on("viz-panel:response:updates", (addPanel: any) => {
|
||||||
|
if (addPanel.success) {
|
||||||
|
let addPanelData = addPanel.data.data
|
||||||
|
setSelectedZone(addPanelData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//delete panel response
|
||||||
|
visualizationSocket.on("viz-panel:response:delete", (deletePanel: any) => {
|
||||||
|
if (deletePanel.success) {
|
||||||
|
let deletePanelData = deletePanel.data.data
|
||||||
|
setSelectedZone(deletePanelData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// add 2dWidget
|
||||||
|
visualizationSocket.on("viz-widget:response:updates", (response: any) => {
|
||||||
|
console.log('response: ', response);
|
||||||
|
if (response.success && response.data) {
|
||||||
|
setSelectedZone((prev) => {
|
||||||
|
const isWidgetAlreadyAdded = prev.widgets.some(
|
||||||
|
(widget) => widget.id === response.data.widgetData.id
|
||||||
|
);
|
||||||
|
if (isWidgetAlreadyAdded) return prev; // Prevent duplicate addition
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
zoneId: response.data.zoneId,
|
||||||
|
zoneName: response.data.zoneName,
|
||||||
|
widgets: [...prev.widgets, response.data.widgetData], // Append new widget
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//delete 2D Widget
|
||||||
|
visualizationSocket.on("viz-widget:response:delete", (deleteWidget: any) => {
|
||||||
|
console.log('deleteWidget: ', deleteWidget);
|
||||||
|
if (deleteWidget?.success && deleteWidget.data) {
|
||||||
|
setSelectedZone((prevZone: any) => ({
|
||||||
|
...prevZone,
|
||||||
|
zoneId: deleteWidget.data.zoneId,
|
||||||
|
zoneName: deleteWidget.data.zoneName,
|
||||||
|
widgets: deleteWidget.data.widgetDeleteDatas, // Replace with new widget list
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
}, [selectedZone])
|
||||||
|
return (
|
||||||
|
<></>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import ModuleToggle from "../components/ui/ModuleToggle";
|
import ModuleToggle from "../components/ui/ModuleToggle";
|
||||||
import SideBarLeft from "../components/layout/sidebarLeft/SideBarLeft";
|
import SideBarLeft from "../components/layout/sidebarLeft/SideBarLeft";
|
||||||
import SideBarRight from "../components/layout/sidebarRight/SideBarRight";
|
import SideBarRight from "../components/layout/sidebarRight/SideBarRight";
|
||||||
|
@ -20,6 +20,8 @@ import { usePlayButtonStore } from "../store/usePlayButtonStore";
|
||||||
import MarketPlace from "../modules/market/MarketPlace";
|
import MarketPlace from "../modules/market/MarketPlace";
|
||||||
import LoadingPage from "../components/templates/LoadingPage";
|
import LoadingPage from "../components/templates/LoadingPage";
|
||||||
import SimulationPlayer from "../components/ui/simulation/simulationPlayer";
|
import SimulationPlayer from "../components/ui/simulation/simulationPlayer";
|
||||||
|
import RenderOverlay from "../components/templates/Overlay";
|
||||||
|
import MenuBar from "../components/ui/menu/menu";
|
||||||
|
|
||||||
const Project: React.FC = () => {
|
const Project: React.FC = () => {
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
@ -30,6 +32,7 @@ const Project: React.FC = () => {
|
||||||
const { setFloorItems } = useFloorItems();
|
const { setFloorItems } = useFloorItems();
|
||||||
const { setWallItems } = useWallItems();
|
const { setWallItems } = useWallItems();
|
||||||
const { setZones } = useZones();
|
const { setZones } = useZones();
|
||||||
|
const [openMenu, setOpenMenu] = useState<boolean>(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFloorItems([]);
|
setFloorItems([]);
|
||||||
|
@ -61,6 +64,9 @@ const Project: React.FC = () => {
|
||||||
<SideBarRight />
|
<SideBarRight />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{/* <RenderOverlay>
|
||||||
|
<MenuBar setOpenMenu={setOpenMenu} />
|
||||||
|
</RenderOverlay> */}
|
||||||
{activeModule === "market" && <MarketPlace />}
|
{activeModule === "market" && <MarketPlace />}
|
||||||
<RealTimeVisulization />
|
<RealTimeVisulization />
|
||||||
{activeModule !== "market" && <Tools />}
|
{activeModule !== "market" && <Tools />}
|
||||||
|
|
|
@ -1,32 +1,43 @@
|
||||||
import { setEnvironment } from './setEnvironment';
|
import { setEnvironment } from "./setEnvironment";
|
||||||
|
|
||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
|
||||||
export const findEnvironment = async (organization: string, userId: string) => {
|
export const findEnvironment = async (organization: string, userId: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${url_Backend_dwinzo}/api/v1/findEnvironments/${organization}/${userId}`, {
|
const response = await fetch(
|
||||||
method: "GET",
|
`${url_Backend_dwinzo}/api/v1/findEnvironments/${organization}/${userId}`,
|
||||||
headers: {
|
{
|
||||||
"Content-Type": "application/json",
|
method: "GET",
|
||||||
},
|
headers: {
|
||||||
});
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("Failed to get wall and roof visibility");
|
throw new Error("Failed to get wall and roof visibility");
|
||||||
}
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
if (result === "user not found") {
|
|
||||||
const userpos = setEnvironment(organization, userId, false, false, false);
|
|
||||||
return userpos;
|
|
||||||
} else {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof Error) {
|
|
||||||
throw new Error(error.message);
|
|
||||||
} else {
|
|
||||||
throw new Error("An unknown error occurred");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
const result = await response.json();
|
||||||
|
if (result === "user not found") {
|
||||||
|
const userpos = setEnvironment(
|
||||||
|
organization,
|
||||||
|
userId,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
return userpos;
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -1,26 +1,45 @@
|
||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
|
||||||
export const setEnvironment = async (organization: string, userId: string, wallVisibility: Boolean, roofVisibility: Boolean, shadowVisibility: Boolean) => {
|
export const setEnvironment = async (
|
||||||
try {
|
organization: string,
|
||||||
const response = await fetch(`${url_Backend_dwinzo}/api/v1/setEvironments`, {
|
userId: string,
|
||||||
method: "POST",
|
wallVisibility: Boolean,
|
||||||
headers: {
|
roofVisibility: Boolean,
|
||||||
"Content-Type": "application/json",
|
shadowVisibility: Boolean,
|
||||||
},
|
renderDistance: number,
|
||||||
body: JSON.stringify({ organization, userId, wallVisibility, roofVisibility, shadowVisibility }),
|
limitDistance: boolean
|
||||||
});
|
) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${url_Backend_dwinzo}/api/v1/setEvironments`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
organization,
|
||||||
|
userId,
|
||||||
|
wallVisibility,
|
||||||
|
roofVisibility,
|
||||||
|
shadowVisibility,
|
||||||
|
renderDistance,
|
||||||
|
limitDistance,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("Failed to set wall and roof visibility");
|
throw new Error("Failed to set wall and roof visibility");
|
||||||
}
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
return result;
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof Error) {
|
|
||||||
throw new Error(error.message);
|
|
||||||
} else {
|
|
||||||
throw new Error("An unknown error occurred");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -6,8 +6,8 @@ export const fetchAssets = async () => {
|
||||||
throw new Error("Network response was not ok");
|
throw new Error("Network response was not ok");
|
||||||
}
|
}
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
const last10Assets = result.slice(-10);
|
// const last10Assets = result.slice(-10);
|
||||||
console.log('last10Assets: ', last10Assets);
|
// console.log('last10Assets: ', last10Assets);
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("error: ", error);
|
console.log("error: ", error);
|
||||||
|
|
|
@ -6,9 +6,9 @@ export const addingFloatingWidgets = async (
|
||||||
organization: string,
|
organization: string,
|
||||||
widget: {}
|
widget: {}
|
||||||
) => {
|
) => {
|
||||||
console.log('organization: ', organization);
|
|
||||||
console.log('widget: ', widget);
|
|
||||||
console.log('zoneId: ', zoneId);
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${url_Backend_dwinzo}/api/v2/floatwidget/save`,
|
`${url_Backend_dwinzo}/api/v2/floatwidget/save`,
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
|
||||||
|
|
||||||
|
export const deletePanelApi = async (
|
||||||
|
zoneId: string,
|
||||||
|
panelName: string,
|
||||||
|
organization: string
|
||||||
|
) => {
|
||||||
|
console.log('panelName: ', panelName);
|
||||||
|
console.log('organization: ', organization);
|
||||||
|
console.log('zoneId: ', zoneId);
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/panel/delete`, {
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ organization, zoneId, panelName }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to delete widget in the zone");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,8 +0,0 @@
|
||||||
import { create } from "zustand";
|
|
||||||
|
|
||||||
const useFloatingDataStore = create((set) => ({
|
|
||||||
floatingdata: [], // Initial state
|
|
||||||
setfloatingadata: (newData: []) => set({ floatingdata: newData }), // Setter function
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default useFloatingDataStore;
|
|
|
@ -11,16 +11,28 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, {
|
const socket = io(
|
||||||
reconnection: false,
|
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}`,
|
||||||
auth: { email, organization },
|
{
|
||||||
});
|
reconnection: false,
|
||||||
|
auth: { email, organization },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
set({ socket });
|
const visualizationSocket = io(
|
||||||
|
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`,
|
||||||
|
{
|
||||||
|
reconnection: false,
|
||||||
|
auth: { email, organization },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
set({ socket, visualizationSocket });
|
||||||
},
|
},
|
||||||
disconnectSocket: () => {
|
disconnectSocket: () => {
|
||||||
set((state: any) => {
|
set((state: any) => {
|
||||||
state.socket?.disconnect();
|
state.socket?.disconnect();
|
||||||
|
state.visualizationSocket?.disconnect();
|
||||||
return { socket: null };
|
return { socket: null };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -205,7 +217,9 @@ export const useActiveLayer = create<any>((set: any) => ({
|
||||||
|
|
||||||
interface RefTextUpdateState {
|
interface RefTextUpdateState {
|
||||||
refTextupdate: number;
|
refTextupdate: number;
|
||||||
setRefTextUpdate: (callback: (currentValue: number) => number | number) => void;
|
setRefTextUpdate: (
|
||||||
|
callback: (currentValue: number) => number | number
|
||||||
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useRefTextUpdate = create<RefTextUpdateState>((set) => ({
|
export const useRefTextUpdate = create<RefTextUpdateState>((set) => ({
|
||||||
|
@ -213,7 +227,9 @@ export const useRefTextUpdate = create<RefTextUpdateState>((set) => ({
|
||||||
setRefTextUpdate: (callback) =>
|
setRefTextUpdate: (callback) =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
refTextupdate:
|
refTextupdate:
|
||||||
typeof callback === "function" ? callback(state.refTextupdate) : callback,
|
typeof callback === "function"
|
||||||
|
? callback(state.refTextupdate)
|
||||||
|
: callback,
|
||||||
})),
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -248,7 +264,7 @@ export const useAzimuth = create<any>((set: any) => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const useRenderDistance = create<any>((set: any) => ({
|
export const useRenderDistance = create<any>((set: any) => ({
|
||||||
renderDistance: 50,
|
renderDistance: 40,
|
||||||
setRenderDistance: (x: any) => set({ renderDistance: x }),
|
setRenderDistance: (x: any) => set({ renderDistance: x }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -393,4 +409,22 @@ export const useWidgetSubOption = create<any>((set: any) => ({
|
||||||
widgetSubOption: "2D",
|
widgetSubOption: "2D",
|
||||||
setWidgetSubOption: (x: any) => set({ widgetSubOption: x }),
|
setWidgetSubOption: (x: any) => set({ widgetSubOption: x }),
|
||||||
}));
|
}));
|
||||||
|
export const useLimitDistance = create<any>((set: any) => ({
|
||||||
|
limitDistance: true,
|
||||||
|
setLimitDistance: (x: any) => set({ limitDistance: x }),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const useTileDistance = create<any>((set: any) => ({
|
||||||
|
gridValue: { size: 300, divisions: 75 },
|
||||||
|
planeValue: { height: 300, width: 300 },
|
||||||
|
|
||||||
|
setGridValue: (value: any) =>
|
||||||
|
set((state: any) => ({
|
||||||
|
gridValue: { ...state.gridValue, ...value },
|
||||||
|
})),
|
||||||
|
|
||||||
|
setPlaneValue: (value: any) =>
|
||||||
|
set((state: any) => ({
|
||||||
|
planeValue: { ...state.planeValue, ...value },
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
|
|
@ -10,9 +10,15 @@ interface MeasurementStore {
|
||||||
interval: number;
|
interval: number;
|
||||||
duration: string;
|
duration: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
header: string;
|
||||||
|
flotingDuration: string;
|
||||||
|
flotingMeasurements: Record<string, Measurement>; // Change array to Record<string, Measurement>
|
||||||
setMeasurements: (newMeasurements: Record<string, Measurement>) => void;
|
setMeasurements: (newMeasurements: Record<string, Measurement>) => void;
|
||||||
updateDuration: (newDuration: string) => void;
|
updateDuration: (newDuration: string) => void;
|
||||||
updateName: (newName: string) => void;
|
updateName: (newName: string) => void;
|
||||||
|
updateHeader: (newHeader: string) => void;
|
||||||
|
updateFlotingDuration: (newFlotingDuration: string) => void;
|
||||||
|
setFlotingMeasurements: (newFlotingMeasurements: Record<string, Measurement>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useChartStore = create<MeasurementStore>((set) => ({
|
const useChartStore = create<MeasurementStore>((set) => ({
|
||||||
|
@ -20,6 +26,9 @@ const useChartStore = create<MeasurementStore>((set) => ({
|
||||||
interval: 1000,
|
interval: 1000,
|
||||||
duration: "1h",
|
duration: "1h",
|
||||||
name:'',
|
name:'',
|
||||||
|
header:'',
|
||||||
|
flotingDuration: "1h",
|
||||||
|
flotingMeasurements: {},
|
||||||
|
|
||||||
setMeasurements: (newMeasurements) =>
|
setMeasurements: (newMeasurements) =>
|
||||||
set(() => ({ measurements: newMeasurements })),
|
set(() => ({ measurements: newMeasurements })),
|
||||||
|
@ -28,7 +37,16 @@ const useChartStore = create<MeasurementStore>((set) => ({
|
||||||
set(() => ({ duration: newDuration })),
|
set(() => ({ duration: newDuration })),
|
||||||
|
|
||||||
updateName: (newName) =>
|
updateName: (newName) =>
|
||||||
set(() => ({ duration: newName })),
|
set(() => ({ name: newName })),
|
||||||
|
|
||||||
|
updateHeader: (newHeader) =>
|
||||||
|
set(() => ({ header: newHeader })),
|
||||||
|
|
||||||
|
updateFlotingDuration: (newFlotingDuration) =>
|
||||||
|
set(() => ({ flotingDuration: newFlotingDuration })),
|
||||||
|
|
||||||
|
setFlotingMeasurements: (newFlotingMeasurements) =>
|
||||||
|
set(() => ({ flotingMeasurements: newFlotingMeasurements })),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default useChartStore;
|
export default useChartStore;
|
||||||
|
|
|
@ -36,7 +36,7 @@ type DroppedObjectsState = {
|
||||||
bottom: number | "auto";
|
bottom: number | "auto";
|
||||||
}
|
}
|
||||||
) => void;
|
) => void;
|
||||||
deleteObject: (zoneName: string, index: number) => void; // Add this line
|
deleteObject: (zoneName: string, id: string, index: number) => void; // Add this line
|
||||||
duplicateObject: (zoneName: string, index: number) => void; // Add this line
|
duplicateObject: (zoneName: string, index: number) => void; // Add this line
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,15 +77,16 @@ export const useDroppedObjectsStore = create<DroppedObjectsState>((set) => ({
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
deleteObject: (zoneName: string, index: number) =>
|
deleteObject: (zoneName: string, id: string, index: number) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const zone = state.zones[zoneName];
|
const zone = state.zones[zoneName];
|
||||||
|
console.log("zone: ", zone);
|
||||||
if (!zone) return state;
|
if (!zone) return state;
|
||||||
return {
|
return {
|
||||||
zones: {
|
zones: {
|
||||||
[zoneName]: {
|
[zoneName]: {
|
||||||
...zone,
|
...zone,
|
||||||
objects: zone.objects.filter((_, i) => i !== index), // Remove object at the given index
|
objects: zone.objects.filter((obj) => obj.id !== id), // Remove object at the given index
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
.confirmation-overlay {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background: var(--background-color-secondary);
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
|
||||||
|
.confirmation-modal {
|
||||||
|
min-width: 35%;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: 5;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
padding: 14px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
.buttton-wrapper {
|
||||||
|
padding-top: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: end;
|
||||||
|
align-items: end;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.confirmation-button {
|
||||||
|
padding: 6px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
background-color: #ffe3e0;
|
||||||
|
color: #f65648;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -551,7 +551,7 @@ input {
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-value {
|
.input-value {
|
||||||
width: 40px;
|
width: 42px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
&::-webkit-inner-spin-button,
|
&::-webkit-inner-spin-button,
|
||||||
&::-webkit-outer-spin-button {
|
&::-webkit-outer-spin-button {
|
||||||
|
|
|
@ -113,7 +113,9 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
.assets-container {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
.icon {
|
.icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 12px;
|
top: 12px;
|
||||||
|
|
|
@ -253,7 +253,7 @@
|
||||||
|
|
||||||
.user-profile-container {
|
.user-profile-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
.user-profile{
|
.user-profile {
|
||||||
background: var(--accent-color);
|
background: var(--accent-color);
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
@ -320,9 +320,7 @@
|
||||||
.dataSideBar {
|
.dataSideBar {
|
||||||
.inputs-wrapper {
|
.inputs-wrapper {
|
||||||
.datas {
|
.datas {
|
||||||
|
|
||||||
.input-value {
|
.input-value {
|
||||||
|
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,7 +686,7 @@
|
||||||
font-weight: var(--font-weight-regular);
|
font-weight: var(--font-weight-regular);
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
}
|
}
|
||||||
.input-toggle-container{
|
.input-toggle-container {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
@ -963,6 +961,7 @@
|
||||||
padding: 0 6px;
|
padding: 0 6px;
|
||||||
|
|
||||||
.assets-wrapper {
|
.assets-wrapper {
|
||||||
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 8px 10px;
|
margin: 8px 10px;
|
||||||
|
|
||||||
|
@ -1010,9 +1009,11 @@
|
||||||
top: 50%;
|
top: 50%;
|
||||||
right: -10px;
|
right: -10px;
|
||||||
transform: translate(0, -50%);
|
transform: translate(0, -50%);
|
||||||
background: linear-gradient(144.19deg,
|
background: linear-gradient(
|
||||||
#f1e7cd 16.62%,
|
144.19deg,
|
||||||
#fffaef 85.81%);
|
#f1e7cd 16.62%,
|
||||||
|
#fffaef 85.81%
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.category-image {
|
.category-image {
|
||||||
|
@ -1075,4 +1076,52 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.assets-container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
height: 100%;
|
||||||
|
gap: 3px;
|
||||||
|
padding: 10px 0;
|
||||||
|
|
||||||
|
.assets {
|
||||||
|
width: 117px;
|
||||||
|
height: 95px;
|
||||||
|
border-radius: 3.59px;
|
||||||
|
background-color: var(--background-color-gray);
|
||||||
|
padding: 8px;
|
||||||
|
padding-top: 12px;
|
||||||
|
font-weight: $medium-weight;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.asset-name {
|
||||||
|
position: relative;
|
||||||
|
z-index: 3;
|
||||||
|
font-size: var(--font-size-regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset-image {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
// top: 50%;
|
||||||
|
// right: 5px;
|
||||||
|
// transform: translate(0, -50%);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.assets-result {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 8px 10px;
|
||||||
|
.assets-wrapper {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
@use 'components/marketPlace/marketPlace';
|
@use 'components/marketPlace/marketPlace';
|
||||||
@use 'components/simulation/simulation';
|
@use 'components/simulation/simulation';
|
||||||
@use 'components/menu/menu';
|
@use 'components/menu/menu';
|
||||||
|
@use 'components/confirmationPopUp';
|
||||||
|
|
||||||
// layout
|
// layout
|
||||||
@use 'layout/loading';
|
@use 'layout/loading';
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
border-radius: $border-radius-medium;
|
border-radius: $border-radius-medium;
|
||||||
padding: 18px;
|
padding: 18px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1000;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scene-container {
|
.scene-container {
|
||||||
|
@ -172,6 +172,7 @@
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
overflow: visible !important;
|
overflow: visible !important;
|
||||||
z-index: $z-index-tools;
|
z-index: $z-index-tools;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
.panel-content {
|
.panel-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -320,6 +321,10 @@
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel.hidePanel {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.playingFlase {
|
.playingFlase {
|
||||||
|
@ -545,20 +550,21 @@
|
||||||
|
|
||||||
.floating-wrapper {
|
.floating-wrapper {
|
||||||
.icon {
|
.icon {
|
||||||
width: 25px !important;
|
// width: 25px !important;
|
||||||
height: 25px !important;
|
// height: 25px !important;
|
||||||
background-color: transparent;
|
// background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kebab {
|
.kebab {
|
||||||
width: 30px;
|
width: 25px;
|
||||||
height: 30px;
|
height: 25px;
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@include flex-center;
|
@include flex-center;
|
||||||
|
background-color: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kebab-options {
|
.kebab-options {
|
||||||
|
@ -576,6 +582,12 @@
|
||||||
|
|
||||||
box-shadow: var(--box-shadow-medium);
|
box-shadow: var(--box-shadow-medium);
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 25px !important;
|
||||||
|
height: 25px !important;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
@ -607,18 +619,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dublicate {
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.distance-line {
|
.distance-line {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border-style: dashed;
|
border-style: dashed;
|
||||||
border-color: var(--accent-color); /* Green color for visibility */
|
border-color: var(--accent-color);
|
||||||
|
/* Green color for visibility */
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
pointer-events: none; /* Ensure lins don't interfere with dragging */
|
pointer-events: none;
|
||||||
|
/* Ensure lins don't interfere with dragging */
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,51 +644,112 @@
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
transform: translate(-50%, -50%); /* Center the label */
|
transform: translate(-50%, -50%);
|
||||||
|
/* Center the label */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Specific styles for each type of line */
|
/* Specific styles for each type of line */
|
||||||
|
|
||||||
/* Top distance line */
|
/* Top distance line */
|
||||||
.distance-line.top {
|
.distance-line.top {
|
||||||
border-bottom: none; /* Remove bottom border for a single line */
|
border-bottom: none;
|
||||||
width: 2px; /* Thin vertical line */
|
/* Remove bottom border for a single line */
|
||||||
|
width: 2px;
|
||||||
|
/* Thin vertical line */
|
||||||
}
|
}
|
||||||
|
|
||||||
.distance-line.top .distance-label {
|
.distance-line.top .distance-label {
|
||||||
top: -10px; /* Position label above the line */
|
top: -10px;
|
||||||
left: 50%; /* Center horizontally */
|
/* Position label above the line */
|
||||||
|
left: 50%;
|
||||||
|
/* Center horizontally */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bottom distance line */
|
/* Bottom distance line */
|
||||||
.distance-line.bottom {
|
.distance-line.bottom {
|
||||||
border-top: none; /* Remove top border for a single line */
|
border-top: none;
|
||||||
width: 2px; /* Thin vertical line */
|
/* Remove top border for a single line */
|
||||||
|
width: 2px;
|
||||||
|
/* Thin vertical line */
|
||||||
}
|
}
|
||||||
|
|
||||||
.distance-line.bottom .distance-label {
|
.distance-line.bottom .distance-label {
|
||||||
bottom: -10px; /* Position label below the line */
|
bottom: -10px;
|
||||||
left: 50%; /* Center horizontally */
|
/* Position label below the line */
|
||||||
|
left: 50%;
|
||||||
|
/* Center horizontally */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Left distance line */
|
/* Left distance line */
|
||||||
.distance-line.left {
|
.distance-line.left {
|
||||||
border-right: none; /* Remove right border for a single line */
|
border-right: none;
|
||||||
height: 2px; /* Thin horizontal line */
|
/* Remove right border for a single line */
|
||||||
|
height: 2px;
|
||||||
|
/* Thin horizontal line */
|
||||||
}
|
}
|
||||||
|
|
||||||
.distance-line.left .distance-label {
|
.distance-line.left .distance-label {
|
||||||
left: -10px; /* Position label to the left of the line */
|
left: -10px;
|
||||||
top: 50%; /* Center vertically */
|
/* Position label to the left of the line */
|
||||||
|
top: 50%;
|
||||||
|
/* Center vertically */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Right distance line */
|
/* Right distance line */
|
||||||
.distance-line.right {
|
.distance-line.right {
|
||||||
border-left: none; /* Remove left border for a single line */
|
border-left: none;
|
||||||
height: 2px; /* Thin horizontal line */
|
/* Remove left border for a single line */
|
||||||
|
height: 2px;
|
||||||
|
/* Thin horizontal line */
|
||||||
}
|
}
|
||||||
|
|
||||||
.distance-line.right .distance-label {
|
.distance-line.right .distance-label {
|
||||||
right: -10px; /* Position label to the right of the line */
|
right: -10px;
|
||||||
top: 50%; /* Center vertically */
|
/* Position label to the right of the line */
|
||||||
|
top: 50%;
|
||||||
|
/* Center vertically */
|
||||||
|
}
|
||||||
|
|
||||||
|
.activeChart {
|
||||||
|
outline: 1px solid var(--accent-color);
|
||||||
|
z-index: 2 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.editWidgetOptions-wrapper {
|
||||||
|
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editWidgetOptions {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background-color: var(--background-color);
|
||||||
|
z-index: 3;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.option {
|
||||||
|
padding: 8px 10px;
|
||||||
|
color: var(--text-color);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--highlight-accent-color);
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
color: #f65648;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #ffe3e0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -59,39 +59,39 @@ export type ThreeDimension = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GridConfig = {
|
export type GridConfig = {
|
||||||
size: number;
|
size: number;
|
||||||
divisions: number;
|
divisions: number;
|
||||||
primaryColor: string;
|
primaryColor: string;
|
||||||
secondaryColor: string;
|
secondaryColor: string;
|
||||||
position2D: [x: number, y: number, z: number];
|
position2D: [x: number, y: number, z: number];
|
||||||
position3D: [x: number, y: number, z: number];
|
position3D: [x: number, y: number, z: number];
|
||||||
}
|
};
|
||||||
|
|
||||||
export type PlaneConfig = {
|
export type PlaneConfig = {
|
||||||
position2D: [x: number, y: number, z: number];
|
position2D: [x: number, y: number, z: number];
|
||||||
position3D: [x: number, y: number, z: number];
|
position3D: [x: number, y: number, z: number];
|
||||||
rotation: number;
|
rotation: number;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
color: string;
|
color: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ShadowConfig = {
|
export type ShadowConfig = {
|
||||||
shadowOffset: number,
|
shadowOffset: number;
|
||||||
shadowmapSizewidth: number,
|
shadowmapSizewidth: number;
|
||||||
shadowmapSizeheight: number,
|
shadowmapSizeheight: number;
|
||||||
shadowcamerafar: number,
|
shadowcamerafar: number;
|
||||||
shadowcameranear: number,
|
shadowcameranear: number;
|
||||||
shadowcameratop: number,
|
shadowcameratop: number;
|
||||||
shadowcamerabottom: number,
|
shadowcamerabottom: number;
|
||||||
shadowcameraleft: number,
|
shadowcameraleft: number;
|
||||||
shadowcameraright: number,
|
shadowcameraright: number;
|
||||||
shadowbias: number,
|
shadowbias: number;
|
||||||
shadownormalBias: number,
|
shadownormalBias: number;
|
||||||
shadowMaterialPosition: [x: number, y: number, z: number],
|
shadowMaterialPosition: [x: number, y: number, z: number];
|
||||||
shadowMaterialRotation: [x: number, y: number, z: number],
|
shadowMaterialRotation: [x: number, y: number, z: number];
|
||||||
shadowMaterialOpacity: number,
|
shadowMaterialOpacity: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type SkyConfig = {
|
export type SkyConfig = {
|
||||||
defaultTurbidity: number;
|
defaultTurbidity: number;
|
||||||
|
@ -109,34 +109,34 @@ export type AssetConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PointConfig = {
|
export type PointConfig = {
|
||||||
defaultInnerColor: string;
|
defaultInnerColor: string;
|
||||||
defaultOuterColor: string;
|
defaultOuterColor: string;
|
||||||
deleteColor: string;
|
deleteColor: string;
|
||||||
boxScale: [number, number, number];
|
boxScale: [number, number, number];
|
||||||
wallOuterColor: string;
|
wallOuterColor: string;
|
||||||
floorOuterColor: string;
|
floorOuterColor: string;
|
||||||
aisleOuterColor: string;
|
aisleOuterColor: string;
|
||||||
zoneOuterColor: string;
|
zoneOuterColor: string;
|
||||||
snappingThreshold: number;
|
snappingThreshold: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type LineConfig = {
|
export type LineConfig = {
|
||||||
tubularSegments: number;
|
tubularSegments: number;
|
||||||
radius: number;
|
radius: number;
|
||||||
radialSegments: number;
|
radialSegments: number;
|
||||||
wallName: string;
|
wallName: string;
|
||||||
floorName: string;
|
floorName: string;
|
||||||
aisleName: string;
|
aisleName: string;
|
||||||
zoneName: string;
|
zoneName: string;
|
||||||
referenceName: string;
|
referenceName: string;
|
||||||
lineIntersectionPoints: number;
|
lineIntersectionPoints: number;
|
||||||
defaultColor: string;
|
defaultColor: string;
|
||||||
wallColor: string;
|
wallColor: string;
|
||||||
floorColor: string;
|
floorColor: string;
|
||||||
aisleColor: string;
|
aisleColor: string;
|
||||||
zoneColor: string;
|
zoneColor: string;
|
||||||
helperColor: string;
|
helperColor: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type WallConfig = {
|
export type WallConfig = {
|
||||||
defaultColor: string;
|
defaultColor: string;
|
||||||
|
@ -145,10 +145,10 @@ export type WallConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FloorConfig = {
|
export type FloorConfig = {
|
||||||
defaultColor: string;
|
defaultColor: string;
|
||||||
height: number;
|
height: number;
|
||||||
textureScale: number;
|
textureScale: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type RoofConfig = {
|
export type RoofConfig = {
|
||||||
defaultColor: string;
|
defaultColor: string;
|
||||||
|
@ -156,16 +156,16 @@ export type RoofConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AisleConfig = {
|
export type AisleConfig = {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
defaultColor: number;
|
defaultColor: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ZoneConfig = {
|
export type ZoneConfig = {
|
||||||
defaultColor: string;
|
defaultColor: string;
|
||||||
height: number;
|
height: number;
|
||||||
color: string;
|
color: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ColumnConfig = {
|
export type ColumnConfig = {
|
||||||
defaultColor: string;
|
defaultColor: string;
|
||||||
|
@ -242,24 +242,24 @@ export const threeDimension: ThreeDimension = {
|
||||||
export const camPositionUpdateInterval: number = 200; // Interval for updating the camera position
|
export const camPositionUpdateInterval: number = 200; // Interval for updating the camera position
|
||||||
|
|
||||||
export const gridConfig: GridConfig = {
|
export const gridConfig: GridConfig = {
|
||||||
size: 300, // Size of the grid
|
size: 300, // Size of the grid
|
||||||
divisions: 75, // Number of divisions in the grid
|
divisions: 75, // Number of divisions in the grid
|
||||||
primaryColor: savedTheme === "dark" ? "#131313" : "#d5d5d5", // Primary color of the grid
|
primaryColor: savedTheme === "dark" ? "#131313" : "#d5d5d5", // Primary color of the grid
|
||||||
secondaryColor: savedTheme === "dark" ? "#434343" : "#e3e3e3", // Secondary color of the grid
|
secondaryColor: savedTheme === "dark" ? "#434343" : "#e3e3e3", // Secondary color of the grid
|
||||||
|
|
||||||
position2D: [0, 0.1, 0], // Position of the grid in 2D view
|
position2D: [0, 0.1, 0], // Position of the grid in 2D view
|
||||||
position3D: [0, -0.5, 0], // Position of the grid in 3D view
|
position3D: [0, -0.5, 0], // Position of the grid in 3D view
|
||||||
}
|
};
|
||||||
|
|
||||||
export const planeConfig: PlaneConfig = {
|
export const planeConfig: PlaneConfig = {
|
||||||
position2D: [0, -0.5, 0], // Position of the plane
|
position2D: [0, -0.5, 0], // Position of the plane
|
||||||
position3D: [0, -0.65, 0], // Position of the plane
|
position3D: [0, -0.65, 0], // Position of the plane
|
||||||
rotation: -Math.PI / 2, // Rotation of the plane
|
rotation: -Math.PI / 2, // Rotation of the plane
|
||||||
|
|
||||||
width: 300, // Width of the plane
|
width: 300, // Width of the plane
|
||||||
height: 300, // Height of the plane
|
height: 300, // Height of the plane
|
||||||
color: savedTheme === "dark" ? "#323232" : "#f3f3f3" // Color of the plane
|
color: savedTheme === "dark" ? "#323232" : "#f3f3f3", // Color of the plane
|
||||||
}
|
};
|
||||||
|
|
||||||
export const shadowConfig: ShadowConfig = {
|
export const shadowConfig: ShadowConfig = {
|
||||||
shadowOffset: 50, // Offset of the shadow
|
shadowOffset: 50, // Offset of the shadow
|
||||||
|
@ -349,10 +349,10 @@ export const aisleConfig: AisleConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const zoneConfig: ZoneConfig = {
|
export const zoneConfig: ZoneConfig = {
|
||||||
defaultColor: "black", // Default color of the zones
|
defaultColor: "black", // Default color of the zones
|
||||||
height: 3,
|
height: 3,
|
||||||
color: "#8656DF" // Color of the zones
|
color: "#8656DF", // Color of the zones
|
||||||
}
|
};
|
||||||
|
|
||||||
export const columnConfig: ColumnConfig = {
|
export const columnConfig: ColumnConfig = {
|
||||||
defaultColor: "White", // Default color of the columns
|
defaultColor: "White", // Default color of the columns
|
||||||
|
|
|
@ -18,4 +18,4 @@ export function toggleTheme() {
|
||||||
localStorage.setItem('theme', newTheme);
|
localStorage.setItem('theme', newTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTheme();
|
setTheme();
|
||||||
|
|
Loading…
Reference in New Issue