diff --git a/app/.gitignore b/app/.gitignore index d1f5e53..2f5cb0a 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1,29 +1,29 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -# /package-lock.json -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* - - -# remove zip -*.zip -**/temp/ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +# /package-lock.json +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + + +# remove zip +*.zip +**/temp/ diff --git a/app/package-lock.json b/app/package-lock.json index c8d940e..20fa0fc 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -47,6 +47,7 @@ "devDependencies": { "@types/node": "^22.9.1", "@types/three": "^0.169.0", + "axios": "^1.8.4", "cypress": "^13.14.2", "dotenv": "^16.4.5", "husky": "^9.1.6", @@ -7672,6 +7673,25 @@ "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": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", diff --git a/app/package.json b/app/package.json index f8eb17d..e7ca3e7 100644 --- a/app/package.json +++ b/app/package.json @@ -69,6 +69,7 @@ "devDependencies": { "@types/node": "^22.9.1", "@types/three": "^0.169.0", + "axios": "^1.8.4", "cypress": "^13.14.2", "dotenv": "^16.4.5", "husky": "^9.1.6", diff --git a/app/src/components/icons/marketPlaceIcons.tsx b/app/src/components/icons/marketPlaceIcons.tsx index 9aa8619..76dedd3 100644 --- a/app/src/components/icons/marketPlaceIcons.tsx +++ b/app/src/components/icons/marketPlaceIcons.tsx @@ -130,3 +130,24 @@ export function StarsIconSmall() { ); } + +export function FiileedStarsIconSmall() { + return ( + + + + ); +} diff --git a/app/src/components/layout/sidebarLeft/Outline.tsx b/app/src/components/layout/sidebarLeft/Outline.tsx index a364947..bad3b59 100644 --- a/app/src/components/layout/sidebarLeft/Outline.tsx +++ b/app/src/components/layout/sidebarLeft/Outline.tsx @@ -30,6 +30,7 @@ const Outline: React.FC = () => { defaultOpen={true} showKebabMenu={false} showFocusIcon={true} + remove /> { const { activeModule } = useModuleStore(); - const [activeList] = useState("properties"); const { toggleUI } = useToggleStore(); const { selectedActionSphere } = useSelectedActionSphere(); const { subModule, setSubModule } = useSubModuleStore(); @@ -38,9 +37,8 @@ const SideBarRight: React.FC = () => {
{/* {activeModule === "builder" && ( */}
setSubModule("properties")} > @@ -49,28 +47,25 @@ const SideBarRight: React.FC = () => { {activeModule === "simulation" && ( <>
setSubModule("mechanics")} > - +
setSubModule("simulations")} > - +
setSubModule("analysis")} > - +
)} @@ -78,7 +73,7 @@ const SideBarRight: React.FC = () => { )} {/* process builder */} {toggleUI && - activeList === "properties" && + subModule === "properties" && activeModule !== "visualization" && (
@@ -88,7 +83,17 @@ const SideBarRight: React.FC = () => {
)} - + {toggleUI && + subModule === "zoneProperties" && + activeModule === "builder" && ( +
+
+ {/* */} + + {/* */} +
+
+ )} {/* simulation */} {toggleUI && activeModule === "simulation" && ( @@ -114,7 +119,7 @@ const SideBarRight: React.FC = () => {
)} - {activeList === "simulations" && ( + {subModule === "simulations" && (
diff --git a/app/src/components/layout/sidebarRight/customInput/Vector3Input.tsx b/app/src/components/layout/sidebarRight/customInput/Vector3Input.tsx index 05b7041..38fae4e 100644 --- a/app/src/components/layout/sidebarRight/customInput/Vector3Input.tsx +++ b/app/src/components/layout/sidebarRight/customInput/Vector3Input.tsx @@ -1,62 +1,57 @@ import React from "react"; import { EyeDroperIcon } from "../../../icons/ExportCommonIcons"; +// import { useThree } from "@react-three/fiber"; interface PositionInputProps { - onChange: (value: string) => void; // Callback for value change + onChange: (value: [number, number, number]) => void; // Callback for value change header: string; placeholder?: string; // Optional placeholder type?: string; // Input type (e.g., text, number, email) + value: [number, number, number] | null; + disabled?: boolean; // To enable/disable editing } const Vector3Input: React.FC = ({ onChange, header, 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 (
- {header}{" "} -
- -
+ {header}
-
-
X :
- onChange(e.target.value)} - placeholder={placeholder} - disabled - /> -
-
-
Y :
- onChange(e.target.value)} - placeholder={placeholder} - disabled - min={0} - /> -
-
-
Z :
- onChange(e.target.value)} - placeholder={placeholder} - disabled - /> -
+ {["X", "Y", "Z"].map((axis, i) => ( +
+
{axis}:
+ handleChange(i, e.target.value)} + placeholder={placeholder} + disabled={disabled} + /> +
+ ))}
); }; -export default Vector3Input; +export default Vector3Input; \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx index 65dd55f..c707f14 100644 --- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx @@ -1,32 +1,65 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import RenameInput from "../../../ui/inputs/RenameInput"; import Vector3Input from "../customInput/Vector3Input"; +import { useSelectedZoneStore } from "../../../../store/useZoneStore"; +import { useEditPosition, usezonePosition, usezoneTarget } from "../../../../store/store"; 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() { + console.log("setApi"); + + console.log('zoneTarget: ', zoneTarget); + console.log('zonePosition: ', zonePosition); setEdit(false); } function handleEditView() { - if (Edit) { - setEdit(false); - } else { - setEdit(true); - } + setEdit(!Edit); // This will toggle the `Edit` state correctly } + 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 (
- +
{Edit ? "Cancel" : "Edit"}
- {}} header="Viewport Target" /> - {}} header="Viewport Position" /> + handleVectorChange("zoneViewPortTarget", value)} + header="Viewport Target" + value={zoneTarget as [number, number, number]} + disabled={!Edit} + /> + handleVectorChange("zoneViewPortPosition", value)} + header="Viewport Position" + value={zonePosition as [number, number, number]} + disabled={!Edit} + /> + {Edit && (
Set View @@ -37,3 +70,4 @@ const ZoneProperties: React.FC = () => { }; export default ZoneProperties; + diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx new file mode 100644 index 0000000..c223c67 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx @@ -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>({}) + 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 ( + <> +
+ {[...Array(6)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} + /> +
+ +
+
+
+ ); + })} +
+
+
+
duration
+
+ +
+
+
+ + ) +} + +export default LineGrapInput \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx new file mode 100644 index 0000000..5b056a5 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx @@ -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>({}) + + 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 ( + <> +
+ {[...Array(3)].map((_, index) => { + const inputKey = `input${index+1}`; + return ( +
+
Input {index+1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} + /> +
+ +
+
+
+ ); + })} +
+
+ +
+ + ) +} + +export default PieChartInput \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/visualization/data/Data.tsx b/app/src/components/layout/sidebarRight/visualization/data/Data.tsx index 039ad1e..71847c7 100644 --- a/app/src/components/layout/sidebarRight/visualization/data/Data.tsx +++ b/app/src/components/layout/sidebarRight/visualization/data/Data.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons"; import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown"; +import LineGrapInput from "../IotInputCards/LineGrapInput"; // Define the data structure for demonstration purposes const DATA_STRUCTURE = { @@ -123,41 +124,10 @@ const Data = () => {
{selectedChartId?.title}
)} {/* Render groups dynamically */} - {chartDataGroups[selectedChartId?.id]?.map((group) => ( -
- {group.children.map((child, index) => ( -
-
Input {index + 1}
-
- - {/* Add Icon */} - {group.children.length < 7 && ( -
handleAddClick(group.id)} // Pass groupId to handleAddClick - > - -
- )} - {/* Remove Icon */} - - 1 ? "" : "disable" - }`} - onClick={(e) => { - e.stopPropagation(); // Prevent event bubbling - removeChild(group.id, child.id); // Pass groupId and childId to removeChild - }} - > - - -
-
- ))} -
- ))} - + { + chartDataGroups[selectedChartId?.id] && + } + {/* Info Box */}
i @@ -173,3 +143,40 @@ const Data = () => { }; export default Data; + + + +// {chartDataGroups[selectedChartId?.id]?.map((group) => ( +//
+// {group.children.map((child, index) => ( +//
+//
Input {index + 1}
+//
+// +// {/* Add Icon */} +// {group.children.length < 7 && ( +//
handleAddClick(group.id)} // Pass groupId to handleAddClick +// > +// +//
+// )} +// {/* Remove Icon */} + +// 1 ? "" : "disable" +// }`} +// onClick={(e) => { +// e.stopPropagation(); // Prevent event bubbling +// removeChild(group.id, child.id); // Pass groupId and childId to removeChild +// }} +// > +// +// +//
+//
+// ))} +//
+// ))} diff --git a/app/src/components/ui/componets/AddButtons.tsx b/app/src/components/ui/componets/AddButtons.tsx index ee3092e..42dc082 100644 --- a/app/src/components/ui/componets/AddButtons.tsx +++ b/app/src/components/ui/componets/AddButtons.tsx @@ -4,6 +4,7 @@ import { EyeIcon, LockIcon, } from "../../icons/RealTimeVisulationIcons"; +import { panelData } from "../../../services/realTimeVisulization/zoneData/panel"; // Define the type for `Side` type Side = "top" | "bottom" | "left" | "right"; @@ -15,6 +16,9 @@ interface ButtonsProps { activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[] widgets: { id: string; type: string; @@ -29,6 +33,9 @@ interface ButtonsProps { activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[] widgets: { id: string; type: string; @@ -108,7 +115,7 @@ const AddButtons: React.FC = ({ panelOrder: newActiveSides, }; - // Update the selectedZone state + // Delete the selectedZone state console.log('updatedZone: ', updatedZone); setSelectedZone(updatedZone); } else { @@ -120,73 +127,84 @@ const AddButtons: React.FC = ({ activeSides: 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 - console.log('updatedZone: ', updatedZone); + console.log("updatedZone: ", updatedZone); setSelectedZone(updatedZone); } }; return ( -
- {(["top", "right", "bottom", "left"] as Side[]).map((side) => ( -
- + <> +
+ {(["top", "right", "bottom", "left"] as Side[]).map((side) => ( +
+ {/* "+" Button */} + - {/* Extra Buttons */} - {selectedZone.activeSides.includes(side) && ( -
- {/* Hide Panel */} -
toggleVisibility(side)} - > - -
+ {/* Extra Buttons */} + {selectedZone.activeSides.includes(side) && ( +
+ {/* Hide Panel */} +
toggleVisibility(side)} + > + +
- {/* Clean Panel */} -
cleanPanel(side)} - > - -
+ {/* Clean Panel */} +
cleanPanel(side)} + > + +
- {/* Lock/Unlock Panel */} -
toggleLockPanel(side)} - > - + {/* Lock/Unlock Panel */} +
toggleLockPanel(side)} + > + +
-
- )} -
- ))} -
+ )} +
+ ))} +
+ ); }; diff --git a/app/src/components/ui/componets/DisplayZone.tsx b/app/src/components/ui/componets/DisplayZone.tsx index e699f27..56c67bb 100644 --- a/app/src/components/ui/componets/DisplayZone.tsx +++ b/app/src/components/ui/componets/DisplayZone.tsx @@ -11,6 +11,9 @@ interface DisplayZoneProps { panelOrder: Side[]; lockedPanels: Side[]; widgets: Widget[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[]; }; }; selectedZone: { @@ -18,6 +21,9 @@ interface DisplayZoneProps { activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[]; widgets: { id: string; type: string; @@ -32,6 +38,9 @@ interface DisplayZoneProps { activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[]; widgets: { id: string; type: string; @@ -152,16 +161,16 @@ const DisplayZone: React.FC = ({ return (
{Object.keys(zonesData).map((zoneName, index) => (
{ - console.log('zoneName: ', zoneName); + setSelectedZone({ zoneName, @@ -169,12 +178,15 @@ const DisplayZone: React.FC = ({ panelOrder: zonesData[zoneName].panelOrder || [], lockedPanels: zonesData[zoneName].lockedPanels || [], widgets: zonesData[zoneName].widgets || [], - }) + zoneId: zonesData[zoneName]?.zoneId || "", + zoneViewPortTarget: zonesData[zoneName].zoneViewPortTarget || [], + zoneViewPortPosition: + zonesData[zoneName].zoneViewPortPosition || [], + }); // setSelectedZone({ // zoneName, // ...zonesData[zoneName], // }); - console.log(selectedZone); }} > {zoneName} @@ -184,4 +196,4 @@ const DisplayZone: React.FC = ({ ); }; -export default DisplayZone; \ No newline at end of file +export default DisplayZone; diff --git a/app/src/components/ui/componets/DraggableWidget.tsx b/app/src/components/ui/componets/DraggableWidget.tsx index 1157292..9172fa4 100644 --- a/app/src/components/ui/componets/DraggableWidget.tsx +++ b/app/src/components/ui/componets/DraggableWidget.tsx @@ -1,165 +1,164 @@ -import { useWidgetStore } from "../../../store/useWidgetStore"; -import ProgressCard from "../realTimeVis/charts/ProgressCard"; -import PieGraphComponent from "../realTimeVis/charts/PieGraphComponent"; -import BarGraphComponent from "../realTimeVis/charts/BarGraphComponent"; -import LineGraphComponent from "../realTimeVis/charts/LineGraphComponent"; -import RadarGraphComponent from "../realTimeVis/charts/RadarGraphComponent"; -import DoughnutGraphComponent from "../realTimeVis/charts/DoughnutGraphComponent"; -import PolarAreaGraphComponent from "../realTimeVis/charts/PolarAreaGraphComponent"; - -export const DraggableWidget = ({ - widget, - hiddenPanels, // Add this prop to track hidden panels - index, onReorder -}: { - widget: any; - hiddenPanels: string[]; // Array of hidden panel names - index: number; onReorder: (fromIndex: number, toIndex: number) => void -}) => { - - const { selectedChartId, setSelectedChartId } = useWidgetStore(); - - const handlePointerDown = () => { - if (selectedChartId?.id !== widget.id) { - setSelectedChartId(widget); - } - }; - - // Determine if the widget's panel is hidden - const isPanelHidden = hiddenPanels.includes(widget.panel); - - const handleDragStart = (event: React.DragEvent) => { - event.dataTransfer.setData('text/plain', index.toString()); // Store the index of the dragged widget - }; - const handleDragEnter = (event: React.DragEvent) => { - event.preventDefault(); // Allow drop - }; - - const handleDragOver = (event: React.DragEvent) => { - event.preventDefault(); // Allow drop - }; - - const handleDrop = (event: React.DragEvent) => { - event.preventDefault(); - const fromIndex = parseInt(event.dataTransfer.getData('text/plain'), 10); // Get the dragged widget's index - const toIndex = index; // The index of the widget where the drop occurred - if (fromIndex !== toIndex) { - onReorder(fromIndex, toIndex); // Call the reorder function passed as a prop - } - }; - - - return ( - <> - - - ); -}; +import { useWidgetStore } from "../../../store/useWidgetStore"; +import ProgressCard from "../realTimeVis/charts/ProgressCard"; +import PieGraphComponent from "../realTimeVis/charts/PieGraphComponent"; +import BarGraphComponent from "../realTimeVis/charts/BarGraphComponent"; +import LineGraphComponent from "../realTimeVis/charts/LineGraphComponent"; +import RadarGraphComponent from "../realTimeVis/charts/RadarGraphComponent"; +import DoughnutGraphComponent from "../realTimeVis/charts/DoughnutGraphComponent"; +import PolarAreaGraphComponent from "../realTimeVis/charts/PolarAreaGraphComponent"; + +export const DraggableWidget = ({ + widget, + hiddenPanels, // Add this prop to track hidden panels + index, onReorder +}: { + widget: any; + hiddenPanels: string[]; // Array of hidden panel names + index: number; onReorder: (fromIndex: number, toIndex: number) => void +}) => { + const { selectedChartId, setSelectedChartId } = useWidgetStore(); + + const handlePointerDown = () => { + if (selectedChartId?.id !== widget.id) { + setSelectedChartId(widget); + } + }; + + // Determine if the widget's panel is hidden + const isPanelHidden = hiddenPanels.includes(widget.panel); + + const handleDragStart = (event: React.DragEvent) => { + event.dataTransfer.setData('text/plain', index.toString()); // Store the index of the dragged widget + }; + const handleDragEnter = (event: React.DragEvent) => { + event.preventDefault(); // Allow drop + }; + + const handleDragOver = (event: React.DragEvent) => { + event.preventDefault(); // Allow drop + }; + + const handleDrop = (event: React.DragEvent) => { + event.preventDefault(); + const fromIndex = parseInt(event.dataTransfer.getData('text/plain'), 10); // Get the dragged widget's index + const toIndex = index; // The index of the widget where the drop occurred + if (fromIndex !== toIndex) { + onReorder(fromIndex, toIndex); // Call the reorder function passed as a prop + } + }; + + + return ( + <> + + + ); +}; diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx new file mode 100644 index 0000000..f7c1bd3 --- /dev/null +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -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 ( +// +// {/* Render dropped objects as green boxes */} +// {objects.map((obj) => ( +// +// +// +// +// ))} +// +// ); +// }; + +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) => ( + + +
+
{obj.header}
+
+
{obj.value}
+
{obj.per}
+
+
+ +
+ ))} + + ); +}; + +export default DroppedObjects; + diff --git a/app/src/components/ui/componets/Panel.tsx b/app/src/components/ui/componets/Panel.tsx index 03ce03b..6cce425 100644 --- a/app/src/components/ui/componets/Panel.tsx +++ b/app/src/components/ui/componets/Panel.tsx @@ -20,6 +20,9 @@ interface PanelProps { activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[] widgets: Widget[]; }; setSelectedZone: React.Dispatch< @@ -28,6 +31,9 @@ interface PanelProps { activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[] widgets: Widget[]; }> >; @@ -65,7 +71,7 @@ const Panel: React.FC = ({ return { width: `calc(100% - ${(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0) }px)`, - height: `${panelSize - 5}px`, + height: `${panelSize - 2}px`, left: leftActive ? `${panelSize}px` : "0", right: rightActive ? `${panelSize}px` : "0", [side]: "0", @@ -73,7 +79,7 @@ const Panel: React.FC = ({ case "left": case "right": return { - width: `${panelSize - 5}px`, + width: `${panelSize - 2}px`, height: `calc(100% - ${(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0) }px)`, top: topActive ? `${panelSize}px` : "0", diff --git a/app/src/components/ui/componets/RealTimeVisulization.tsx b/app/src/components/ui/componets/RealTimeVisulization.tsx index 90aa06f..cecc2c0 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -6,7 +6,9 @@ import { useSelectedZoneStore } from "../../../store/useZoneStore"; import DisplayZone from "./DisplayZone"; import Scene from "../../../modules/scene/scene"; 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"; @@ -17,7 +19,9 @@ type FormattedZoneData = Record< activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; - zoneCentrePoint: number[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[] widgets: Widget[]; } >; @@ -28,60 +32,39 @@ type Widget = { panel: Side; data: any; }; -type Zone = { - zoneId: string; - zoneName: string; - points: number[][]; - layer: number; -}; const RealTimeVisulization: React.FC = () => { const [hiddenPanels, setHiddenPanels] = React.useState([]); const containerRef = useRef(null); const { isPlaying } = usePlayButtonStore(); const { activeModule } = useModuleStore(); - + const [droppedObjects, setDroppedObjects] = useState([]); const [zonesData, setZonesData] = useState({}); const { selectedZone, setSelectedZone } = useSelectedZoneStore(); + const { zones } = useZones() useEffect(() => { - async function GetZoneData() { - try { - const response: { data: Zone[] } | undefined = await getZonesApi( - "hexrfactory" - ); + const data = Array.isArray(zones) ? zones : []; - if (!response || !response.data) { - return; - } - const formattedData = response?.data?.reduce( - (acc, zone) => { - acc[zone.zoneName] = { - activeSides: [], - panelOrder: [], - lockedPanels: [], - zoneCentrePoint: [], - widgets: [], - }; - return acc; - }, - {} - ); - setZonesData(formattedData); - } catch (error) { } - } - GetZoneData(); - }, []); + const formattedData = data.reduce((acc, zone) => { + acc[zone.zoneName] = { + activeSides: [], + panelOrder: [], + lockedPanels: [], + zoneId: zone.zoneId, + zoneViewPortTarget: zone.viewPortCenter, + zoneViewPortPosition: zone.viewPortposition, + widgets: [], + }; + return acc; + }, {}); - useEffect(() => { - - console.log('zonesData: ', zonesData); - }, [zonesData]); + setZonesData(formattedData); + }, [zones]); useEffect(() => { setZonesData((prev) => { if (!selectedZone) return prev; - return { ...prev, [selectedZone.zoneName]: { @@ -89,12 +72,46 @@ const RealTimeVisulization: React.FC = () => { activeSides: selectedZone.activeSides || [], panelOrder: selectedZone.panelOrder || [], lockedPanels: selectedZone.lockedPanels || [], + zoneId: selectedZone.zoneId || "", + zoneViewPortTarget: selectedZone.zoneViewPortTarget || [], + zoneViewPortPosition: selectedZone.zoneViewPortPosition || [], widgets: selectedZone.widgets || [], }, }; }); }, [selectedZone]); + // const handleDrop = (event: React.DragEvent) => { + // 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) => { + 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 (
{ width: "100%", borderRadius: isPlaying || activeModule !== "visualization" ? "" : "6px", }} + onDrop={(event) => handleDrop(event)} + onDragOver={(event) => event.preventDefault()} > +
{activeModule === "visualization" && ( @@ -124,7 +144,7 @@ const RealTimeVisulization: React.FC = () => { setSelectedZone={setSelectedZone} /> - {!isPlaying && ( + {!isPlaying && selectedZone?.zoneName !== "" && ( { )} )} diff --git a/app/src/components/ui/componets/zoneCameraTarget.tsx b/app/src/components/ui/componets/zoneCameraTarget.tsx new file mode 100644 index 0000000..2412926 --- /dev/null +++ b/app/src/components/ui/componets/zoneCameraTarget.tsx @@ -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(null); + const sphereRef = useRef(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 ( + <> + ); +} diff --git a/app/src/components/ui/inputs/MultiLevelDropDown.tsx b/app/src/components/ui/inputs/MultiLevelDropDown.tsx index 3c1780b..ef74bcf 100644 --- a/app/src/components/ui/inputs/MultiLevelDropDown.tsx +++ b/app/src/components/ui/inputs/MultiLevelDropDown.tsx @@ -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; +// }) => ( +// { +// e.preventDefault(); +// onClick?.(); +// }} +// > +// {label} +// +// ); + +// // Nested Dropdown Component +// const NestedDropdown = ({ +// label, +// children, +// onSelect, +// }: { +// label: string; +// children: React.ReactNode; +// onSelect: (selectedLabel: string) => void; +// }) => { +// const [open, setOpen] = useState(false); + +// return ( +//
+// {/* Dropdown Trigger */} +//
setOpen(!open)} // Toggle submenu on click +// > +// {label} {open ? "▼" : "▶"} +//
+ +// {/* Submenu */} +// {open && ( +//
+// {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, { onSelect }); +// } +// return child; // Return non-element children as-is +// })} +//
+// )} +//
+// ); +// }; + +// // Recursive Function to Render Nested Data +// const renderNestedData = ( +// data: Record, +// 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 ( +// +// {renderNestedData(value, onSelect)} +// +// ); +// } else if (Array.isArray(value)) { +// // If the value is an array, render each item as a dropdown item +// return value.map((item, index) => ( +// onSelect(item)} /> +// )); +// } else { +// // If the value is a simple string, render it as a dropdown item +// return ( +// onSelect(value)} /> +// ); +// } +// }); +// }; + +// // Main Multi-Level Dropdown Component +// const MultiLevelDropdown = ({ data }: { data: Record }) => { +// const [open, setOpen] = useState(false); +// const [selectedLabel, setSelectedLabel] = useState("Dropdown trigger"); +// const dropdownRef = useRef(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 ( +//
+// {/* Dropdown Trigger Button */} +// + +// {/* Dropdown Menu */} +// {open && ( +//
+//
+// {renderNestedData(data, handleSelect)} +//
+//
+// )} +//
+// ); +// }; + +// export default MultiLevelDropdown; + import React, { useState, useRef, useEffect } from "react"; // Dropdown Item Component const DropdownItem = ({ label, - href, onClick, }: { label: string; - href?: string; - onClick?: () => void; + onClick: () => void; }) => ( - { - e.preventDefault(); - onClick?.(); - }} - > + ); // Nested Dropdown Component const NestedDropdown = ({ label, - children, + fields, onSelect, }: { label: string; - children: React.ReactNode; - onSelect: (selectedLabel: string) => void; + fields: string[]; + onSelect: (selectedData: { name: string; fields: string }) => void; }) => { const [open, setOpen] = useState(false); return (
- {/* Dropdown Trigger */}
setOpen(!open)} // Toggle submenu on click + onClick={() => setOpen(!open)} > {label} {open ? "▼" : "▶"}
- - {/* Submenu */} {open && (
- {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, { onSelect }); - } - return child; // Return non-element children as-is - })} + {fields.map((field) => ( + onSelect({ name: label, fields: field })} + /> + ))}
)}
); }; -// Recursive Function to Render Nested Data -const renderNestedData = ( - data: Record, - 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 ( - - {renderNestedData(value, onSelect)} - - ); - } else if (Array.isArray(value)) { - // If the value is an array, render each item as a dropdown item - return value.map((item, index) => ( - onSelect(item)} /> - )); - } else { - // If the value is a simple string, render it as a dropdown item - return ( - onSelect(value)} /> - ); - } - }); -}; +// Props type for MultiLevelDropdown +interface MultiLevelDropdownProps { + data: Record; + onSelect: (selectedData: { name: string; fields: string }) => void; + onUnselect: () => void; + selectedValue?: { name: string; fields: string }; +} // Main Multi-Level Dropdown Component -const MultiLevelDropdown = ({ data }: { data: Record }) => { +const MultiLevelDropdown = ({ + data, + onSelect, + onUnselect, + selectedValue +}: MultiLevelDropdownProps) => { const [open, setOpen] = useState(false); - const [selectedLabel, setSelectedLabel] = useState("Dropdown trigger"); const dropdownRef = useRef(null); - // Handle outer click to close the dropdown useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( @@ -103,34 +217,51 @@ const MultiLevelDropdown = ({ data }: { data: Record }) => { 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 + // Handle item selection + const handleItemSelect = (selectedData: { name: string; fields: string }) => { + onSelect(selectedData); + setOpen(false); }; + // Handle unselect + const handleItemUnselect = () => { + onUnselect(); + setOpen(false); + }; + + // Determine the display label + const displayLabel = selectedValue + ? `${selectedValue.name} - ${selectedValue.fields}` + : "Dropdown trigger"; + return (
- {/* Dropdown Trigger Button */} - - {/* Dropdown Menu */} {open && (
- {renderNestedData(data, handleSelect)} + {/* Unselect Option */} + + {/* Nested Dropdown Items */} + {Object.entries(data).map(([key, value]) => ( + + ))}
)} @@ -138,4 +269,5 @@ const MultiLevelDropdown = ({ data }: { data: Record }) => { ); }; -export default MultiLevelDropdown; \ No newline at end of file +export default MultiLevelDropdown; + diff --git a/app/src/components/ui/inputs/RenameInput.tsx b/app/src/components/ui/inputs/RenameInput.tsx index cae54f3..d197dd4 100644 --- a/app/src/components/ui/inputs/RenameInput.tsx +++ b/app/src/components/ui/inputs/RenameInput.tsx @@ -1,4 +1,4 @@ -import React, { useState, useRef } from "react"; +import React, { useState, useRef, useEffect } from "react"; interface RenameInputProps { value: string; @@ -9,6 +9,9 @@ const RenameInput: React.FC = ({ value, onRename }) => { const [isEditing, setIsEditing] = useState(false); const [text, setText] = useState(value); const inputRef = useRef(null); + useEffect(() => { + setText(value); // Ensure state updates when parent value changes + }, [value]); const handleDoubleClick = () => { setIsEditing(true); diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index d31ef96..4ff51ca 100644 --- a/app/src/components/ui/list/DropDownList.tsx +++ b/app/src/components/ui/list/DropDownList.tsx @@ -2,7 +2,8 @@ import React, { useEffect, useState } from "react"; import List from "./List"; import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons"; import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect"; -import { getZonesApi } from "../../../services/realTimeVisulization/zoneData/getZones"; +import { useZones } from "../../../store/store"; +import { useSelectedZoneStore } from "../../../store/useZoneStore"; interface DropDownListProps { value?: string; // Value to display in the DropDownList @@ -13,6 +14,7 @@ interface DropDownListProps { kebabMenuItems?: { id: string; name: string }[]; // Items for the KebabMenuList defaultOpen?: boolean; // Determines if the dropdown list should be open by default listType?: string; // Type of list to display + remove?: boolean; } const DropDownList: React.FC = ({ @@ -28,25 +30,25 @@ const DropDownList: React.FC = ({ ], defaultOpen = false, listType = "default", + remove, }) => { + const [isOpen, setIsOpen] = useState(defaultOpen); + const { zones, setZones } = useZones() const handleToggle = () => { setIsOpen((prev) => !prev); // Toggle the state }; const [zoneDataList, setZoneDataList] = useState<{ id: string; name: string }[]>([]); + const { selectedZone, setSelectedZone } = useSelectedZoneStore(); useEffect(() => { - async function GetZoneData() { - const response = await getZonesApi("hexrfactory") - // console.log('response: ', response.data); - setZoneDataList([{ id: "1", name: "zone1" }, - { id: "2", name: "Zone 2" },]) - } - - GetZoneData() - - }, []) + const value = (zones || []).map((val: { zoneId: string; zoneName: string }) => ({ + id: val.zoneId, + name: val.zoneName + })); + setZoneDataList(prev => (JSON.stringify(prev) !== JSON.stringify(value) ? value : prev)); + }, [zones]); return (
@@ -81,7 +83,7 @@ const DropDownList: React.FC = ({
{isOpen && (
- {listType === "default" && } + {listType === "default" && } {listType === "outline" && ( <> = ({ items = [] }) => { - console.log('items: ', items); +const List: React.FC = ({ items = [], remove }) => { + 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 ( <> {items.length > 0 ? ( @@ -16,7 +40,7 @@ const List: React.FC = ({ items = [] }) => { {items.map((item, index) => (
  • -
    +
    handleSelectZone(item.id)}>
    @@ -26,9 +50,11 @@ const List: React.FC = ({ items = [] }) => {
    -
    - -
    + {remove && ( +
    + +
    + )}
  • diff --git a/app/src/components/ui/realTimeVis/charts/LineGraphComponent.tsx b/app/src/components/ui/realTimeVis/charts/LineGraphComponent.tsx index 5911842..07a387f 100644 --- a/app/src/components/ui/realTimeVis/charts/LineGraphComponent.tsx +++ b/app/src/components/ui/realTimeVis/charts/LineGraphComponent.tsx @@ -1,5 +1,107 @@ -import { useMemo } from "react"; -import { Line } from "react-chartjs-2"; +// import { useMemo } from "react"; +// 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 ; +// }; + +// 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 { type: any; @@ -11,86 +113,153 @@ interface ChartComponentProps { } const LineGraphComponent = ({ + type, title, fontFamily, fontSize, fontWeight = "Regular", + data, }: ChartComponentProps) => { - // Memoize Font Weight Mapping - const chartFontWeightMap = useMemo( - () => ({ - Light: "lighter" as const, - Regular: "normal" as const, - Bold: "bold" as const, - }), - [] - ); + const canvasRef = useRef(null); + const { themeColor } = useThemeStore(); + const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ + labels: [], + datasets: [], + }); - // 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 + // Memoize Theme Colors to Prevent Unnecessary Recalculations + const buttonActionColor = useMemo( + () => themeColor[0] || "#5c87df", + [themeColor] + ); + const buttonAbortColor = useMemo( + () => themeColor[1] || "#ffffff", + [themeColor] + ); + + // Memoize Font Weight Mapping + const chartFontWeightMap = useMemo( + () => ({ + Light: "lighter" as const, + Regular: "normal" as const, + Bold: "bold" as const, + }), + [] + ); + + // Parse and Memoize Font Size + const fontSizeValue = useMemo( + () => (fontSize ? parseInt(fontSize) : 12), + [fontSize] + ); + + // Determine and Memoize Font Weight + const fontWeightValue = useMemo( + () => chartFontWeightMap[fontWeight], + [fontWeight, chartFontWeightMap] + ); + + // Memoize Chart Font Style + const chartFontStyle = useMemo( + () => ({ + family: fontFamily || "Arial", + size: fontSizeValue, + weight: fontWeightValue, + }), + [fontFamily, fontSizeValue, fontWeightValue] + ); + + // Memoize Chart Data + // const data = useMemo(() => propsData, [propsData]); + + // Memoize Chart Options + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + text: title, + font: chartFontStyle, + }, + legend: { + display: false, }, }, - }, - }), - [title, chartFontStyle] - ); + 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 + const { measurements, setMeasurements, updateDuration, duration } = useChartStore(); + + useEffect(() => { + if ( measurements.length > 0 ) { + const socket = io("http://192.168.0.192:5010"); + + var inputes = { + 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, - 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 ; }; -export default LineGraphComponent; - - -// like this \ No newline at end of file +export default LineGraphComponent; \ No newline at end of file diff --git a/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx b/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx index d67e87f..ef3d85c 100644 --- a/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx +++ b/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx @@ -13,8 +13,22 @@ const SimpleCard: React.FC = ({ value, per, }) => { + + const handleDragStart = (event: React.DragEvent) => { + 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 ( -
    +
    {header}
    diff --git a/app/src/modules/builder/geomentries/assets/assetManager.ts b/app/src/modules/builder/geomentries/assets/assetManager.ts index f083395..38d0721 100644 --- a/app/src/modules/builder/geomentries/assets/assetManager.ts +++ b/app/src/modules/builder/geomentries/assets/assetManager.ts @@ -112,7 +112,7 @@ export default async function assetManager( ) { 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) { // console.log(`Model ${item.modelname} already exists in the scene.`); resolve(); diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index 9e0bc15..3d47a7e 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -65,6 +65,8 @@ const ZoneGroup: React.FC = () => { zoneId: zone.zoneId, zoneName: zone.zoneName, points: zone.points, + viewPortCenter: zone.viewPortCenter, + viewPortposition: zone.viewPortposition, layer: zone.layer })); @@ -145,7 +147,7 @@ const ZoneGroup: React.FC = () => { const target: [number, number, number] | null = calculateCenter(zone.points); if (!target) return; - const position = [target[0], 75, target[2]]; + const position = [target[0], 10, target[2]]; const input = { userId: userId, @@ -186,7 +188,7 @@ const ZoneGroup: React.FC = () => { const target: [number, number, number] | null = calculateCenter(zone.points); if (!target) return; - const position = [target[0], 75, target[2]]; + const position = [target[0], 10, target[2]]; const input = { userId: userId, diff --git a/app/src/modules/collaboration/socketResponses.dev.tsx b/app/src/modules/collaboration/socketResponses.dev.tsx index e9ca9e0..031629f 100644 --- a/app/src/modules/collaboration/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socketResponses.dev.tsx @@ -745,6 +745,7 @@ export default function SocketResponses({ return } if (data.message === "zone deleted") { + console.log('data: ', data); const updatedZones = zones.filter((zone: any) => zone.zoneId !== data.data.zoneId); setZones(updatedZones); diff --git a/app/src/modules/market/AssetPreview.tsx b/app/src/modules/market/AssetPreview.tsx new file mode 100644 index 0000000..a3c1cb0 --- /dev/null +++ b/app/src/modules/market/AssetPreview.tsx @@ -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>; // Type for setter function +} + +const AssetPreview: React.FC = ({ + 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 ( +
    +
    +
    + +
    + +
    +
    +
    H
    +
    +
    HERX FACTORY
    +
    Follow +
    +
    +
    + + {/* asset details */} +
    +
    {selectedCard.assetName}
    +
    + 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! +
    +
    +
    + + {selectedCard.rating} +
    +
    {selectedCard.views} views
    +
    +
    ₹ {selectedCard.price}
    +
    + + {/* buttons */} +
    +
    Add to cart
    +
    Buy now
    +
    + + {/* close button */} +
    setSelectedCard(null)}> + {`<-back`} +
    +
    +
    +
    + ); +}; + +export default AssetPreview; diff --git a/app/src/modules/market/CardsContainer.tsx b/app/src/modules/market/CardsContainer.tsx index 204ef6d..27d4a6b 100644 --- a/app/src/modules/market/CardsContainer.tsx +++ b/app/src/modules/market/CardsContainer.tsx @@ -15,4 +15,4 @@ const CardsContainer: React.FC = () => { ); }; -export default CardsContainer; \ No newline at end of file +export default CardsContainer; diff --git a/app/src/modules/market/MarketPlace.tsx b/app/src/modules/market/MarketPlace.tsx index 71dc0a5..a68bfc3 100644 --- a/app/src/modules/market/MarketPlace.tsx +++ b/app/src/modules/market/MarketPlace.tsx @@ -1,18 +1,18 @@ -import React from "react"; -import FilterSearch from "./FilterSearch"; -import CardsContainer from "./CardsContainer"; - -const MarketPlace = () => { - return ( -
    -
    -
    - - -
    -
    -
    - ); -}; - -export default MarketPlace; +import React from "react"; +import FilterSearch from "./FilterSearch"; +import CardsContainer from "./CardsContainer"; + +const MarketPlace = () => { + return ( +
    +
    +
    + + +
    +
    +
    + ); +}; + +export default MarketPlace; diff --git a/app/src/modules/scene/scene.tsx b/app/src/modules/scene/scene.tsx index 6d291b1..66ca9e7 100644 --- a/app/src/modules/scene/scene.tsx +++ b/app/src/modules/scene/scene.tsx @@ -1,4 +1,4 @@ -import { useMemo } from "react"; +import { useMemo, useState } from "react"; import { Canvas } from "@react-three/fiber"; 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 MeasurementTool from "./tools/measurementTool"; 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"; export default function Scene() { @@ -27,6 +33,9 @@ export default function Scene() { // { name: "jump", keys: ["Space"] }, ], []) + + + return ( { e.preventDefault(); }} + > + + {/* */} diff --git a/app/src/services/realTimeVisulization/zoneData/getZones.ts b/app/src/services/realTimeVisulization/zoneData/getZones.ts index b5e8147..39031d8 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZones.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZones.ts @@ -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) => { - try { - const response = await fetch(`${url_Backend_dwinzo}/api/v2/findZones/${organization}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }); +export const getZoneData = async (zoneId: string, organization: string) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v2/A_zone/${zoneId}/${organization}`, + { + method: "GET", + headers: { + "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"); } -}; \ No newline at end of file + + return await response.json(); + } catch (error: any) { + throw new Error(error.message); + } +}; diff --git a/app/src/services/realTimeVisulization/zoneData/panel.ts b/app/src/services/realTimeVisulization/zoneData/panel.ts new file mode 100644 index 0000000..5e0b5ac --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/panel.ts @@ -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"); + } + } +}; \ No newline at end of file diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 0cca1fe..86c6dee 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -1,324 +1,344 @@ import * as THREE from "three"; -import * as Types from '../types/world/worldTypes'; +import * as Types from "../types/world/worldTypes"; import { create } from "zustand"; import { io } from "socket.io-client"; export const useSocketStore = create((set: any, get: any) => ({ - socket: null, - initializeSocket: (email: any) => { - const existingSocket = get().socket; - if (existingSocket) { - return; - } - - const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/`, { - reconnection: false, - auth: { email } - }); - - set({ socket }); - }, - disconnectSocket: () => { - set((state: any) => { - state.socket?.disconnect(); - return { socket: null }; - }); + socket: null, + initializeSocket: (email: any) => { + const existingSocket = get().socket; + if (existingSocket) { + return; } + + const socket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/`, + { + reconnection: false, + auth: { email }, + } + ); + + set({ socket }); + }, + disconnectSocket: () => { + set((state: any) => { + state.socket?.disconnect(); + return { socket: null }; + }); + }, })); export const useOrganization = create((set: any) => ({ - organization: "", - setOrganization: (x: any) => set(() => ({ organization: x })), + organization: "", + setOrganization: (x: any) => set(() => ({ organization: x })), })); export const useToggleView = create((set: any) => ({ - toggleView: false, - setToggleView: (x: any) => set(() => ({ toggleView: x })), + toggleView: false, + setToggleView: (x: any) => set(() => ({ toggleView: x })), })); export const useUpdateScene = create((set: any) => ({ - updateScene: false, - setUpdateScene: (x: any) => set(() => ({ updateScene: x })), + updateScene: false, + setUpdateScene: (x: any) => set(() => ({ updateScene: x })), })); export const useWalls = create((set: any) => ({ - walls: [], - setWalls: (x: any) => set(() => ({ walls: x })), + walls: [], + setWalls: (x: any) => set(() => ({ walls: x })), })); export const useZones = create((set: any) => ({ - zones: [], - setZones: (x: any) => set(() => ({ zones: x })), + zones: [], + setZones: (x: any) => set(() => ({ zones: x })), })); interface ZonePointsState { - zonePoints: THREE.Vector3[]; - setZonePoints: (points: THREE.Vector3[]) => void; + zonePoints: THREE.Vector3[]; + setZonePoints: (points: THREE.Vector3[]) => void; } export const useZonePoints = create((set) => ({ - zonePoints: [], - setZonePoints: (points) => set({ zonePoints: points }), + zonePoints: [], + setZonePoints: (points) => set({ zonePoints: points }), })); export const useSelectedItem = create((set: any) => ({ - selectedItem: { name: "", id: "" }, - setSelectedItem: (x: any) => set(() => ({ selectedItem: x })), + selectedItem: { name: "", id: "" }, + setSelectedItem: (x: any) => set(() => ({ selectedItem: x })), })); export const useSelectedAssets = create((set: any) => ({ - selectedAssets: [], - setSelectedAssets: (x: any) => set(() => ({ selectedAssets: x })), + selectedAssets: [], + setSelectedAssets: (x: any) => set(() => ({ selectedAssets: x })), })); export const useLayers = create((set: any) => ({ - Layers: 1, - setLayers: (x: any) => set(() => ({ Layers: x })), + Layers: 1, + setLayers: (x: any) => set(() => ({ Layers: x })), })); export const useCamPosition = create((set: any) => ({ - camPosition: { x: undefined, y: undefined, z: undefined }, - setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }), + camPosition: { x: undefined, y: undefined, z: undefined }, + setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }), })); export const useMenuVisible = create((set: any) => ({ - menuVisible: false, - setMenuVisible: (x: any) => set(() => ({ menuVisible: x })), + menuVisible: false, + setMenuVisible: (x: any) => set(() => ({ menuVisible: x })), })); export const useDeleteModels = create((set: any) => ({ - deleteModels: false, - setDeleteModels: (x: any) => set(() => ({ deleteModels: x })), + deleteModels: false, + setDeleteModels: (x: any) => set(() => ({ deleteModels: x })), })); export const useToolMode = create((set: any) => ({ - toolMode: null, - setToolMode: (x: any) => set(() => ({ toolMode: x })), + toolMode: null, + setToolMode: (x: any) => set(() => ({ toolMode: x })), })); export const useNewLines = create((set: any) => ({ - newLines: [], - setNewLines: (x: any) => set(() => ({ newLines: x })), + newLines: [], + setNewLines: (x: any) => set(() => ({ newLines: x })), })); export const useDeletedLines = create((set: any) => ({ - deletedLines: [], - setDeletedLines: (x: any) => set(() => ({ deletedLines: x })), + deletedLines: [], + setDeletedLines: (x: any) => set(() => ({ deletedLines: x })), })); export const useMovePoint = create((set: any) => ({ - movePoint: false, - setMovePoint: (x: any) => set(() => ({ movePoint: x })), + movePoint: false, + setMovePoint: (x: any) => set(() => ({ movePoint: x })), })); export const useTransformMode = create((set: any) => ({ - transformMode: null, - setTransformMode: (x: any) => set(() => ({ transformMode: x })), + transformMode: null, + setTransformMode: (x: any) => set(() => ({ transformMode: x })), })); export const useDeletePointOrLine = create((set: any) => ({ - deletePointOrLine: false, - setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })), + deletePointOrLine: false, + setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })), })); export const useFloorItems = create((set: any) => ({ - floorItems: null, - setFloorItems: (callback: any) => - set((state: any) => ({ - floorItems: - typeof callback === "function" - ? callback(state.floorItems) - : callback, - })), + floorItems: null, + setFloorItems: (callback: any) => + set((state: any) => ({ + floorItems: + typeof callback === "function" ? callback(state.floorItems) : callback, + })), })); export const useWallItems = create((set: any) => ({ - wallItems: [], - setWallItems: (callback: any) => - set((state: any) => ({ - wallItems: - typeof callback === "function" - ? callback(state.wallItems) - : callback, - })), + wallItems: [], + setWallItems: (callback: any) => + set((state: any) => ({ + wallItems: + typeof callback === "function" ? callback(state.wallItems) : callback, + })), })); export const useSelectedWallItem = create((set: any) => ({ - selectedWallItem: null, - setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })), + selectedWallItem: null, + setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })), })); export const useselectedFloorItem = create((set: any) => ({ - selectedFloorItem: null, - setselectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })), + selectedFloorItem: null, + setselectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })), })); export const useDeletableFloorItem = create((set: any) => ({ - deletableFloorItem: null, - setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })), + deletableFloorItem: null, + setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })), })); export const useSetScale = create((set: any) => ({ - scale: null, - setScale: (x: any) => set(() => ({ scale: x })), + scale: null, + setScale: (x: any) => set(() => ({ scale: x })), })); export const useRoofVisibility = create((set: any) => ({ - roofVisibility: false, - setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })), + roofVisibility: false, + setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })), })); export const useWallVisibility = create((set: any) => ({ - wallVisibility: false, - setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })), + wallVisibility: false, + setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })), })); export const useShadows = create((set: any) => ({ - shadows: false, - setShadows: (x: any) => set(() => ({ shadows: x })), + shadows: false, + setShadows: (x: any) => set(() => ({ shadows: x })), })); export const useSunPosition = create((set: any) => ({ - sunPosition: { x: undefined, y: undefined, z: undefined }, - setSunPosition: (newSuntPosition: any) => set({ sunPosition: newSuntPosition }), + sunPosition: { x: undefined, y: undefined, z: undefined }, + setSunPosition: (newSuntPosition: any) => + set({ sunPosition: newSuntPosition }), })); export const useRemoveLayer = create((set: any) => ({ - removeLayer: false, - setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })), + removeLayer: false, + setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })), })); export const useRemovedLayer = create((set: any) => ({ - removedLayer: null, - setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })), + removedLayer: null, + setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })), })); export const useActiveLayer = create((set: any) => ({ - activeLayer: 1, - setActiveLayer: (x: any) => set({ activeLayer: x }), + activeLayer: 1, + setActiveLayer: (x: any) => set({ activeLayer: x }), })); export const useResetCamera = create((set: any) => ({ - resetCamera: false, - setResetCamera: (x: any) => set({ resetCamera: x }), + resetCamera: false, + setResetCamera: (x: any) => set({ resetCamera: x }), })); export const useAddAction = create((set: any) => ({ - addAction: null, - setAddAction: (x: any) => set({ addAction: x }), + addAction: null, + setAddAction: (x: any) => set({ addAction: x }), })); export const useActiveTool = create((set: any) => ({ - activeTool: "Cursor", - setActiveTool: (x: any) => set({ activeTool: x }), + activeTool: "Cursor", + setActiveTool: (x: any) => set({ activeTool: x }), })); export const use2DUndoRedo = create((set: any) => ({ - is2DUndoRedo: null, - set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }), -})) + is2DUndoRedo: null, + set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }), +})); export const useElevation = create((set: any) => ({ - elevation: 45, - setElevation: (x: any) => set({ elevation: x }), + elevation: 45, + setElevation: (x: any) => set({ elevation: x }), })); export const useAzimuth = create((set: any) => ({ - azimuth: -160, - setAzimuth: (x: any) => set({ azimuth: x }), + azimuth: -160, + setAzimuth: (x: any) => set({ azimuth: x }), })); export const useRenderDistance = create((set: any) => ({ - renderDistance: 50, - setRenderDistance: (x: any) => set({ renderDistance: x }), + renderDistance: 50, + setRenderDistance: (x: any) => set({ renderDistance: x }), })); export const useCamMode = create((set: any) => ({ - camMode: "ThirdPerson", - setCamMode: (x: any) => set({ camMode: x }), + camMode: "ThirdPerson", + setCamMode: (x: any) => set({ camMode: x }), })); export const useUserName = create((set: any) => ({ - userName: "", - setUserName: (x: any) => set({ userName: x }), + userName: "", + setUserName: (x: any) => set({ userName: x }), })); export const useObjectPosition = create((set: any) => ({ - objectPosition: { x: undefined, y: undefined, z: undefined }, - setObjectPosition: (newObjectPosition: any) => set({ objectPosition: newObjectPosition }), + objectPosition: { x: undefined, y: undefined, z: undefined }, + setObjectPosition: (newObjectPosition: any) => + set({ objectPosition: newObjectPosition }), })); export const useObjectScale = create((set: any) => ({ - objectScale: { x: undefined, y: undefined, z: undefined }, - setObjectScale: (newObjectScale: any) => set({ objectScale: newObjectScale }), + objectScale: { x: undefined, y: undefined, z: undefined }, + setObjectScale: (newObjectScale: any) => set({ objectScale: newObjectScale }), })); export const useObjectRotation = create((set: any) => ({ - objectRotation: { x: undefined, y: undefined, z: undefined }, - setObjectRotation: (newObjectRotation: any) => set({ objectRotation: newObjectRotation }), + objectRotation: { x: undefined, y: undefined, z: undefined }, + setObjectRotation: (newObjectRotation: any) => + set({ objectRotation: newObjectRotation }), })); export const useDrieTemp = create((set: any) => ({ - drieTemp: undefined, - setDrieTemp: (x: any) => set({ drieTemp: x }), + drieTemp: undefined, + setDrieTemp: (x: any) => set({ drieTemp: x }), })); export const useActiveUsers = create((set: any) => ({ - activeUsers: [], - setActiveUsers: (x: any) => set({ activeUsers: x }), + activeUsers: [], + setActiveUsers: (x: any) => set({ activeUsers: x }), })); export const useDrieUIValue = create((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 } })), - setTemperature: (value: any) => set((state: any) => ({ drieUIValue: { ...state.drieUIValue, temperature: value } })), - setHumidity: (value: any) => set((state: any) => ({ drieUIValue: { ...state.drieUIValue, humidity: value } })), + setTouch: (value: any) => + set((state: any) => ({ + 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((set: any) => ({ - drawMaterialPath: false, - setDrawMaterialPath: (x: any) => set({ drawMaterialPath: x }), + drawMaterialPath: false, + setDrawMaterialPath: (x: any) => set({ drawMaterialPath: x }), })); export const useSelectedActionSphere = create((set: any) => ({ - selectedActionSphere: undefined, - setSelectedActionSphere: (x: any) => set({ selectedActionSphere: x }), + selectedActionSphere: undefined, + setSelectedActionSphere: (x: any) => set({ selectedActionSphere: x }), })); export const useSelectedPath = create((set: any) => ({ - selectedPath: undefined, - setSelectedPath: (x: any) => set({ selectedPath: x }), + selectedPath: undefined, + setSelectedPath: (x: any) => set({ selectedPath: x }), })); interface Path { - modeluuid: string; - modelName: string; - points: { - uuid: string; - position: [number, number, number]; - rotation: [number, number, number]; - actions: { uuid: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | []; - triggers: { uuid: string; type: string; isUsed: boolean }[] | []; - }[]; - pathPosition: [number, number, number]; - pathRotation: [number, number, number]; - speed: number; + modeluuid: string; + modelName: string; + points: { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; + actions: + | { + uuid: string; + type: string; + material: string; + delay: number | string; + spawnInterval: number | string; + isUsed: boolean; + }[] + | []; + triggers: { uuid: string; type: string; isUsed: boolean }[] | []; + }[]; + pathPosition: [number, number, number]; + pathRotation: [number, number, number]; + speed: number; } interface SimulationPathsStore { - simulationPaths: Path[]; - setSimulationPaths: (paths: Path[]) => void; + simulationPaths: Path[]; + setSimulationPaths: (paths: Path[]) => void; } export const useSimulationPaths = create((set) => ({ - simulationPaths: [], - setSimulationPaths: (paths) => set({ simulationPaths: paths }), + simulationPaths: [], + setSimulationPaths: (paths) => set({ simulationPaths: paths }), })); - // interface Point { // uuid: string; // position: [number, number, number]; @@ -363,40 +383,75 @@ export const useSimulationPaths = create((set) => ({ // setSimulationPaths: (paths) => set({ simulationPaths: paths }), // })); - export const useConnections = create((set) => ({ - connections: [], + connections: [], - setConnections: (connections) => set({ connections }), + setConnections: (connections) => set({ connections }), - addConnection: (newConnection) => - set((state) => ({ - connections: [...state.connections, newConnection], - })), + addConnection: (newConnection) => + set((state) => ({ + connections: [...state.connections, newConnection], + })), - removeConnection: (fromUUID, toUUID) => - set((state) => ({ - connections: state.connections - .map((connection) => - connection.fromUUID === fromUUID - ? { - ...connection, - toConnections: connection.toConnections.filter( - (to) => to.toUUID !== toUUID - ), - } - : connection - ) - .filter((connection) => connection.toConnections.length > 0), - })), + removeConnection: (fromUUID, toUUID) => + set((state) => ({ + connections: state.connections + .map((connection) => + connection.fromUUID === fromUUID + ? { + ...connection, + toConnections: connection.toConnections.filter( + (to) => to.toUUID !== toUUID + ), + } + : connection + ) + .filter((connection) => connection.toConnections.length > 0), + })), })); export const useIsConnecting = create((set: any) => ({ - isConnecting: false, - setIsConnecting: (x: any) => set({ isConnecting: x }), + isConnecting: false, + setIsConnecting: (x: any) => set({ isConnecting: x }), })); export const useStartSimulation = create((set: any) => ({ - startSimulation: false, - setStartSimulation: (x: any) => set({ startSimulation: x }), -})); \ No newline at end of file + startSimulation: false, + setStartSimulation: (x: any) => set({ startSimulation: x }), +})); +export const usezoneTarget = create((set: any) => ({ + zoneTarget: [], + setZoneTarget: (x: any) => set({ zoneTarget: x }), +})); +export const usezonePosition = create((set: any) => ({ + zonePosition: [], + setZonePosition: (x: any) => set({ zonePosition: x }), +})); + + +interface EditPositionState { + Edit: boolean; + setEdit: (value: boolean) => void; + } + + export const useEditPosition = create((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((set) => ({ + objects: [], + addObject: (obj) => set((state) => ({ objects: [...state.objects, obj] })), + })); \ No newline at end of file diff --git a/app/src/store/useChartStore.ts b/app/src/store/useChartStore.ts new file mode 100644 index 0000000..ee9da29 --- /dev/null +++ b/app/src/store/useChartStore.ts @@ -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((set) => ({ + measurements: [], + interval: 1000, + duration: "1h", + + setMeasurements: (newMeasurements) => + set(() => ({ measurements: newMeasurements })), + + updateDuration: (newDuration) => + set(() => ({ duration: newDuration })), +})); + +export default useChartStore; diff --git a/app/src/store/useZoneStore.ts b/app/src/store/useZoneStore.ts index e0a66f0..007a1c6 100644 --- a/app/src/store/useZoneStore.ts +++ b/app/src/store/useZoneStore.ts @@ -15,21 +15,31 @@ interface SelectedZoneState { activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[]; widgets: Widget[]; } interface SelectedZoneStore { selectedZone: SelectedZoneState; - setSelectedZone: (zone: Partial | ((prev: SelectedZoneState) => SelectedZoneState)) => void; + setSelectedZone: ( + zone: + | Partial + | ((prev: SelectedZoneState) => SelectedZoneState) + ) => void; } export const useSelectedZoneStore = create((set) => ({ selectedZone: { - zoneName: "", - activeSides: [], - panelOrder: [], - lockedPanels: [], - widgets: [], + zoneName: "", // Empty string initially + activeSides: [], // Empty array + panelOrder: [], // Empty array + lockedPanels: [], // Empty array + zoneId: "", + zoneViewPortTarget: [], + zoneViewPortPosition: [], + widgets: [], // Empty array }, setSelectedZone: (zone) => set((state) => ({ @@ -38,4 +48,4 @@ export const useSelectedZoneStore = create((set) => ({ ? zone(state.selectedZone) // Handle functional updates : { ...state.selectedZone, ...zone }, // Handle partial updates })), -})); \ No newline at end of file +})); diff --git a/app/src/styles/components/marketPlace/marketPlace.scss b/app/src/styles/components/marketPlace/marketPlace.scss index 3d2f647..2ae2790 100644 --- a/app/src/styles/components/marketPlace/marketPlace.scss +++ b/app/src/styles/components/marketPlace/marketPlace.scss @@ -184,4 +184,4 @@ } } } -} \ No newline at end of file +} diff --git a/app/src/styles/components/tools.scss b/app/src/styles/components/tools.scss index cda735a..cb65697 100644 --- a/app/src/styles/components/tools.scss +++ b/app/src/styles/components/tools.scss @@ -161,25 +161,49 @@ width: 30px; height: 30px; border-radius: 50%; - background-color: var(--accent-color); - + background-color: var(--highlight-accent-color); cursor: pointer; @include flex-center; position: fixed; bottom: 60px; left: 50%; transform: translate(-50%, 0); - transition: background-color 0.3s, transform 0.3s; - color: var(--background-color); - // transform: none; + color: var(--accent-color); z-index: 100; - + isolation: isolate; + font-weight: 700; &:hover { + font-weight: 500; 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 { from { diff --git a/compose.yaml b/compose.yaml index 2b5e419..33328bc 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,24 +1,24 @@ -services: - frontend: - build: - context: ./app - dockerfile: Dockerfile - args: - - REACT_APP_SERVER_SOCKET_API_BASE_URL=185.100.212.76:8000 - - REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000 - - REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011 - container_name: dwinzo-beta - stdin_open: true - tty: true - ports: - - "8200:3000" - environment: - - WDS_SOCKET_PORT=0 - - PORT=3000 - - DOCSIFY_PORT=8201 - volumes: - - ./app:/app - -volumes: - frontend: - driver: local +services: + frontend: + build: + context: ./app + dockerfile: Dockerfile + args: + - REACT_APP_SERVER_SOCKET_API_BASE_URL=185.100.212.76:8000 + - REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000 + - REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011 + container_name: dwinzo-beta + stdin_open: true + tty: true + ports: + - "8200:3000" + environment: + - WDS_SOCKET_PORT=0 + - PORT=3000 + - DOCSIFY_PORT=8201 + volumes: + - ./app:/app + +volumes: + frontend: + driver: local