merge conflicts resolved

This commit is contained in:
2025-03-27 15:48:11 +05:30
39 changed files with 1957 additions and 827 deletions

20
app/package-lock.json generated
View File

@@ -47,6 +47,7 @@
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.1", "@types/node": "^22.9.1",
"@types/three": "^0.169.0", "@types/three": "^0.169.0",
"axios": "^1.8.4",
"cypress": "^13.14.2", "cypress": "^13.14.2",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"husky": "^9.1.6", "husky": "^9.1.6",
@@ -7672,6 +7673,25 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/axios": {
"version": "1.8.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
"dev": true,
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/axios/node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"dev": true,
"license": "MIT"
},
"node_modules/axobject-query": { "node_modules/axobject-query": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",

View File

@@ -69,6 +69,7 @@
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.1", "@types/node": "^22.9.1",
"@types/three": "^0.169.0", "@types/three": "^0.169.0",
"axios": "^1.8.4",
"cypress": "^13.14.2", "cypress": "^13.14.2",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"husky": "^9.1.6", "husky": "^9.1.6",

View File

@@ -130,3 +130,24 @@ export function StarsIconSmall() {
</svg> </svg>
); );
} }
export function FiileedStarsIconSmall() {
return (
<svg
width="11"
height="12"
viewBox="0 0 11 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5.07372 1.61354C5.20877 1.31056 5.27632 1.15908 5.37035 1.11243C5.45202 1.0719 5.54791 1.0719 5.62958 1.11243C5.72362 1.15908 5.79117 1.31056 5.92621 1.61354L7.00187 4.02675C7.04183 4.11631 7.06178 4.16109 7.0927 4.19539C7.12 4.22573 7.15342 4.25 7.1907 4.26662C7.23287 4.2854 7.28164 4.29055 7.37917 4.30084L10.0067 4.57816C10.3366 4.61297 10.5015 4.63038 10.5749 4.70539C10.6387 4.77054 10.6683 4.86177 10.655 4.95198C10.6397 5.05581 10.5165 5.16682 10.2701 5.3889L8.30737 7.15768C8.23457 7.22331 8.19811 7.25615 8.17507 7.29611C8.15466 7.33152 8.14188 7.37077 8.13762 7.41137C8.13278 7.45728 8.14293 7.50523 8.16329 7.60119L8.71151 10.1858C8.78034 10.5103 8.81476 10.6725 8.76611 10.7655C8.72381 10.8463 8.64623 10.9027 8.55634 10.9179C8.45286 10.9354 8.30918 10.8526 8.02183 10.6868L5.73312 9.36677C5.64819 9.31777 5.60572 9.29332 5.56057 9.2837C5.52062 9.27524 5.47931 9.27524 5.43936 9.2837C5.39421 9.29332 5.35174 9.31777 5.26681 9.36677L2.97811 10.6868C2.69077 10.8526 2.5471 10.9354 2.44361 10.9179C2.35372 10.9027 2.27611 10.8463 2.23385 10.7655C2.18521 10.6725 2.21962 10.5103 2.28845 10.1858L2.83664 7.60119C2.85699 7.50523 2.86716 7.45728 2.86233 7.41137C2.85805 7.37077 2.8453 7.33152 2.82488 7.29611C2.80181 7.25615 2.76539 7.22331 2.69254 7.15768L0.72985 5.3889C0.483444 5.16682 0.360238 5.05581 0.34492 4.95198C0.33162 4.86177 0.361259 4.77054 0.425041 4.70539C0.498471 4.63038 0.663408 4.61297 0.993283 4.57816L3.62079 4.30084C3.71831 4.29055 3.76706 4.2854 3.80923 4.26662C3.84653 4.25 3.87993 4.22573 3.90727 4.19539C3.93815 4.16109 3.95812 4.11631 3.99804 4.02675L5.07372 1.61354Z"
fill="#F3A50C"
stroke="#F3A50C"
stroke-width="0.7"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);
}

View File

@@ -30,6 +30,7 @@ const Outline: React.FC = () => {
defaultOpen={true} defaultOpen={true}
showKebabMenu={false} showKebabMenu={false}
showFocusIcon={true} showFocusIcon={true}
remove
/> />
<DropDownList <DropDownList
value="Scene" value="Scene"

View File

@@ -12,16 +12,15 @@ import {
import useToggleStore from "../../../store/useUIToggleStore"; import useToggleStore from "../../../store/useUIToggleStore";
import MachineMechanics from "./mechanics/MachineMechanics"; import MachineMechanics from "./mechanics/MachineMechanics";
import Visualization from "./visualization/Visualization"; import Visualization from "./visualization/Visualization";
import GlobalProperties from "./properties/GlobalProperties";
import AsstePropertiies from "./properties/AssetProperties";
import Analysis from "./analysis/Analysis"; import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations"; import Simulations from "./simulation/Simulations";
import { useSelectedActionSphere } from "../../../store/store"; import { useSelectedActionSphere } from "../../../store/store";
import GlobalProperties from "./properties/GlobalProperties";
import AsstePropertiies from "./properties/AssetProperties";
import ZoneProperties from "./properties/ZoneProperties"; import ZoneProperties from "./properties/ZoneProperties";
const SideBarRight: React.FC = () => { const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const [activeList] = useState("properties");
const { toggleUI } = useToggleStore(); const { toggleUI } = useToggleStore();
const { selectedActionSphere } = useSelectedActionSphere(); const { selectedActionSphere } = useSelectedActionSphere();
const { subModule, setSubModule } = useSubModuleStore(); const { subModule, setSubModule } = useSubModuleStore();
@@ -38,8 +37,7 @@ const SideBarRight: React.FC = () => {
<div className="sidebar-actions-container"> <div className="sidebar-actions-container">
{/* {activeModule === "builder" && ( */} {/* {activeModule === "builder" && ( */}
<div <div
className={`sidebar-action-list ${ className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
subModule === "properties" ? "active" : ""
}`} }`}
onClick={() => setSubModule("properties")} onClick={() => setSubModule("properties")}
> >
@@ -49,28 +47,25 @@ const SideBarRight: React.FC = () => {
{activeModule === "simulation" && ( {activeModule === "simulation" && (
<> <>
<div <div
className={`sidebar-action-list ${ className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
subModule === "mechanics" ? "active" : ""
}`} }`}
onClick={() => setSubModule("mechanics")} onClick={() => setSubModule("mechanics")}
> >
<MechanicsIcon isActive={activeList === "mechanics"} /> <MechanicsIcon isActive={subModule === "mechanics"} />
</div> </div>
<div <div
className={`sidebar-action-list ${ className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
subModule === "simulations" ? "active" : ""
}`} }`}
onClick={() => setSubModule("simulations")} onClick={() => setSubModule("simulations")}
> >
<SimulationIcon isActive={activeList === "simulations"} /> <SimulationIcon isActive={subModule === "simulations"} />
</div> </div>
<div <div
className={`sidebar-action-list ${ className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
subModule === "analysis" ? "active" : ""
}`} }`}
onClick={() => setSubModule("analysis")} onClick={() => setSubModule("analysis")}
> >
<AnalysisIcon isActive={activeList === "analysis"} /> <AnalysisIcon isActive={subModule === "analysis"} />
</div> </div>
</> </>
)} )}
@@ -78,7 +73,7 @@ const SideBarRight: React.FC = () => {
)} )}
{/* process builder */} {/* process builder */}
{toggleUI && {toggleUI &&
activeList === "properties" && subModule === "properties" &&
activeModule !== "visualization" && ( activeModule !== "visualization" && (
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
@@ -88,7 +83,17 @@ const SideBarRight: React.FC = () => {
</div> </div>
</div> </div>
)} )}
{toggleUI &&
subModule === "zoneProperties" &&
activeModule === "builder" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
{/* <GlobalProperties /> */}
<ZoneProperties />
{/* <AsstePropertiies /> */}
</div>
</div>
)}
{/* simulation */} {/* simulation */}
{toggleUI && activeModule === "simulation" && ( {toggleUI && activeModule === "simulation" && (
@@ -114,7 +119,7 @@ const SideBarRight: React.FC = () => {
</div> </div>
</div> </div>
)} )}
{activeList === "simulations" && ( {subModule === "simulations" && (
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
<Simulations /> <Simulations />

View File

@@ -1,59 +1,54 @@
import React from "react"; import React from "react";
import { EyeDroperIcon } from "../../../icons/ExportCommonIcons"; import { EyeDroperIcon } from "../../../icons/ExportCommonIcons";
// import { useThree } from "@react-three/fiber";
interface PositionInputProps { interface PositionInputProps {
onChange: (value: string) => void; // Callback for value change onChange: (value: [number, number, number]) => void; // Callback for value change
header: string; header: string;
placeholder?: string; // Optional placeholder placeholder?: string; // Optional placeholder
type?: string; // Input type (e.g., text, number, email) type?: string; // Input type (e.g., text, number, email)
value: [number, number, number] | null;
disabled?: boolean; // To enable/disable editing
} }
const Vector3Input: React.FC<PositionInputProps> = ({ const Vector3Input: React.FC<PositionInputProps> = ({
onChange, onChange,
header, header,
placeholder = "Enter value", // Default placeholder placeholder = "Enter value", // Default placeholder
type = "number", // Default type type = "string", // Default type
value,
disabled = false, // Default to disabled
}) => { }) => {
const handleChange = (index: number, newValue: string) => {
if (!value) return;
const updatedValue = [...value] as [number, number, number];
updatedValue[index] = parseFloat(newValue) || 0;
console.log('updatedValue: ', updatedValue);
onChange(updatedValue);
};
return ( return (
<div className="custom-input-container"> <div className="custom-input-container">
<div className="header"> <div className="header">
{header}{" "} {header}
<div className="eyedrop-button">
<EyeDroperIcon isActive={false} />
</div>
</div> </div>
<div className="inputs-container"> <div className="inputs-container">
<div className="input-container"> {["X", "Y", "Z"].map((axis, i) => (
<div className="custom-input-label">X : </div> <div className="input-container" key={axis}>
<div className="custom-input-label">{axis}:</div>
<input <input
className="custom-input-field" className="custom-input-field"
type={type} type={type}
onChange={(e) => onChange(e.target.value)} value={value?.[i] !== undefined ? value[i].toFixed(2) : ""}
// onChange={(e) => handleChange(i, e.target.value)}
placeholder={placeholder} placeholder={placeholder}
disabled disabled={disabled}
/>
</div>
<div className="input-container">
<div className="custom-input-label">Y : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
disabled
min={0}
/>
</div>
<div className="input-container">
<div className="custom-input-label">Z : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
disabled
/> />
</div> </div>
))}
</div> </div>
</div> </div>
); );

View File

@@ -1,32 +1,65 @@
import React, { useState } from "react"; import React, { useEffect, useState } from "react";
import RenameInput from "../../../ui/inputs/RenameInput"; import RenameInput from "../../../ui/inputs/RenameInput";
import Vector3Input from "../customInput/Vector3Input"; import Vector3Input from "../customInput/Vector3Input";
import { useSelectedZoneStore } from "../../../../store/useZoneStore";
import { useEditPosition, usezonePosition, usezoneTarget } from "../../../../store/store";
const ZoneProperties: React.FC = () => { const ZoneProperties: React.FC = () => {
const [Edit, setEdit] = useState(false); const { Edit, setEdit } = useEditPosition();
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const { zonePosition, setZonePosition } = usezonePosition();
const { zoneTarget, setZoneTarget } = usezoneTarget();
useEffect(() => {
setZonePosition(selectedZone.zoneViewPortPosition)
setZoneTarget(selectedZone.zoneViewPortTarget)
}, [selectedZone?.zoneViewPortPosition, selectedZone?.zoneViewPortTarget])
function handleSetView() { function handleSetView() {
console.log("setApi");
console.log('zoneTarget: ', zoneTarget);
console.log('zonePosition: ', zonePosition);
setEdit(false); setEdit(false);
} }
function handleEditView() { function handleEditView() {
if (Edit) { setEdit(!Edit); // This will toggle the `Edit` state correctly
setEdit(false);
} else {
setEdit(true);
} }
function handleZoneNameChange(newName: string) {
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
} }
function handleVectorChange(key: "zoneViewPortTarget" | "zoneViewPortPosition", newValue: [number, number, number]) {
setSelectedZone((prev) => ({ ...prev, [key]: newValue }));
}
useEffect(() => {
console.log("Updated selectedZone: ", selectedZone);
}, [selectedZone]);
return ( return (
<div className="zone-properties-container"> <div className="zone-properties-container">
<div className="header"> <div className="header">
<RenameInput value="Selected Zone Name" /> <RenameInput value={selectedZone.zoneName} onRename={handleZoneNameChange} />
<div className="button" onClick={handleEditView}> <div className="button" onClick={handleEditView}>
{Edit ? "Cancel" : "Edit"} {Edit ? "Cancel" : "Edit"}
</div> </div>
</div> </div>
<Vector3Input onChange={() => {}} header="Viewport Target" /> <Vector3Input
<Vector3Input onChange={() => {}} header="Viewport Position" /> onChange={(value) => handleVectorChange("zoneViewPortTarget", value)}
header="Viewport Target"
value={zoneTarget as [number, number, number]}
disabled={!Edit}
/>
<Vector3Input
onChange={(value) => handleVectorChange("zoneViewPortPosition", value)}
header="Viewport Position"
value={zonePosition as [number, number, number]}
disabled={!Edit}
/>
{Edit && ( {Edit && (
<div className="button-save" onClick={handleSetView}> <div className="button-save" onClick={handleSetView}>
Set View Set View
@@ -37,3 +70,4 @@ const ZoneProperties: React.FC = () => {
}; };
export default ZoneProperties; export default ZoneProperties;

View File

@@ -0,0 +1,115 @@
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 axios from 'axios'
type Props = {}
const LineGrapInput = (props: Props) => {
const [dropDowndata, setDropDownData] = useState({})
const [selections, setSelections] = useState<Record<string, { name: string, fields: string }>>({})
const [selectedOption, setSelectedOption] = useState('1h')
const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
const handleSelectDuration = (option: string) => {
updateDuration(option); // Normalize for key matching
};
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get('http://192.168.0.192:5010/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(() => {
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
};
}
});
};
interface Measurement {
name: string;
fields: string;
}
interface InputData {
[key: string]: Measurement;
}
const extractMeasurements = (input: InputData): Measurement[] => {
return Object.values(input);
};
useEffect(() => {
const measurementsData = extractMeasurements(selections);
setMeasurements(measurementsData);
}, [selections]);
return (
<>
<div className="inputs-wrapper">
{[...Array(6)].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]}
/>
<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 LineGrapInput

View File

@@ -0,0 +1,77 @@
import React, { useEffect, useState } from 'react'
import MultiLevelDropdown from '../../../../ui/inputs/MultiLevelDropDown'
import { AddIcon } from '../../../../icons/ExportCommonIcons'
import axios from 'axios'
type Props = {}
const PieChartInput = (props: Props) => {
const [dropDowndata, setDropDownData] = useState({})
const [selections, setSelections] = useState<Record<string, {name: string, fields: string}>>({})
useEffect(() => {
const fetchZoneData = async () => {
try {
const response = await axios.get('http://192.168.0.192:5010/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(() => {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
};
}
});
};
return (
<>
<div className="inputs-wrapper">
{[...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]}
/>
<div className="icon">
<AddIcon />
</div>
</div>
</div>
);
})}
</div>
<div>
</div>
</>
)
}
export default PieChartInput

View File

@@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
import { useWidgetStore } from "../../../../../store/useWidgetStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore";
import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons"; import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons";
import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown"; import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown";
import LineGrapInput from "../IotInputCards/LineGrapInput";
// Define the data structure for demonstration purposes // Define the data structure for demonstration purposes
const DATA_STRUCTURE = { const DATA_STRUCTURE = {
@@ -123,40 +124,9 @@ const Data = () => {
<div className="sideBarHeader">{selectedChartId?.title}</div> <div className="sideBarHeader">{selectedChartId?.title}</div>
)} )}
{/* Render groups dynamically */} {/* Render groups dynamically */}
{chartDataGroups[selectedChartId?.id]?.map((group) => ( {
<div key={group.id} className="inputs-wrapper"> chartDataGroups[selectedChartId?.id] && <LineGrapInput />
{group.children.map((child, index) => ( }
<div key={child.id} className="datas">
<div className="datas__label">Input {index + 1}</div>
<div className="datas__class">
<MultiLevelDropDown data={DATA_STRUCTURE} />
{/* Add Icon */}
{group.children.length < 7 && (
<div
className="icon"
onClick={() => handleAddClick(group.id)} // Pass groupId to handleAddClick
>
<AddIcon />
</div>
)}
{/* Remove Icon */}
<span
className={`datas__separator ${
group.children.length > 1 ? "" : "disable"
}`}
onClick={(e) => {
e.stopPropagation(); // Prevent event bubbling
removeChild(group.id, child.id); // Pass groupId and childId to removeChild
}}
>
<RemoveIcon />
</span>
</div>
</div>
))}
</div>
))}
{/* Info Box */} {/* Info Box */}
<div className="infoBox"> <div className="infoBox">
@@ -173,3 +143,40 @@ const Data = () => {
}; };
export default Data; export default Data;
// {chartDataGroups[selectedChartId?.id]?.map((group) => (
// <div key={group.id} className="inputs-wrapper">
// {group.children.map((child, index) => (
// <div key={child.id} className="datas">
// <div className="datas__label">Input {index + 1}</div>
// <div className="datas__class">
// <MultiLevelDropDown data={DATA_STRUCTURE} />
// {/* Add Icon */}
// {group.children.length < 7 && (
// <div
// className="icon"
// onClick={() => handleAddClick(group.id)} // Pass groupId to handleAddClick
// >
// <AddIcon />
// </div>
// )}
// {/* Remove Icon */}
// <span
// className={`datas__separator ${
// group.children.length > 1 ? "" : "disable"
// }`}
// onClick={(e) => {
// e.stopPropagation(); // Prevent event bubbling
// removeChild(group.id, child.id); // Pass groupId and childId to removeChild
// }}
// >
// <RemoveIcon />
// </span>
// </div>
// </div>
// ))}
// </div>
// ))}

View File

@@ -4,6 +4,7 @@ import {
EyeIcon, EyeIcon,
LockIcon, LockIcon,
} from "../../icons/RealTimeVisulationIcons"; } from "../../icons/RealTimeVisulationIcons";
import { panelData } from "../../../services/realTimeVisulization/zoneData/panel";
// Define the type for `Side` // Define the type for `Side`
type Side = "top" | "bottom" | "left" | "right"; type Side = "top" | "bottom" | "left" | "right";
@@ -15,6 +16,9 @@ interface ButtonsProps {
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[]
widgets: { widgets: {
id: string; id: string;
type: string; type: string;
@@ -29,6 +33,9 @@ interface ButtonsProps {
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[]
widgets: { widgets: {
id: string; id: string;
type: string; type: string;
@@ -108,7 +115,7 @@ const AddButtons: React.FC<ButtonsProps> = ({
panelOrder: newActiveSides, panelOrder: newActiveSides,
}; };
// Update the selectedZone state // Delete the selectedZone state
console.log('updatedZone: ', updatedZone); console.log('updatedZone: ', updatedZone);
setSelectedZone(updatedZone); setSelectedZone(updatedZone);
} else { } else {
@@ -120,17 +127,23 @@ const AddButtons: React.FC<ButtonsProps> = ({
activeSides: newActiveSides, activeSides: newActiveSides,
panelOrder: newActiveSides, panelOrder: newActiveSides,
}; };
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
// let response = panelData(organization, selectedZone.zoneId, newActiveSides)
// console.log('response: ', response);
// Update the selectedZone state // Update the selectedZone state
console.log('updatedZone: ', updatedZone); console.log("updatedZone: ", updatedZone);
setSelectedZone(updatedZone); setSelectedZone(updatedZone);
} }
}; };
return ( return (
<>
<div> <div>
{(["top", "right", "bottom", "left"] as Side[]).map((side) => ( {(["top", "right", "bottom", "left"] as Side[]).map((side) => (
<div key={side} className={`side-button-container ${side}`}> <div key={side} className={`side-button-container ${side}`}>
{/* "+" Button */}
<button <button
className={`side-button ${side}`} className={`side-button ${side}`}
onClick={() => handlePlusButtonClick(side)} onClick={() => handlePlusButtonClick(side)}
@@ -156,7 +169,11 @@ const AddButtons: React.FC<ButtonsProps> = ({
onClick={() => toggleVisibility(side)} onClick={() => toggleVisibility(side)}
> >
<EyeIcon <EyeIcon
fill={hiddenPanels.includes(side) ? "white" : "#1D1E21"} fill={
hiddenPanels.includes(side)
? "white"
: "#1D1E21"
}
/> />
</div> </div>
@@ -187,6 +204,7 @@ const AddButtons: React.FC<ButtonsProps> = ({
</div> </div>
))} ))}
</div> </div>
</>
); );
}; };

View File

@@ -11,6 +11,9 @@ interface DisplayZoneProps {
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
widgets: Widget[]; widgets: Widget[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[];
}; };
}; };
selectedZone: { selectedZone: {
@@ -18,6 +21,9 @@ interface DisplayZoneProps {
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[];
widgets: { widgets: {
id: string; id: string;
type: string; type: string;
@@ -32,6 +38,9 @@ interface DisplayZoneProps {
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[];
widgets: { widgets: {
id: string; id: string;
type: string; type: string;
@@ -152,7 +161,7 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
return ( return (
<div <div
ref={containerRef} ref={containerRef}
className={`zoon-wrapper ${selectedZone.activeSides.includes("bottom") && "bottom" className={`zoon-wrapper ${selectedZone?.activeSides?.includes("bottom") && "bottom"
}`} }`}
> >
{Object.keys(zonesData).map((zoneName, index) => ( {Object.keys(zonesData).map((zoneName, index) => (
@@ -161,7 +170,7 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
className={`zone ${selectedZone.zoneName === zoneName ? "active" : "" className={`zone ${selectedZone.zoneName === zoneName ? "active" : ""
}`} }`}
onClick={() => { onClick={() => {
console.log('zoneName: ', zoneName);
setSelectedZone({ setSelectedZone({
zoneName, zoneName,
@@ -169,12 +178,15 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
panelOrder: zonesData[zoneName].panelOrder || [], panelOrder: zonesData[zoneName].panelOrder || [],
lockedPanels: zonesData[zoneName].lockedPanels || [], lockedPanels: zonesData[zoneName].lockedPanels || [],
widgets: zonesData[zoneName].widgets || [], widgets: zonesData[zoneName].widgets || [],
}) zoneId: zonesData[zoneName]?.zoneId || "",
zoneViewPortTarget: zonesData[zoneName].zoneViewPortTarget || [],
zoneViewPortPosition:
zonesData[zoneName].zoneViewPortPosition || [],
});
// setSelectedZone({ // setSelectedZone({
// zoneName, // zoneName,
// ...zonesData[zoneName], // ...zonesData[zoneName],
// }); // });
console.log(selectedZone);
}} }}
> >
{zoneName} {zoneName}

View File

@@ -16,7 +16,6 @@ export const DraggableWidget = ({
hiddenPanels: string[]; // Array of hidden panel names hiddenPanels: string[]; // Array of hidden panel names
index: number; onReorder: (fromIndex: number, toIndex: number) => void index: number; onReorder: (fromIndex: number, toIndex: number) => void
}) => { }) => {
const { selectedChartId, setSelectedChartId } = useWidgetStore(); const { selectedChartId, setSelectedChartId } = useWidgetStore();
const handlePointerDown = () => { const handlePointerDown = () => {

View File

@@ -0,0 +1,89 @@
// import { useState } from "react";
// import { useThree } from "@react-three/fiber";
// import * as THREE from "three";
// const DroppedObjects = () => {
// const { camera } = useThree(); // Now inside Canvas ✅
// const [objects, setObjects] = useState<{ id: number; position: [number, number, number] }[]>([]);
// // Function to convert drop event into 3D position
// const handleDrop = (event: DragEvent) => {
// event.preventDefault();
// const data = event.dataTransfer?.getData("text/plain");
// if (!data) return;
// try {
// const cardData = JSON.parse(data);
// if (!cardData.className.includes("floating total-card")) {
// console.log("Drop rejected: Incorrect element.");
// return;
// }
// // Convert 2D drop position to 3D world coordinates
// const x = (event.clientX / window.innerWidth) * 2 - 1;
// const y = -(event.clientY / window.innerHeight) * 2 + 1;
// // Raycasting to determine the drop position in 3D
// const raycaster = new THREE.Raycaster();
// const mouseVector = new THREE.Vector2(x, y);
// raycaster.setFromCamera(mouseVector, camera);
// // Intersect with a ground plane (assume y = 0)
// const groundPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
// const intersection = new THREE.Vector3();
// raycaster.ray.intersectPlane(groundPlane, intersection);
// console.log("Spawn Object at:", intersection);
// // Add the dropped object to the scene state
// setObjects((prev) => [...prev, { id: Date.now(), position: [intersection.x, intersection.y, intersection.z] }]);
// } catch (error) {
// console.error("Invalid data:", error);
// }
// };
// return (
// <group>
// {/* Render dropped objects as green boxes */}
// {objects.map((obj) => (
// <mesh key={obj.id} position={obj.position}>
// <boxGeometry args={[1, 1, 1]} />
// <meshStandardMaterial color="green" />
// </mesh>
// ))}
// </group>
// );
// };
import { Html } from "@react-three/drei";
import { useDroppedObjectsStore } from "../../../store/store";
const DroppedObjects: React.FC = () => {
const objects = useDroppedObjectsStore((state) => state.objects); // Get objects from Zustand store
console.log('objects: ', objects);
return (
<>
{objects.map((obj, index) => (
<group key={index} position={[Math.random() * 5, Math.random() * 5, 0]}>
<Html wrapperClass={obj.className}>
<div style={{ padding: "10px", background: "#fff", borderRadius: "6px" }}>
<div className="header">{obj.header}</div>
<div className="data-values">
<div className="value">{obj.value}</div>
<div className="per">{obj.per}</div>
</div>
</div>
</Html>
</group>
))}
</>
);
};
export default DroppedObjects;

View File

@@ -20,6 +20,9 @@ interface PanelProps {
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[]
widgets: Widget[]; widgets: Widget[];
}; };
setSelectedZone: React.Dispatch< setSelectedZone: React.Dispatch<
@@ -28,6 +31,9 @@ interface PanelProps {
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[]
widgets: Widget[]; widgets: Widget[];
}> }>
>; >;
@@ -65,7 +71,7 @@ const Panel: React.FC<PanelProps> = ({
return { return {
width: `calc(100% - ${(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0) width: `calc(100% - ${(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0)
}px)`, }px)`,
height: `${panelSize - 5}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",
[side]: "0", [side]: "0",
@@ -73,7 +79,7 @@ const Panel: React.FC<PanelProps> = ({
case "left": case "left":
case "right": case "right":
return { return {
width: `${panelSize - 5}px`, width: `${panelSize - 2}px`,
height: `calc(100% - ${(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0) height: `calc(100% - ${(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0)
}px)`, }px)`,
top: topActive ? `${panelSize}px` : "0", top: topActive ? `${panelSize}px` : "0",

View File

@@ -6,7 +6,9 @@ import { useSelectedZoneStore } from "../../../store/useZoneStore";
import DisplayZone from "./DisplayZone"; 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 { getZonesApi } from "../../../services/realTimeVisulization/zoneData/getZones"; import { useDroppedObjectsStore, useZones } from "../../../store/store";
import DroppedObjects from "./DroppedFloatingWidgets";
type Side = "top" | "bottom" | "left" | "right"; type Side = "top" | "bottom" | "left" | "right";
@@ -17,7 +19,9 @@ type FormattedZoneData = Record<
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
zoneCentrePoint: number[]; zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[]
widgets: Widget[]; widgets: Widget[];
} }
>; >;
@@ -28,60 +32,39 @@ type Widget = {
panel: Side; panel: Side;
data: any; data: any;
}; };
type Zone = {
zoneId: string;
zoneName: string;
points: number[][];
layer: number;
};
const RealTimeVisulization: React.FC = () => { const RealTimeVisulization: React.FC = () => {
const [hiddenPanels, setHiddenPanels] = React.useState<Side[]>([]); const [hiddenPanels, setHiddenPanels] = React.useState<Side[]>([]);
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const [droppedObjects, setDroppedObjects] = useState<any[]>([]);
const [zonesData, setZonesData] = useState<FormattedZoneData>({}); const [zonesData, setZonesData] = useState<FormattedZoneData>({});
const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const { zones } = useZones()
useEffect(() => { useEffect(() => {
async function GetZoneData() { const data = Array.isArray(zones) ? zones : [];
try {
const response: { data: Zone[] } | undefined = await getZonesApi(
"hexrfactory"
);
if (!response || !response.data) { const formattedData = data.reduce<FormattedZoneData>((acc, zone) => {
return;
}
const formattedData = response?.data?.reduce<FormattedZoneData>(
(acc, zone) => {
acc[zone.zoneName] = { acc[zone.zoneName] = {
activeSides: [], activeSides: [],
panelOrder: [], panelOrder: [],
lockedPanels: [], lockedPanels: [],
zoneCentrePoint: [], zoneId: zone.zoneId,
zoneViewPortTarget: zone.viewPortCenter,
zoneViewPortPosition: zone.viewPortposition,
widgets: [], widgets: [],
}; };
return acc; return acc;
}, }, {});
{}
);
setZonesData(formattedData); setZonesData(formattedData);
} catch (error) { } }, [zones]);
}
GetZoneData();
}, []);
useEffect(() => {
console.log('zonesData: ', zonesData);
}, [zonesData]);
useEffect(() => { useEffect(() => {
setZonesData((prev) => { setZonesData((prev) => {
if (!selectedZone) return prev; if (!selectedZone) return prev;
return { return {
...prev, ...prev,
[selectedZone.zoneName]: { [selectedZone.zoneName]: {
@@ -89,12 +72,46 @@ const RealTimeVisulization: React.FC = () => {
activeSides: selectedZone.activeSides || [], activeSides: selectedZone.activeSides || [],
panelOrder: selectedZone.panelOrder || [], panelOrder: selectedZone.panelOrder || [],
lockedPanels: selectedZone.lockedPanels || [], lockedPanels: selectedZone.lockedPanels || [],
zoneId: selectedZone.zoneId || "",
zoneViewPortTarget: selectedZone.zoneViewPortTarget || [],
zoneViewPortPosition: selectedZone.zoneViewPortPosition || [],
widgets: selectedZone.widgets || [], widgets: selectedZone.widgets || [],
}, },
}; };
}); });
}, [selectedZone]); }, [selectedZone]);
// const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
// console.log("Drop event fired! ✅");
// event.preventDefault();
// const data = event.dataTransfer.getData("text/plain");
// if (!data) {
// console.log("❌ No data received on drop!");
// return;
// }
// try {
// const droppedData = JSON.parse(data);
// console.log("✅ Dropped Data:", droppedData);
// console.log('droppedData: ', droppedData);
// setDroppedObjects((prev) => [...prev, droppedData]); // ✅ Add to state
// console.log(droppedObjects);
// } catch (error) {
// console.error("❌ Error parsing dropped data:", error);
// }
// };
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
const data = event.dataTransfer.getData("text/plain"); // Use "text/plain" to match the drag event
if (data) {
const droppedData = JSON.parse(data);
useDroppedObjectsStore.getState().addObject(droppedData); // Add to Zustand store
}
};
return ( return (
<div <div
ref={containerRef} ref={containerRef}
@@ -113,7 +130,10 @@ const RealTimeVisulization: React.FC = () => {
width: "100%", width: "100%",
borderRadius: isPlaying || activeModule !== "visualization" ? "" : "6px", borderRadius: isPlaying || activeModule !== "visualization" ? "" : "6px",
}} }}
onDrop={(event) => handleDrop(event)}
onDragOver={(event) => event.preventDefault()}
> >
<Scene /> <Scene />
</div> </div>
{activeModule === "visualization" && ( {activeModule === "visualization" && (
@@ -124,7 +144,7 @@ const RealTimeVisulization: React.FC = () => {
setSelectedZone={setSelectedZone} setSelectedZone={setSelectedZone}
/> />
{!isPlaying && ( {!isPlaying && selectedZone?.zoneName !== "" && (
<AddButtons <AddButtons
hiddenPanels={hiddenPanels} hiddenPanels={hiddenPanels}
setHiddenPanels={setHiddenPanels} setHiddenPanels={setHiddenPanels}
@@ -134,9 +154,10 @@ const RealTimeVisulization: React.FC = () => {
)} )}
<Panel <Panel
hiddenPanels={hiddenPanels}
selectedZone={selectedZone} selectedZone={selectedZone}
setSelectedZone={setSelectedZone} setSelectedZone={setSelectedZone}
hiddenPanels={hiddenPanels}
/> />
</> </>
)} )}

View File

@@ -0,0 +1,107 @@
import { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import * as THREE from "three";
import { useSelectedZoneStore } from "../../../store/useZoneStore";
import { useEditPosition, usezonePosition, usezoneTarget } from "../../../store/store";
export default function ZoneCentreTarget() {
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const [previousZoneCentre, setPreviousZoneCentre] = useState<number[] | null>(null);
const sphereRef = useRef<THREE.Mesh>(null);
const { camera, controls }: any = useThree();
const { zonePosition, setZonePosition } = usezonePosition();
const { zoneTarget, setZoneTarget } = usezoneTarget();
const { Edit, setEdit } = useEditPosition();
useEffect(() => {
if (
selectedZone.zoneViewPortTarget &&
JSON.stringify(previousZoneCentre) !== JSON.stringify(selectedZone.zoneViewPortTarget)
) {
setPreviousZoneCentre(selectedZone.zoneViewPortTarget);
}
}, [selectedZone.zoneViewPortTarget, previousZoneCentre]);
const centrePoint = useMemo(() => {
if (!previousZoneCentre || !selectedZone.zoneViewPortTarget) return null;
return previousZoneCentre.map((value, index) =>
(value + selectedZone.zoneViewPortTarget[index]) / 2
);
}, [previousZoneCentre, selectedZone.zoneViewPortTarget]);
useEffect(() => {
if (selectedZone.zoneName !== "") {
if (sphereRef.current) {
sphereRef.current.position.set(selectedZone.zoneViewPortTarget[0], selectedZone.zoneViewPortTarget[1], selectedZone.zoneViewPortTarget[2]);
}
if (centrePoint) {
if (centrePoint.length > 0) {
let camPosition = new THREE.Vector3(...selectedZone.zoneViewPortPosition);
let CamTarget = new THREE.Vector3(...selectedZone.zoneViewPortTarget);
const direction = new THREE.Vector3().subVectors(CamTarget, camPosition).normalize();
const worldUp = new THREE.Vector3(0, 0, 1);
const right = new THREE.Vector3().crossVectors(worldUp, direction).normalize();
const up = new THREE.Vector3().crossVectors(direction, right).normalize();
const offsetPosition = up.clone().multiplyScalar(20);
camPosition.add(offsetPosition);
const setCam = async () => {
controls.setLookAt(centrePoint[0], 100, centrePoint[2], ...centrePoint, true);
setTimeout(() => {
controls?.setLookAt(
...camPosition.toArray(),
selectedZone.zoneViewPortTarget[0],
selectedZone.zoneViewPortTarget[1],
selectedZone.zoneViewPortTarget[2],
true
);
}, 400)
};
setCam();
} else {
let camPosition = new THREE.Vector3(...selectedZone.zoneViewPortPosition);
let CamTarget = new THREE.Vector3(...selectedZone.zoneViewPortTarget);
const direction = new THREE.Vector3().subVectors(CamTarget, camPosition).normalize();
const worldUp = new THREE.Vector3(0, 0, 1);
const right = new THREE.Vector3().crossVectors(worldUp, direction).normalize();
const up = new THREE.Vector3().crossVectors(direction, right).normalize();
const offsetPosition = up.clone().multiplyScalar(20);
camPosition.add(offsetPosition);
const setCam = async () => {
controls?.setLookAt(
...camPosition.toArray(),
selectedZone.zoneViewPortTarget[0],
selectedZone.zoneViewPortTarget[1],
selectedZone.zoneViewPortTarget[2],
true
);
};
setCam();
}
}
}
}, [selectedZone.zoneViewPortTarget]);
useFrame(() => {
if (Edit) {
setZonePosition([controls.getPosition().x, controls.getPosition().y, controls.getPosition().z])
setZoneTarget([controls.getTarget().x, controls.getTarget().y, controls.getTarget().z])
}
})
return (
<> </>
);
}

View File

@@ -1,99 +1,213 @@
// import React, { useState, useRef, useEffect } from "react";
// // Dropdown Item Component
// const DropdownItem = ({
// label,
// href,
// onClick,
// }: {
// label: string;
// href?: string;
// onClick?: () => void;
// }) => (
// <a
// href={href || "#"}
// className="dropdown-item"
// onClick={(e) => {
// e.preventDefault();
// onClick?.();
// }}
// >
// {label}
// </a>
// );
// // Nested Dropdown Component
// const NestedDropdown = ({
// label,
// children,
// onSelect,
// }: {
// label: string;
// children: React.ReactNode;
// onSelect: (selectedLabel: string) => void;
// }) => {
// const [open, setOpen] = useState(false);
// return (
// <div className="nested-dropdown">
// {/* Dropdown Trigger */}
// <div
// className={`dropdown-trigger ${open ? "open" : ""}`}
// onClick={() => setOpen(!open)} // Toggle submenu on click
// >
// {label} <span className="icon">{open ? "▼" : "▶"}</span>
// </div>
// {/* Submenu */}
// {open && (
// <div className="submenu">
// {React.Children.map(children, (child) => {
// if (React.isValidElement(child)) {
// // Clone the element and pass the `onSelect` prop only if it's expected
// return React.cloneElement(child as React.ReactElement<any>, { onSelect });
// }
// return child; // Return non-element children as-is
// })}
// </div>
// )}
// </div>
// );
// };
// // Recursive Function to Render Nested Data
// const renderNestedData = (
// data: Record<string, any>,
// onSelect: (selectedLabel: string) => void
// ) => {
// return Object.entries(data).map(([key, value]) => {
// if (typeof value === "object" && !Array.isArray(value)) {
// // If the value is an object, render it as a nested dropdown
// return (
// <NestedDropdown key={key} label={key} onSelect={onSelect}>
// {renderNestedData(value, onSelect)}
// </NestedDropdown>
// );
// } else if (Array.isArray(value)) {
// // If the value is an array, render each item as a dropdown item
// return value.map((item, index) => (
// <DropdownItem key={index} label={item} onClick={() => onSelect(item)} />
// ));
// } else {
// // If the value is a simple string, render it as a dropdown item
// return (
// <DropdownItem key={key} label={value} onClick={() => onSelect(value)} />
// );
// }
// });
// };
// // Main Multi-Level Dropdown Component
// const MultiLevelDropdown = ({ data }: { data: Record<string, any> }) => {
// const [open, setOpen] = useState(false);
// const [selectedLabel, setSelectedLabel] = useState("Dropdown trigger");
// const dropdownRef = useRef<HTMLDivElement>(null);
// // Handle outer click to close the dropdown
// useEffect(() => {
// const handleClickOutside = (event: MouseEvent) => {
// if (
// dropdownRef.current &&
// !dropdownRef.current.contains(event.target as Node)
// ) {
// setOpen(false);
// }
// };
// document.addEventListener("mousedown", handleClickOutside);
// return () => {
// document.removeEventListener("mousedown", handleClickOutside);
// };
// }, []);
// // Handle selection of an item
// const handleSelect = (selectedLabel: string) => {
// setSelectedLabel(selectedLabel); // Update the dropdown trigger text
// setOpen(false); // Close the dropdown
// };
// return (
// <div className="multi-level-dropdown" ref={dropdownRef}>
// {/* Dropdown Trigger Button */}
// <button
// className={`dropdown-button ${open ? "open" : ""}`}
// onClick={() => setOpen(!open)} // Toggle main menu on click
// >
// {selectedLabel} <span className="icon">▾</span>
// </button>
// {/* Dropdown Menu */}
// {open && (
// <div className="dropdown-menu">
// <div className="dropdown-content">
// {renderNestedData(data, handleSelect)}
// </div>
// </div>
// )}
// </div>
// );
// };
// export default MultiLevelDropdown;
import React, { useState, useRef, useEffect } from "react"; import React, { useState, useRef, useEffect } from "react";
// Dropdown Item Component // Dropdown Item Component
const DropdownItem = ({ const DropdownItem = ({
label, label,
href,
onClick, onClick,
}: { }: {
label: string; label: string;
href?: string; onClick: () => void;
onClick?: () => void;
}) => ( }) => (
<a <div className="dropdown-item" onClick={onClick}>
href={href || "#"}
className="dropdown-item"
onClick={(e) => {
e.preventDefault();
onClick?.();
}}
>
{label} {label}
</a> </div>
); );
// Nested Dropdown Component // Nested Dropdown Component
const NestedDropdown = ({ const NestedDropdown = ({
label, label,
children, fields,
onSelect, onSelect,
}: { }: {
label: string; label: string;
children: React.ReactNode; fields: string[];
onSelect: (selectedLabel: string) => void; onSelect: (selectedData: { name: string; fields: string }) => void;
}) => { }) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
return ( return (
<div className="nested-dropdown"> <div className="nested-dropdown">
{/* Dropdown Trigger */}
<div <div
className={`dropdown-trigger ${open ? "open" : ""}`} className={`dropdown-trigger ${open ? "open" : ""}`}
onClick={() => setOpen(!open)} // Toggle submenu on click onClick={() => setOpen(!open)}
> >
{label} <span className="icon">{open ? "▼" : "▶"}</span> {label} <span className="icon">{open ? "▼" : "▶"}</span>
</div> </div>
{/* Submenu */}
{open && ( {open && (
<div className="submenu"> <div className="submenu">
{React.Children.map(children, (child) => { {fields.map((field) => (
if (React.isValidElement(child)) { <DropdownItem
// Clone the element and pass the `onSelect` prop only if it's expected key={field}
return React.cloneElement(child as React.ReactElement<any>, { onSelect }); label={field}
} onClick={() => onSelect({ name: label, fields: field })}
return child; // Return non-element children as-is />
})} ))}
</div> </div>
)} )}
</div> </div>
); );
}; };
// Recursive Function to Render Nested Data // Props type for MultiLevelDropdown
const renderNestedData = ( interface MultiLevelDropdownProps {
data: Record<string, any>, data: Record<string, any>;
onSelect: (selectedLabel: string) => void onSelect: (selectedData: { name: string; fields: string }) => void;
) => { onUnselect: () => void;
return Object.entries(data).map(([key, value]) => { selectedValue?: { name: string; fields: string };
if (typeof value === "object" && !Array.isArray(value)) { }
// If the value is an object, render it as a nested dropdown
return (
<NestedDropdown key={key} label={key} onSelect={onSelect}>
{renderNestedData(value, onSelect)}
</NestedDropdown>
);
} else if (Array.isArray(value)) {
// If the value is an array, render each item as a dropdown item
return value.map((item, index) => (
<DropdownItem key={index} label={item} onClick={() => onSelect(item)} />
));
} else {
// If the value is a simple string, render it as a dropdown item
return (
<DropdownItem key={key} label={value} onClick={() => onSelect(value)} />
);
}
});
};
// Main Multi-Level Dropdown Component // Main Multi-Level Dropdown Component
const MultiLevelDropdown = ({ data }: { data: Record<string, any> }) => { const MultiLevelDropdown = ({
data,
onSelect,
onUnselect,
selectedValue
}: MultiLevelDropdownProps) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [selectedLabel, setSelectedLabel] = useState("Dropdown trigger");
const dropdownRef = useRef<HTMLDivElement>(null); const dropdownRef = useRef<HTMLDivElement>(null);
// Handle outer click to close the dropdown
useEffect(() => { useEffect(() => {
const handleClickOutside = (event: MouseEvent) => { const handleClickOutside = (event: MouseEvent) => {
if ( if (
@@ -103,34 +217,51 @@ const MultiLevelDropdown = ({ data }: { data: Record<string, any> }) => {
setOpen(false); setOpen(false);
} }
}; };
document.addEventListener("mousedown", handleClickOutside); document.addEventListener("mousedown", handleClickOutside);
return () => { return () => {
document.removeEventListener("mousedown", handleClickOutside); document.removeEventListener("mousedown", handleClickOutside);
}; };
}, []); }, []);
// Handle selection of an item // Handle item selection
const handleSelect = (selectedLabel: string) => { const handleItemSelect = (selectedData: { name: string; fields: string }) => {
setSelectedLabel(selectedLabel); // Update the dropdown trigger text onSelect(selectedData);
setOpen(false); // Close the dropdown setOpen(false);
}; };
// Handle unselect
const handleItemUnselect = () => {
onUnselect();
setOpen(false);
};
// Determine the display label
const displayLabel = selectedValue
? `${selectedValue.name} - ${selectedValue.fields}`
: "Dropdown trigger";
return ( return (
<div className="multi-level-dropdown" ref={dropdownRef}> <div className="multi-level-dropdown" ref={dropdownRef}>
{/* Dropdown Trigger Button */}
<button <button
className={`dropdown-button ${open ? "open" : ""}`} className={`dropdown-button ${open ? "open" : ""}`}
onClick={() => setOpen(!open)} // Toggle main menu on click onClick={() => setOpen(!open)}
> >
{selectedLabel} <span className="icon"></span> {displayLabel} <span className="icon"></span>
</button> </button>
{/* Dropdown Menu */}
{open && ( {open && (
<div className="dropdown-menu"> <div className="dropdown-menu">
<div className="dropdown-content"> <div className="dropdown-content">
{renderNestedData(data, handleSelect)} {/* Unselect Option */}
<DropdownItem label="Unselect" onClick={handleItemUnselect} />
{/* Nested Dropdown Items */}
{Object.entries(data).map(([key, value]) => (
<NestedDropdown
key={key}
label={key}
fields={Object.keys(value)}
onSelect={handleItemSelect}
/>
))}
</div> </div>
</div> </div>
)} )}
@@ -139,3 +270,4 @@ const MultiLevelDropdown = ({ data }: { data: Record<string, any> }) => {
}; };
export default MultiLevelDropdown; export default MultiLevelDropdown;

View File

@@ -1,4 +1,4 @@
import React, { useState, useRef } from "react"; import React, { useState, useRef, useEffect } from "react";
interface RenameInputProps { interface RenameInputProps {
value: string; value: string;
@@ -9,6 +9,9 @@ const RenameInput: React.FC<RenameInputProps> = ({ value, onRename }) => {
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const [text, setText] = useState(value); const [text, setText] = useState(value);
const inputRef = useRef<HTMLInputElement | null>(null); const inputRef = useRef<HTMLInputElement | null>(null);
useEffect(() => {
setText(value); // Ensure state updates when parent value changes
}, [value]);
const handleDoubleClick = () => { const handleDoubleClick = () => {
setIsEditing(true); setIsEditing(true);

View File

@@ -2,7 +2,8 @@ import React, { useEffect, useState } from "react";
import List from "./List"; import List from "./List";
import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons"; import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons";
import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect"; import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect";
import { getZonesApi } from "../../../services/realTimeVisulization/zoneData/getZones"; import { useZones } from "../../../store/store";
import { useSelectedZoneStore } from "../../../store/useZoneStore";
interface DropDownListProps { interface DropDownListProps {
value?: string; // Value to display in the DropDownList value?: string; // Value to display in the DropDownList
@@ -13,6 +14,7 @@ interface DropDownListProps {
kebabMenuItems?: { id: string; name: string }[]; // Items for the KebabMenuList kebabMenuItems?: { id: string; name: string }[]; // Items for the KebabMenuList
defaultOpen?: boolean; // Determines if the dropdown list should be open by default defaultOpen?: boolean; // Determines if the dropdown list should be open by default
listType?: string; // Type of list to display listType?: string; // Type of list to display
remove?: boolean;
} }
const DropDownList: React.FC<DropDownListProps> = ({ const DropDownList: React.FC<DropDownListProps> = ({
@@ -28,25 +30,25 @@ const DropDownList: React.FC<DropDownListProps> = ({
], ],
defaultOpen = false, defaultOpen = false,
listType = "default", listType = "default",
remove,
}) => { }) => {
const [isOpen, setIsOpen] = useState<boolean>(defaultOpen); const [isOpen, setIsOpen] = useState<boolean>(defaultOpen);
const { zones, setZones } = useZones()
const handleToggle = () => { const handleToggle = () => {
setIsOpen((prev) => !prev); // Toggle the state setIsOpen((prev) => !prev); // Toggle the state
}; };
const [zoneDataList, setZoneDataList] = useState<{ id: string; name: string }[]>([]); const [zoneDataList, setZoneDataList] = useState<{ id: string; name: string }[]>([]);
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
useEffect(() => { useEffect(() => {
async function GetZoneData() { const value = (zones || []).map((val: { zoneId: string; zoneName: string }) => ({
const response = await getZonesApi("hexrfactory") id: val.zoneId,
// console.log('response: ', response.data); name: val.zoneName
setZoneDataList([{ id: "1", name: "zone1" }, }));
{ id: "2", name: "Zone 2" },]) setZoneDataList(prev => (JSON.stringify(prev) !== JSON.stringify(value) ? value : prev));
} }, [zones]);
GetZoneData()
}, [])
return ( return (
<div className="dropdown-list-container"> <div className="dropdown-list-container">
@@ -81,7 +83,7 @@ const DropDownList: React.FC<DropDownListProps> = ({
</div> </div>
{isOpen && ( {isOpen && (
<div className="lists-container"> <div className="lists-container">
{listType === "default" && <List items={items} />} {listType === "default" && <List items={items} remove={remove} />}
{listType === "outline" && ( {listType === "outline" && (
<> <>
<DropDownList <DropDownList

View File

@@ -1,14 +1,38 @@
import React from "react"; import React from "react";
import RenameInput from "../inputs/RenameInput"; import RenameInput from "../inputs/RenameInput";
import { EyeIcon, LockIcon, RmoveIcon } from "../../icons/ExportCommonIcons"; import { EyeIcon, LockIcon, RmoveIcon } from "../../icons/ExportCommonIcons";
import { useSelectedZoneStore } from "../../../store/useZoneStore";
import { getZoneData } from "../../../services/realTimeVisulization/zoneData/getZones";
import { useSubModuleStore } from "../../../store/useModuleStore";
interface ListProps { interface ListProps {
items?: { id: string; name: string }[]; // Optional array of items to render items?: { id: string; name: string }[]; // Optional array of items to render
placeholder?: string; // Optional placeholder text placeholder?: string; // Optional placeholder text
remove?: boolean;
} }
const List: React.FC<ListProps> = ({ items = [] }) => { const List: React.FC<ListProps> = ({ items = [], remove }) => {
console.log('items: ', items); const { setSelectedZone } = useSelectedZoneStore();
const { setSubModule } = useSubModuleStore();
async function handleSelectZone(id: string) {
setSubModule("zoneProperties")
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
let response = await getZoneData(id, organization)
setSelectedZone({
zoneName: response?.zoneName,
activeSides: response?.activeSides || [],
panelOrder: response?.panelOrder || [],
lockedPanels: response?.lockedPanels || [],
widgets: response?.widgets || [],
zoneId: response?.zoneId,
zoneViewPortTarget: response?.viewPortCenter || [],
zoneViewPortPosition:
response?.viewPortposition || [],
});
}
return ( return (
<> <>
{items.length > 0 ? ( {items.length > 0 ? (
@@ -16,7 +40,7 @@ const List: React.FC<ListProps> = ({ items = [] }) => {
{items.map((item, index) => ( {items.map((item, index) => (
<li key={index} className="list-container"> <li key={index} className="list-container">
<div className="list-item"> <div className="list-item">
<div className="value"> <div className="value" onClick={() => handleSelectZone(item.id)}>
<RenameInput value={item.name} /> <RenameInput value={item.name} />
</div> </div>
<div className="options-container"> <div className="options-container">
@@ -26,9 +50,11 @@ const List: React.FC<ListProps> = ({ items = [] }) => {
<div className="visibe option"> <div className="visibe option">
<EyeIcon isClosed /> <EyeIcon isClosed />
</div> </div>
{remove && (
<div className="remove option"> <div className="remove option">
<RmoveIcon /> <RmoveIcon />
</div> </div>
)}
</div> </div>
</div> </div>
</li> </li>

View File

@@ -1,5 +1,107 @@
import { useMemo } from "react"; // import { useMemo } from "react";
import { Line } from "react-chartjs-2"; // import { Line } from "react-chartjs-2";
// interface ChartComponentProps {
// type: any;
// title: string;
// fontFamily?: string;
// fontSize?: string;
// fontWeight?: "Light" | "Regular" | "Bold";
// data: any;
// }
// const LineGraphComponent = ({
// title,
// fontFamily,
// fontSize,
// fontWeight = "Regular",
// }: ChartComponentProps) => {
// // Memoize Font Weight Mapping
// const chartFontWeightMap = useMemo(
// () => ({
// Light: "lighter" as const,
// Regular: "normal" as const,
// Bold: "bold" as const,
// }),
// []
// );
// // Parse and Memoize Font Size
// const fontSizeValue = useMemo(
// () => (fontSize ? parseInt(fontSize) : 12),
// [fontSize]
// );
// // Determine and Memoize Font Weight
// const fontWeightValue = useMemo(
// () => chartFontWeightMap[fontWeight],
// [fontWeight, chartFontWeightMap]
// );
// // Memoize Chart Font Style
// const chartFontStyle = useMemo(
// () => ({
// family: fontFamily || "Arial",
// size: fontSizeValue,
// weight: fontWeightValue,
// }),
// [fontFamily, fontSizeValue, fontWeightValue]
// );
// const options = useMemo(
// () => ({
// responsive: true,
// maintainAspectRatio: false,
// plugins: {
// title: {
// display: true,
// text: title,
// font: chartFontStyle,
// },
// legend: {
// display: false,
// },
// },
// scales: {
// x: {
// ticks: {
// display: true, // This hides the x-axis labels
// },
// },
// },
// }),
// [title, chartFontStyle]
// );
// const chartData = {
// labels: ["January", "February", "March", "April", "May", "June", "July"],
// datasets: [
// {
// label: "My First Dataset",
// data: [65, 59, 80, 81, 56, 55, 40],
// backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple)
// borderColor: "#ffffff", // Keeping border color white
// borderWidth: 2,
// fill: false,
// },
// ],
// };
// return <Line data={chartData} options={options} />;
// };
// export default LineGraphComponent;
import React, { useEffect, useRef, useMemo, useState } from "react";
import { Chart } from "chart.js/auto";
import { useThemeStore } from "../../../../store/useThemeStore";
import io from "socket.io-client";
import { Line } from 'react-chartjs-2';
import useChartStore from "../../../../store/useChartStore";
// WebSocket Connection
// const socket = io("http://localhost:5000"); // Adjust to your backend URL
interface ChartComponentProps { interface ChartComponentProps {
type: any; type: any;
@@ -11,11 +113,30 @@ interface ChartComponentProps {
} }
const LineGraphComponent = ({ const LineGraphComponent = ({
type,
title, title,
fontFamily, fontFamily,
fontSize, fontSize,
fontWeight = "Regular", fontWeight = "Regular",
data,
}: ChartComponentProps) => { }: ChartComponentProps) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const { themeColor } = useThemeStore();
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
labels: [],
datasets: [],
});
// Memoize Theme Colors to Prevent Unnecessary Recalculations
const buttonActionColor = useMemo(
() => themeColor[0] || "#5c87df",
[themeColor]
);
const buttonAbortColor = useMemo(
() => themeColor[1] || "#ffffff",
[themeColor]
);
// Memoize Font Weight Mapping // Memoize Font Weight Mapping
const chartFontWeightMap = useMemo( const chartFontWeightMap = useMemo(
() => ({ () => ({
@@ -48,6 +169,10 @@ const LineGraphComponent = ({
[fontFamily, fontSizeValue, fontWeightValue] [fontFamily, fontSizeValue, fontWeightValue]
); );
// Memoize Chart Data
// const data = useMemo(() => propsData, [propsData]);
// Memoize Chart Options
const options = useMemo( const options = useMemo(
() => ({ () => ({
responsive: true, responsive: true,
@@ -73,24 +198,68 @@ const LineGraphComponent = ({
[title, chartFontStyle] [title, chartFontStyle]
); );
const chartData = { const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [ useEffect(() => {
{ if ( measurements.length > 0 ) {
label: "My First Dataset", const socket = io("http://192.168.0.192:5010");
data: [65, 59, 80, 81, 56, 55, 40],
backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple) var inputes = {
borderColor: "#ffffff", // Keeping border color white measurements: measurements,
duration: duration,
interval: 1000,
}
console.log('graphHHHHHHHHHHHHHHHHHHHHHHHHHHHHH',inputes);
// Start stream
const startStream = () => {
socket.emit("lineInput", inputes);
}
socket.on('connect', startStream);
socket.on("lineOutput", (response) => {
const responceData = response.data;
console.log("Received data:", responceData);
// Extract timestamps and values
const labels = responceData.time;
const datasets = data.measurements.map((measurement: any) => ({
label: `${measurement.name}.${measurement.fields}`,
data: responceData[`${measurement.name}.${measurement.fields}`]?.values || [],
backgroundColor: themeColor[0] || "#5c87df",
borderColor: themeColor[1] || "#ffffff",
borderWidth: 2, borderWidth: 2,
fill: false, // fill: false,
}, }));
],
setChartData({ labels, datasets });
});
return () => {
socket.off("lineOutput");
socket.emit("stop_stream"); // Stop streaming when component unmounts
}; };
}
}, [measurements, duration]);
// useEffect(() => {
// if (!canvasRef.current) return;
// const ctx = canvasRef.current.getContext("2d");
// if (!ctx) return;
// const chart = new Chart(ctx, {
// type,
// data: chartData,
// options: options,
// });
// return () => chart.destroy();
// }, [chartData, type, title]);
return <Line data={chartData} options={options} />; return <Line data={chartData} options={options} />;
}; };
export default LineGraphComponent; export default LineGraphComponent;
// like this

View File

@@ -13,8 +13,22 @@ const SimpleCard: React.FC<SimpleCardProps> = ({
value, value,
per, per,
}) => { }) => {
const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
const cardData = JSON.stringify({
header,
value,
per,
className: event.currentTarget.className,
});
console.log("Dragging Data:", cardData); // ✅ Debugging log
event.dataTransfer.setData("text/plain", cardData);
};
return ( return (
<div className="floating total-card" draggable> <div className="floating total-card" draggable onDragStart={handleDragStart}>
<div className="header-wrapper"> <div className="header-wrapper">
<div className="header">{header}</div> <div className="header">{header}</div>
<div className="data-values"> <div className="data-values">

View File

@@ -112,7 +112,7 @@ export default async function assetManager(
) { ) {
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
const existingModel = itemsGroup.current.getObjectByProperty("uuid", item.modeluuid); const existingModel = itemsGroup?.current?.getObjectByProperty("uuid", item.modeluuid);
if (existingModel) { if (existingModel) {
// console.log(`Model ${item.modelname} already exists in the scene.`); // console.log(`Model ${item.modelname} already exists in the scene.`);
resolve(); resolve();

View File

@@ -65,6 +65,8 @@ const ZoneGroup: React.FC = () => {
zoneId: zone.zoneId, zoneId: zone.zoneId,
zoneName: zone.zoneName, zoneName: zone.zoneName,
points: zone.points, points: zone.points,
viewPortCenter: zone.viewPortCenter,
viewPortposition: zone.viewPortposition,
layer: zone.layer layer: zone.layer
})); }));
@@ -145,7 +147,7 @@ const ZoneGroup: React.FC = () => {
const target: [number, number, number] | null = calculateCenter(zone.points); const target: [number, number, number] | null = calculateCenter(zone.points);
if (!target) return; if (!target) return;
const position = [target[0], 75, target[2]]; const position = [target[0], 10, target[2]];
const input = { const input = {
userId: userId, userId: userId,
@@ -186,7 +188,7 @@ const ZoneGroup: React.FC = () => {
const target: [number, number, number] | null = calculateCenter(zone.points); const target: [number, number, number] | null = calculateCenter(zone.points);
if (!target) return; if (!target) return;
const position = [target[0], 75, target[2]]; const position = [target[0], 10, target[2]];
const input = { const input = {
userId: userId, userId: userId,

View File

@@ -745,6 +745,7 @@ export default function SocketResponses({
return return
} }
if (data.message === "zone deleted") { if (data.message === "zone deleted") {
console.log('data: ', data);
const updatedZones = zones.filter((zone: any) => zone.zoneId !== data.data.zoneId); const updatedZones = zones.filter((zone: any) => zone.zoneId !== data.data.zoneId);
setZones(updatedZones); setZones(updatedZones);

View File

@@ -0,0 +1,95 @@
import React from "react";
import assetImage from "../../assets/image/image.png";
import { FiileedStarsIconSmall } from "../../components/icons/marketPlaceIcons";
// Define the shape of the selected card
interface SelectedCard {
assetName: string;
uploadedOn: string;
price: number;
rating: number;
views: number;
}
// Define the props type for AssetPreview
interface AssetPreviewProps {
selectedCard: SelectedCard;
setSelectedCard: React.Dispatch<React.SetStateAction<SelectedCard | null>>; // Type for setter function
}
const AssetPreview: React.FC<AssetPreviewProps> = ({
selectedCard,
setSelectedCard,
}) => {
// Ensure rating is a valid number between 0 and 5
const rating = Math.max(
0,
Math.min(5, isNaN(selectedCard.rating) ? 0 : selectedCard.rating)
);
console.log("selectedCard: ", selectedCard);
// Ensure that the rating is a valid positive integer for array length
const starsArray = Array.from({ length: rating }, (_, index) => index);
return (
<div className="assetPreview-wrapper">
<div className="assetPreview">
<div className="image-preview">
<img src={assetImage} alt="" />
</div>
<div className="asset-details-preview">
<div className="organization">
<div className="image">H</div>
<div className="organization-details">
<div className="organization-name">HERX FACTORY</div>
<div className="follow">Follow +</div>
</div>
</div>
{/* asset details */}
<div className="asset-details">
<div className="asset-name">{selectedCard.assetName}</div>
<div className="asset-description">
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Doloremque nisi beatae facilis architecto quaerat delectus velit
aliquid assumenda cumque vitae! Tempore quibusdam ab natus in
minima voluptates, aliquid corrupti excepturi consectetur
distinctio sequi beatae odit autem? Distinctio ab, voluptatem
omnis quibusdam, incidunt eum ipsa aliquid enim eaque eveniet nisi
autem, accusantium vel! Laborum in iste voluptates ad! Harum eum
amet pariatur fugit laudantium dolorem maxime voluptates atque
molestiae modi inventore quidem maiores dolore numquam, natus
quisquam optio distinctio eveniet aliquam, aut eligendi laboriosam
eaque! Porro cumque cum distinctio ullam debitis, dolorum
similique! Harum cupiditate perferendis voluptatum molestiae,
fugiat quisquam assumenda!
</div>
<div className="asset-review">
<div className="asset-rating">
<FiileedStarsIconSmall />
{selectedCard.rating}
</div>
<div className="asset-view">{selectedCard.views} views</div>
</div>
<div className="asset-price"> {selectedCard.price}</div>
</div>
{/* buttons */}
<div className="button-container">
<div className="button">Add to cart</div>
<div className="button">Buy now</div>
</div>
{/* close button */}
<div className="closeButton" onClick={() => setSelectedCard(null)}>
{`<-back`}
</div>
</div>
</div>
</div>
);
};
export default AssetPreview;

View File

@@ -1,4 +1,4 @@
import { useMemo } from "react"; import { useMemo, useState } from "react";
import { Canvas } from "@react-three/fiber"; import { Canvas } from "@react-three/fiber";
import { Environment, KeyboardControls } from "@react-three/drei"; import { Environment, KeyboardControls } from "@react-three/drei";
@@ -15,6 +15,12 @@ import background from "../../assets/textures/hdr/mudroadpuresky2k.hdr";
import SelectionControls from "./controls/selection/selectionControls"; import SelectionControls from "./controls/selection/selectionControls";
import MeasurementTool from "./tools/measurementTool"; import MeasurementTool from "./tools/measurementTool";
import Simulation from "../simulation/simulation"; import Simulation from "../simulation/simulation";
import ZoneCentreTarget from "../../components/ui/componets/zoneCameraTarget";
import { useThree } from "@react-three/fiber";
import * as THREE from "three";
import DroppedObjects from "../../components/ui/componets/DroppedFloatingWidgets";
// import Simulation from "./simulationtemp/simulation"; // import Simulation from "./simulationtemp/simulation";
export default function Scene() { export default function Scene() {
@@ -27,6 +33,9 @@ export default function Scene() {
// { name: "jump", keys: ["Space"] }, // { name: "jump", keys: ["Space"] },
], []) ], [])
return ( return (
<KeyboardControls map={map}> <KeyboardControls map={map}>
<Canvas <Canvas
@@ -36,12 +45,15 @@ export default function Scene() {
onContextMenu={(e) => { onContextMenu={(e) => {
e.preventDefault(); e.preventDefault();
}} }}
> >
<DroppedObjects/>
<Controls /> <Controls />
<TransformControl /> <TransformControl />
<SelectionControls /> <SelectionControls />
<MeasurementTool /> <MeasurementTool />
<World /> <World />
<ZoneCentreTarget />
{/* <Simulation /> */} {/* <Simulation /> */}
<Simulation /> <Simulation />
<PostProcessing /> <PostProcessing />

View File

@@ -1,25 +1,23 @@
let url_Backend_dwinzo = `http://185.100.212.76:5000`; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const getZonesApi = async (organization: string) => { export const getZoneData = async (zoneId: string, organization: string) => {
try { try {
const response = await fetch(`${url_Backend_dwinzo}/api/v2/findZones/${organization}`, { const response = await fetch(
`${url_Backend_dwinzo}/api/v2/A_zone/${zoneId}/${organization}`,
{
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
});
// if (!response.ok) {
// throw new Error("Failed to get Zones");
// }
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");
} }
);
if (!response.ok) {
throw new Error("Failed to fetch zoneData");
}
return await response.json();
} catch (error: any) {
throw new Error(error.message);
} }
}; };

View File

@@ -0,0 +1,31 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_BACKEND_URL}`;
type Side = "top" | "bottom" | "left" | "right";
export const panelData = async (organization: string, zoneID: string, panelOrder: Side[]) => {
console.log('panelOrder: ', panelOrder);
console.log('zoneID: ', zoneID);
console.log('organization: ', organization);
try {
const response = await fetch(`${url_Backend_dwinzo}/api/v1/panel/save`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ organization, zoneID, panelOrder }),
});
if (!response.ok) {
throw new Error("Failed to add panelOrder for 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");
}
}
};

View File

@@ -1,5 +1,5 @@
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 { create } from "zustand"; import { create } from "zustand";
import { io } from "socket.io-client"; import { io } from "socket.io-client";
@@ -11,10 +11,13 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
return; return;
} }
const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/`, { const socket = io(
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/`,
{
reconnection: false, reconnection: false,
auth: { email } auth: { email },
}); }
);
set({ socket }); set({ socket });
}, },
@@ -23,7 +26,7 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
state.socket?.disconnect(); state.socket?.disconnect();
return { socket: null }; return { socket: null };
}); });
} },
})); }));
export const useOrganization = create<any>((set: any) => ({ export const useOrganization = create<any>((set: any) => ({
@@ -126,9 +129,7 @@ export const useFloorItems = create<any>((set: any) => ({
setFloorItems: (callback: any) => setFloorItems: (callback: any) =>
set((state: any) => ({ set((state: any) => ({
floorItems: floorItems:
typeof callback === "function" typeof callback === "function" ? callback(state.floorItems) : callback,
? callback(state.floorItems)
: callback,
})), })),
})); }));
@@ -137,9 +138,7 @@ export const useWallItems = create<any>((set: any) => ({
setWallItems: (callback: any) => setWallItems: (callback: any) =>
set((state: any) => ({ set((state: any) => ({
wallItems: wallItems:
typeof callback === "function" typeof callback === "function" ? callback(state.wallItems) : callback,
? callback(state.wallItems)
: callback,
})), })),
})); }));
@@ -180,7 +179,8 @@ export const useShadows = create<any>((set: any) => ({
export const useSunPosition = create<any>((set: any) => ({ export const useSunPosition = create<any>((set: any) => ({
sunPosition: { x: undefined, y: undefined, z: undefined }, sunPosition: { x: undefined, y: undefined, z: undefined },
setSunPosition: (newSuntPosition: any) => set({ sunPosition: newSuntPosition }), setSunPosition: (newSuntPosition: any) =>
set({ sunPosition: newSuntPosition }),
})); }));
export const useRemoveLayer = create<any>((set: any) => ({ export const useRemoveLayer = create<any>((set: any) => ({
@@ -216,7 +216,7 @@ export const useActiveTool = create<any>((set: any) => ({
export const use2DUndoRedo = create<any>((set: any) => ({ export const use2DUndoRedo = create<any>((set: any) => ({
is2DUndoRedo: null, is2DUndoRedo: null,
set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }), set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }),
})) }));
export const useElevation = create<any>((set: any) => ({ export const useElevation = create<any>((set: any) => ({
elevation: 45, elevation: 45,
@@ -245,7 +245,8 @@ export const useUserName = create<any>((set: any) => ({
export const useObjectPosition = create<any>((set: any) => ({ export const useObjectPosition = create<any>((set: any) => ({
objectPosition: { x: undefined, y: undefined, z: undefined }, objectPosition: { x: undefined, y: undefined, z: undefined },
setObjectPosition: (newObjectPosition: any) => set({ objectPosition: newObjectPosition }), setObjectPosition: (newObjectPosition: any) =>
set({ objectPosition: newObjectPosition }),
})); }));
export const useObjectScale = create<any>((set: any) => ({ export const useObjectScale = create<any>((set: any) => ({
@@ -255,7 +256,8 @@ export const useObjectScale = create<any>((set: any) => ({
export const useObjectRotation = create<any>((set: any) => ({ export const useObjectRotation = create<any>((set: any) => ({
objectRotation: { x: undefined, y: undefined, z: undefined }, objectRotation: { x: undefined, y: undefined, z: undefined },
setObjectRotation: (newObjectRotation: any) => set({ objectRotation: newObjectRotation }), setObjectRotation: (newObjectRotation: any) =>
set({ objectRotation: newObjectRotation }),
})); }));
export const useDrieTemp = create<any>((set: any) => ({ export const useDrieTemp = create<any>((set: any) => ({
@@ -271,11 +273,21 @@ export const useActiveUsers = create<any>((set: any) => ({
export const useDrieUIValue = create<any>((set: any) => ({ export const useDrieUIValue = create<any>((set: any) => ({
drieUIValue: { touch: null, temperature: null, humidity: null }, drieUIValue: { touch: null, temperature: null, humidity: null },
setDrieUIValue: (x: any) => set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })), setDrieUIValue: (x: any) =>
set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })),
setTouch: (value: any) => set((state: any) => ({ drieUIValue: { ...state.drieUIValue, touch: value } })), setTouch: (value: any) =>
setTemperature: (value: any) => set((state: any) => ({ drieUIValue: { ...state.drieUIValue, temperature: value } })), set((state: any) => ({
setHumidity: (value: any) => set((state: any) => ({ drieUIValue: { ...state.drieUIValue, humidity: value } })), drieUIValue: { ...state.drieUIValue, touch: value },
})),
setTemperature: (value: any) =>
set((state: any) => ({
drieUIValue: { ...state.drieUIValue, temperature: value },
})),
setHumidity: (value: any) =>
set((state: any) => ({
drieUIValue: { ...state.drieUIValue, humidity: value },
})),
})); }));
export const useDrawMaterialPath = create<any>((set: any) => ({ export const useDrawMaterialPath = create<any>((set: any) => ({
@@ -300,7 +312,16 @@ interface Path {
uuid: string; uuid: string;
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number]; rotation: [number, number, number];
actions: { uuid: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | []; actions:
| {
uuid: string;
type: string;
material: string;
delay: number | string;
spawnInterval: number | string;
isUsed: boolean;
}[]
| [];
triggers: { uuid: string; type: string; isUsed: boolean }[] | []; triggers: { uuid: string; type: string; isUsed: boolean }[] | [];
}[]; }[];
pathPosition: [number, number, number]; pathPosition: [number, number, number];
@@ -318,7 +339,6 @@ export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
setSimulationPaths: (paths) => set({ simulationPaths: paths }), setSimulationPaths: (paths) => set({ simulationPaths: paths }),
})); }));
// interface Point { // interface Point {
// uuid: string; // uuid: string;
// position: [number, number, number]; // position: [number, number, number];
@@ -363,7 +383,6 @@ export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
// setSimulationPaths: (paths) => set({ simulationPaths: paths }), // setSimulationPaths: (paths) => set({ simulationPaths: paths }),
// })); // }));
export const useConnections = create<Types.ConnectionStore>((set) => ({ export const useConnections = create<Types.ConnectionStore>((set) => ({
connections: [], connections: [],
@@ -400,3 +419,39 @@ export const useStartSimulation = create<any>((set: any) => ({
startSimulation: false, startSimulation: false,
setStartSimulation: (x: any) => set({ startSimulation: x }), setStartSimulation: (x: any) => set({ startSimulation: x }),
})); }));
export const usezoneTarget = create<any>((set: any) => ({
zoneTarget: [],
setZoneTarget: (x: any) => set({ zoneTarget: x }),
}));
export const usezonePosition = create<any>((set: any) => ({
zonePosition: [],
setZonePosition: (x: any) => set({ zonePosition: x }),
}));
interface EditPositionState {
Edit: boolean;
setEdit: (value: boolean) => void;
}
export const useEditPosition = create<EditPositionState>((set) => ({
Edit: false,
setEdit: (value) => set({ Edit: value }), // Properly updating the state
}));
interface DroppedObject {
header: string;
value: string;
per: string;
className: string;
}
interface DroppedObjectsState {
objects: DroppedObject[];
addObject: (obj: DroppedObject) => void;
}
export const useDroppedObjectsStore = create<DroppedObjectsState>((set) => ({
objects: [],
addObject: (obj) => set((state) => ({ objects: [...state.objects, obj] })),
}));

View File

@@ -0,0 +1,28 @@
import { create } from "zustand";
interface Measurement {
name: string;
fields: string;
}
interface MeasurementStore {
measurements: Measurement[];
interval: number;
duration: string;
setMeasurements: (newMeasurements: Measurement[]) => void;
updateDuration: (newDuration: string) => void;
}
const useChartStore = create<MeasurementStore>((set) => ({
measurements: [],
interval: 1000,
duration: "1h",
setMeasurements: (newMeasurements) =>
set(() => ({ measurements: newMeasurements })),
updateDuration: (newDuration) =>
set(() => ({ duration: newDuration })),
}));
export default useChartStore;

View File

@@ -15,21 +15,31 @@ interface SelectedZoneState {
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[];
widgets: Widget[]; widgets: Widget[];
} }
interface SelectedZoneStore { interface SelectedZoneStore {
selectedZone: SelectedZoneState; selectedZone: SelectedZoneState;
setSelectedZone: (zone: Partial<SelectedZoneState> | ((prev: SelectedZoneState) => SelectedZoneState)) => void; setSelectedZone: (
zone:
| Partial<SelectedZoneState>
| ((prev: SelectedZoneState) => SelectedZoneState)
) => void;
} }
export const useSelectedZoneStore = create<SelectedZoneStore>((set) => ({ export const useSelectedZoneStore = create<SelectedZoneStore>((set) => ({
selectedZone: { selectedZone: {
zoneName: "", zoneName: "", // Empty string initially
activeSides: [], activeSides: [], // Empty array
panelOrder: [], panelOrder: [], // Empty array
lockedPanels: [], lockedPanels: [], // Empty array
widgets: [], zoneId: "",
zoneViewPortTarget: [],
zoneViewPortPosition: [],
widgets: [], // Empty array
}, },
setSelectedZone: (zone) => setSelectedZone: (zone) =>
set((state) => ({ set((state) => ({

View File

@@ -161,25 +161,49 @@
width: 30px; width: 30px;
height: 30px; height: 30px;
border-radius: 50%; border-radius: 50%;
background-color: var(--accent-color); background-color: var(--highlight-accent-color);
cursor: pointer; cursor: pointer;
@include flex-center; @include flex-center;
position: fixed; position: fixed;
bottom: 60px; bottom: 60px;
left: 50%; left: 50%;
transform: translate(-50%, 0); transform: translate(-50%, 0);
transition: background-color 0.3s, transform 0.3s; color: var(--accent-color);
color: var(--background-color);
// transform: none;
z-index: 100; z-index: 100;
isolation: isolate;
font-weight: 700;
&:hover { &:hover {
font-weight: 500;
background-color: var(--accent-color); background-color: var(--accent-color);
color: var(--highlight-accent-color);
&::after{
animation: pulse 1s ease-out infinite;
}
}
&::after{
content: "";
position: absolute;
height: 100%;
width: 100%;
background: var(--background-color-secondary);
border-radius: #{$border-radius-circle};
z-index: -1;
} }
} }
@keyframes pulse {
0%{
opacity: 0;
scale: .5;
}
50%{
opacity: 1;
}
100%{
opacity: 0;
scale: 2;
}
}
@keyframes expandWidth { @keyframes expandWidth {
from { from {