From d7f1c5224df36f0e705d747d5832449230ab78c5 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Thu, 24 Apr 2025 14:05:55 +0530 Subject: [PATCH 01/30] feat: Refactor icon components and update button elements for improved accessibility and consistency --- app/src/components/icons/ContextMenuIcons.tsx | 78 ++++++++++--------- .../components/icons/ExportCommonIcons.tsx | 14 ---- .../layout/Dashboard/MarketPlaceBanner.tsx | 12 +-- .../layout/Dashboard/SidePannel.tsx | 2 +- .../confirmationPopup/ConfirmationPopup.tsx | 8 +- .../visualization/widgets/ChartComponent.tsx | 4 +- .../visualization/widgets/Widgets.tsx | 2 - .../visualization/widgets/WidgetsFloating.tsx | 31 -------- .../eventProperties/EventProperties.tsx | 8 +- .../eventProperties/actions/DespawnAction.tsx | 24 +++--- .../eventProperties/actions/SwapAction.tsx | 6 +- .../eventProperties/trigger/Trigger.tsx | 10 +-- app/src/components/ui/list/List.tsx | 6 +- app/src/modules/scene/scene.tsx | 45 ++++++----- .../visualization/RealTimeVisulization.tsx | 34 ++++---- .../modules/visualization/visualization.tsx | 3 +- app/src/styles/base/reset.scss | 7 ++ app/src/styles/layout/sidebar.scss | 3 +- 18 files changed, 125 insertions(+), 172 deletions(-) diff --git a/app/src/components/icons/ContextMenuIcons.tsx b/app/src/components/icons/ContextMenuIcons.tsx index a1ced1b..217ad8f 100644 --- a/app/src/components/icons/ContextMenuIcons.tsx +++ b/app/src/components/icons/ContextMenuIcons.tsx @@ -42,44 +42,46 @@ export function FlipXAxisIcon() { } export function FlipYAxisIcon() { - - - - - - - ; + return ( + + + + + + + + ); } export function FlipZAxisIcon() { return ( diff --git a/app/src/components/icons/ExportCommonIcons.tsx b/app/src/components/icons/ExportCommonIcons.tsx index 6e73c0e..fcf7202 100644 --- a/app/src/components/icons/ExportCommonIcons.tsx +++ b/app/src/components/icons/ExportCommonIcons.tsx @@ -168,20 +168,6 @@ export function AddIcon() { ); } -export function RmoveIcon() { - return ( - - - - ); -} - export function CloseIcon() { return ( { diff --git a/app/src/components/layout/Dashboard/SidePannel.tsx b/app/src/components/layout/Dashboard/SidePannel.tsx index d44c72c..5d69ffc 100644 --- a/app/src/components/layout/Dashboard/SidePannel.tsx +++ b/app/src/components/layout/Dashboard/SidePannel.tsx @@ -11,7 +11,7 @@ import { import { SettingsIcon, TrashIcon } from "../../icons/ExportCommonIcons"; const SidePannel: React.FC = () => { - const userName = localStorage.getItem("userName") || "Anonymous"; + const userName = localStorage.getItem("userName") ?? "Anonymous"; return (
diff --git a/app/src/components/layout/confirmationPopup/ConfirmationPopup.tsx b/app/src/components/layout/confirmationPopup/ConfirmationPopup.tsx index 078f27d..4774bad 100644 --- a/app/src/components/layout/confirmationPopup/ConfirmationPopup.tsx +++ b/app/src/components/layout/confirmationPopup/ConfirmationPopup.tsx @@ -17,12 +17,12 @@ const ConfirmationPopup: React.FC = ({

{message}

-
+
-
+ +
+
diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/ChartComponent.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/ChartComponent.tsx index 9d09291..0e10cf1 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/ChartComponent.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/ChartComponent.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useRef, useMemo } from "react"; import { Chart } from "chart.js/auto"; -// import { useThemeStore } from "../../../../../store/useThemeStore"; // Define Props Interface interface ChartComponentProps { @@ -29,7 +28,6 @@ const ChartComponent = ({ data: propsData, }: ChartComponentProps) => { const canvasRef = useRef(null); - // const { themeColor } = useThemeStore(); // Memoize Theme Colors to Prevent Unnecessary Recalculations // const buttonActionColor = useMemo( @@ -66,7 +64,7 @@ const ChartComponent = ({ // Memoize Chart Font Style const chartFontStyle = useMemo( () => ({ - family: fontFamily || "Arial", + family: fontFamily ?? "Arial", size: fontSizeValue, weight: fontWeightValue, color: "#2B3344", diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets.tsx index d4a64ae..655e641 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets.tsx @@ -1,4 +1,3 @@ -import { useState } from "react"; import ToggleHeader from "../../../../ui/inputs/ToggleHeader"; import Widgets2D from "./Widgets2D"; import Widgets3D from "./Widgets3D"; @@ -6,7 +5,6 @@ import WidgetsFloating from "./WidgetsFloating"; import { useWidgetSubOption } from "../../../../../store/store"; const Widgets = () => { - const [activeOption, setActiveOption] = useState("2D"); const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); const handleToggleClick = (option: string) => { diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx index 50d9712..dfe70d7 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx @@ -8,42 +8,11 @@ import { import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard"; import WarehouseThroughput from "../../../../../modules//visualization/widgets/floating/cards/WarehouseThroughput"; -import ProductivityDashboard from "../../../../../modules//visualization/widgets/floating/cards/ProductivityDashboard"; import FleetEfficiency from "../../../../../modules//visualization/widgets/floating/cards/FleetEfficiency"; -interface Widget { - id: string; - name: string; -} - const WidgetsFloating = () => { - // const [widgets, setWidgets] = useState([ - // { id: "1", name: "Working State Widget" }, - // { id: "2", name: "Floating Widget 2" }, - // { id: "3", name: "Floating Widget 3" }, - // { id: "4", name: "Floating Widget 4" }, - // ]); - - // Function to handle drag start - const handleDragStart = ( - e: React.DragEvent, - widget: Widget - ) => { - e.dataTransfer.setData("application/json", JSON.stringify(widget)); - }; - return (
- {/* {widgets.map((widget) => ( -
handleDragStart(e, widget)} - > - {widget.name} -
- ))} */} {/* Floating 1 */} = ({ const actionsContainerRef = useRef(null); const [activeOption, setActiveOption] = useState("default"); - const [dummyactiveOption, setTypeOption] = useState("default"); const getAvailableActions = () => { if (assetType === "conveyor") { @@ -136,9 +135,9 @@ const EventProperties: React.FC = ({
Actions
-
{}}> +
+
= ({ {activeOption === "swap" && } {/* done */} {activeOption === "despawn" && } {/* done */} {activeOption === "travel" && } {/* done */} - {activeOption === "pickAndPlace" && } {/* done */} + {activeOption === "pickAndPlace" && }{" "} + {/* done */} {activeOption === "process" && } {/* done */} {activeOption === "store" && } {/* done */}
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx index a0f081f..4116add 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DespawnAction.tsx @@ -3,19 +3,17 @@ import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; const DespawnAction: React.FC = () => { return ( - <> - {}} - onChange={(value) => console.log(value)} - /> - + {}} + onChange={(value) => console.log(value)} + /> ); }; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx index 2e18d80..eb8e483 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx @@ -2,11 +2,7 @@ import React from "react"; import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload"; const SwapAction: React.FC = () => { - return ( - <> - - - ); + return ; }; export default SwapAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx index f287b63..f87a852 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx @@ -35,27 +35,27 @@ const Trigger: React.FC = () => {
Trigger
-
Add -
+
{/* Map over triggers and render them */} {triggers.map((trigger, index) => ( -
+
{trigger} -
removeTrigger(index)} style={{ cursor: "pointer" }} > -
+
= ({ items = [], remove }) => {
{remove && (
- +
)} {item.assets && item.assets.length > 0 && ( @@ -221,7 +221,7 @@ const List: React.FC = ({ items = [], remove }) => {
{remove && (
- +
)}
diff --git a/app/src/modules/scene/scene.tsx b/app/src/modules/scene/scene.tsx index 6564032..0f2c489 100644 --- a/app/src/modules/scene/scene.tsx +++ b/app/src/modules/scene/scene.tsx @@ -9,28 +9,35 @@ import Simulation from "../simulation/simulation"; import Collaboration from "../collaboration/collaboration"; export default function Scene() { - const map = useMemo(() => [ - { name: "forward", keys: ["ArrowUp", "w", "W"] }, - { name: "backward", keys: ["ArrowDown", "s", "S"] }, - { name: "left", keys: ["ArrowLeft", "a", "A"] }, - { name: "right", keys: ["ArrowRight", "d", "D"] },], - []); + const map = useMemo( + () => [ + { name: "forward", keys: ["ArrowUp", "w", "W"] }, + { name: "backward", keys: ["ArrowDown", "s", "S"] }, + { name: "left", keys: ["ArrowLeft", "a", "A"] }, + { name: "right", keys: ["ArrowRight", "d", "D"] }, + ], + [] + ); - return ( - - { e.preventDefault(); }}> + return ( + + { + e.preventDefault(); + }} + > + - + - + - + - - - - - - - ); + + + + ); } diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index cd2c57c..44c6717 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -12,15 +12,12 @@ import { useFloatingWidget, } from "../../store/visualization/useDroppedObjectsStore"; import { - useAsset3dWidget, useSocketStore, useWidgetSubOption, - useZones, } from "../../store/store"; import { getZone2dData } from "../../services/visulization/zone/getZoneData"; import { generateUniqueId } from "../../functions/generateUniqueId"; import { determinePosition } from "./functions/determinePosition"; -import { addingFloatingWidgets } from "../../services/visulization/zone/addFloatingWidgets"; import SocketRealTimeViz from "./socket/realTimeVizSocket.dev"; import RenderOverlay from "../../components/templates/Overlay"; import ConfirmationPopup from "../../components/layout/confirmationPopup/ConfirmationPopup"; @@ -68,20 +65,15 @@ const RealTimeVisulization: React.FC = () => { const containerRef = useRef(null); const { isPlaying } = usePlayButtonStore(); const { activeModule } = useModuleStore(); - const [droppedObjects, setDroppedObjects] = useState([]); const [zonesData, setZonesData] = useState({}); const { selectedZone, setSelectedZone } = useSelectedZoneStore(); - const { rightSelect, setRightSelect } = useRightSelected(); - const { editWidgetOptions, setEditWidgetOptions } = - useEditWidgetOptionsStore(); + const { setRightSelect } = useRightSelected(); + const { editWidgetOptions } = useEditWidgetOptionsStore(); const { rightClickSelected, setRightClickSelected } = useRightClickSelected(); const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false); - - // const [floatingWidgets, setFloatingWidgets] = useState>({}); - const { floatingWidget, setFloatingWidget } = useFloatingWidget(); - const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); - const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); + const { setFloatingWidget } = useFloatingWidget(); + const { widgetSubOption } = useWidgetSubOption(); const { visualizationSocket } = useSocketStore(); const { setSelectedChartId } = useWidgetStore(); @@ -99,11 +91,10 @@ const RealTimeVisulization: React.FC = () => { useEffect(() => { async function GetZoneData() { - const email = localStorage.getItem("email") || ""; + const email = localStorage.getItem("email") ?? ""; const organization = email?.split("@")[1]?.split(".")[0]; try { const response = await getZone2dData(organization); - // console.log('response: ', response); if (!Array.isArray(response)) { return; @@ -125,7 +116,9 @@ const RealTimeVisulization: React.FC = () => { {} ); setZonesData(formattedData); - } catch (error) {} + } catch (error) { + console.log(error); + } } GetZoneData(); @@ -151,12 +144,10 @@ const RealTimeVisulization: React.FC = () => { }); }, [selectedZone]); - // useEffect(() => {}, [floatingWidgets]); - const handleDrop = async (event: React.DragEvent) => { event.preventDefault(); try { - const email = localStorage.getItem("email") || ""; + const email = localStorage.getItem("email") ?? ""; const organization = email?.split("@")[1]?.split(".")[0]; const data = event.dataTransfer.getData("text/plain"); @@ -172,8 +163,8 @@ const RealTimeVisulization: React.FC = () => { const relativeY = event.clientY - rect.top; // Widget dimensions - const widgetWidth = droppedData.width || 125; - const widgetHeight = droppedData.height || 100; + const widgetWidth = droppedData.width ?? 125; + const widgetHeight = droppedData.height ?? 100; // Center the widget at cursor const centerOffsetX = widgetWidth / 2; @@ -275,7 +266,7 @@ const RealTimeVisulization: React.FC = () => { return () => { document.removeEventListener("mousedown", handleClickOutside); }; - }, [setRightClickSelected]); + }, [setRightClickSelected, setRightSelect]); const [canvasDimensions, setCanvasDimensions] = useState({ width: 0, @@ -340,6 +331,7 @@ const RealTimeVisulization: React.FC = () => { borderRadius: isPlaying || activeModule !== "visualization" ? "" : "6px", }} + role="application" onDrop={(event) => handleDrop(event)} onDragOver={(event) => event.preventDefault()} > diff --git a/app/src/modules/visualization/visualization.tsx b/app/src/modules/visualization/visualization.tsx index e5b1692..77956f4 100644 --- a/app/src/modules/visualization/visualization.tsx +++ b/app/src/modules/visualization/visualization.tsx @@ -3,9 +3,8 @@ import Dropped3dWidgets from './widgets/3d/Dropped3dWidget' import ZoneCentreTarget from './zone/zoneCameraTarget' import ZoneAssets from './zone/zoneAssets' import MqttEvents from '../../services/factoryBuilder/mqtt/mqttEvents' -import DrieHtmlTemp from './mqttTemp/drieHtmlTemp' -const Visualization = () => { +const Visualization:React.FC = () => { return ( <> diff --git a/app/src/styles/base/reset.scss b/app/src/styles/base/reset.scss index 82d286e..ab77f9a 100644 --- a/app/src/styles/base/reset.scss +++ b/app/src/styles/base/reset.scss @@ -12,3 +12,10 @@ input[type="password"]::-webkit-clear-button, /* For Chrome/Safari clear button input[type="password"]::-webkit-inner-spin-button { /* Just in case */ display: none; } + +button{ + border: none; + outline: none; + background: none; + cursor: pointer; +} \ No newline at end of file diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index cab078e..76d2933 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -675,7 +675,8 @@ color: var(--primary-color); border-radius: #{$border-radius-small}; cursor: pointer; - + outline: none; + border: none; path { stroke: var(--primary-color); } From 2dc076e9c22ea6767665431b98b58c002e149df5 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Thu, 24 Apr 2025 15:43:38 +0530 Subject: [PATCH 02/30] feat: Remove unused placeholders styles and add global section styles --- app/src/styles/abstracts/placeholders.scss | 6 - app/src/styles/abstracts/variables.scss | 229 ++++++++++++--------- app/src/styles/base/global.scss | 3 + app/src/styles/main.scss | 2 +- 4 files changed, 130 insertions(+), 110 deletions(-) delete mode 100644 app/src/styles/abstracts/placeholders.scss create mode 100644 app/src/styles/base/global.scss diff --git a/app/src/styles/abstracts/placeholders.scss b/app/src/styles/abstracts/placeholders.scss deleted file mode 100644 index 18f28f9..0000000 --- a/app/src/styles/abstracts/placeholders.scss +++ /dev/null @@ -1,6 +0,0 @@ -// center a element -%centered { - display: flex; - justify-content: center; - align-items: center; -} diff --git a/app/src/styles/abstracts/variables.scss b/app/src/styles/abstracts/variables.scss index 44e5627..24fe99a 100644 --- a/app/src/styles/abstracts/variables.scss +++ b/app/src/styles/abstracts/variables.scss @@ -1,123 +1,146 @@ -/* ======================================================================== - Global SCSS Variables - ======================================================================== - This file contains the global variables used across the project for - colors, typography, spacing, shadows, and other design tokens. - ======================================================================== */ - @use "functions"; -// ======================================================================== -// Font Imports -// ======================================================================== @import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Josefin+Sans:ital,wght@0,100..700;1,100..700&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100..900;1,100..900&display=swap"); -// ======================================================================== -// Colors -// ======================================================================== +// new variables -// Text colors -$text-color: #2b3344; // Primary text color -$text-disabled: #b7b7c6; // Disabled text color -$input-text-color: #595965; // Input field text color +// text colors +// ---------- light mode ---------- -$text-color-dark: #f3f3fd; // Primary text color for dark mode -$text-disabled-dark: #6f6f7a; // Disabled text color for dark mode -$input-text-color-dark: #b5b5c8; // Input field text color for dark mode +// $text-color: #2b3344; +// $text-disabled: #b7b7c6; +// $input-text-color: #595965; +// $highlight-text-color: #6f42c1; -// Accent colors -$accent-color: #6f42c1; // Primary accent color -$accent-color-dark: #c4abf1; // Primary accent color for dark mode -$highlight-accent-color: #e0dfff; // Highlighted accent for light mode -$highlight-accent-color-dark: #403e6a; // Highlighted accent for dark mode +// ---------- dark mode ---------- -// Background colors -$background-color: #fcfdfd; // Main background color -$background-color-dark: #19191d; // Main background color for dark mode -$background-color-secondary: #e1e0ff80; // Secondary background color -$background-color-secondary-dark: #39394f99; // Secondary background color for dark mode -$background-color-gray: #f3f3f3; // Main background color -$background-color-gray-dark: #232323; // Main background color for dark mode +// $text-color-dark: #f3f3fd; +// $text-disabled-dark: #6f6f7a; +// $input-text-color-dark: #b5b5c8; +// $highlight-text-color-dark: #B392F0; -// Border colors -$border-color: #e0dfff; // Default border color -$border-color-dark: #403e6a; // Border color for dark mode +// background colors +// ---------- light mode ---------- -// Shadow color -$shadow-color: #3c3c431a; // Shadow base color for light and dark mode -$shadow-color-dark: #8f8f8f1a; // Shadow base color for light and dark mode +// $background-color: linear-gradient(-45deg, #FCFDFDCC 0%, #FCFDFD99 100%); +// $background-color-secondary: #FCFDFD4D; +// $background-color-accent: #6f42c1; +// $background-color-button: #6f42c1; +// $background-color-drop-down: #6F42C14D; +// $background-color-input: #FFFFFF4D; +// $background-color-input-focus: #F2F2F7; +// $background-color-drop-down-gradient: linear-gradient(-45deg, #75649366 0%, #40257266 100%); +// $background-color-selected: #E0DFFF; +// $background-radial-gray-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%); -// Gradients -$acent-gradient-dark: linear-gradient( - 90deg, - #b392f0 0%, - #a676ff 100% -); // Dark mode accent gradient -$acent-gradient: linear-gradient( - 90deg, - #6f42c1 0%, - #925df3 100% -); // Light mode accent gradient +// ---------- dark mode ---------- + +// $background-color-dark: linear-gradient(-45deg, #333333B3 0%, #2D2437B3 100%); +// $background-color-secondary-dark: #19191D99; +// $background-color-accent-dark: #6f42c1; +// $background-color-button-dark: #6f42c1; +// $background-color-drop-down-dark: #50505080; +// $background-color-input-dark: #FFFFFF33; +// $background-color-input-focus-dark: #333333; +// $background-color-drop-down-gradient-dark: linear-gradient(-45deg, #8973B166 0%, #53427366 100%); +// $background-color-selected-dark: #403E66; +// $background-radial-gray-gradient-dark: radial-gradient(circle, #31373b 0%, #48494b 46%, #52415c 100%); + +// border colors +// ---------- light mode ---------- + +// $border-color: #E0DFFF; +// $border-color-accent: #6F42C1; + +// ---------- dark mode ---------- +// $border-color-dark: #564B69; +// $border-color-accent-dark: #6F42C1; + +// highlight colors +// ---------- light mode ---------- + +// $highlight-accent-color: #e0dfff; +// $highlight-secondary-color: #c4abf1; + +// ---------- dark mode ---------- +// $highlight-accent-color-dark: #403e6a; +// $highlight-secondary-color-dark: #c4abf1; + +// colors +// $color1: #A392CD; +// $color2: #7b4cd3; +// $color3: #B186FF; +// $color4: #8752E8; +// $color5: #C7A8FF; + + +// old variables +$text-color: #2b3344; +$text-disabled: #b7b7c6; +$input-text-color: #595965; + +$text-color-dark: #f3f3fd; +$text-disabled-dark: #6f6f7a; +$input-text-color-dark: #b5b5c8; + +$accent-color: #6f42c1; +$accent-color-dark: #c4abf1; +$highlight-accent-color: #e0dfff; +$highlight-accent-color-dark: #403e6a; + +$background-color: #fcfdfd; +$background-color-dark: #19191d; +$background-color-secondary: #e1e0ff80; +$background-color-secondary-dark: #39394f99; +$background-color-gray: #f3f3f3; +$background-color-gray-dark: #232323; + +$border-color: #e0dfff; +$border-color-dark: #403e6a; + +$shadow-color: #3c3c431a; +$shadow-color-dark: #8f8f8f1a; + +$acent-gradient-dark: linear-gradient(90deg, #b392f0 0%, #a676ff 100%); +$acent-gradient: linear-gradient(90deg, #6f42c1 0%, #925df3 100%); $faint-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%); $faint-gradient-dark: radial-gradient(circle, #31373b 0%, #48494b 46%, #52415c 100%); -// ======================================================================== -// Typography -// ======================================================================== +$font-inter: "Inter", sans-serif; +$font-josefin-sans: "Josefin Sans", sans-serif; +$font-poppins: "Poppins", sans-serif; +$font-roboto: "Roboto", sans-serif; -// Font Family Variables -$font-inter: "Inter", sans-serif; // Inter font -$font-josefin-sans: "Josefin Sans", sans-serif; // Josefin Sans font -$font-poppins: "Poppins", sans-serif; // Poppins font -$font-roboto: "Roboto", sans-serif; // Roboto font +$tiny: 0.625rem; +$small: 0.75rem; +$regular: 0.8rem; +$large: 1rem; +$xlarge: 1.125rem; +$xxlarge: 1.5rem; +$xxxlarge: 2rem; -// Font sizes (converted to rem using a utility function) -$tiny: 0.625rem; // Extra small text (10px) -$small: 0.75rem; // Small text (12px) -$regular: 0.8rem; // Default text size (14px) -$large: 1rem; // Large text size (16px) -$xlarge: 1.125rem; // Extra large text size (18px) -$xxlarge: 1.5rem; // Double extra large text size (24px) -$xxxlarge: 2rem; // Triple extra large text size (32px) +$thin-weight: 300; +$regular-weight: 400; +$medium-weight: 500; +$bold-weight: 600; -// Font weights -$thin-weight: 300; // Regular font weight -$regular-weight: 400; // Regular font weight -$medium-weight: 500; // Medium font weight -$bold-weight: 600; // Bold font weight +$z-index-drei-html: 1; +$z-index-default: 1; +$z-index-marketplace: 2; +$z-index-tools: 3; +$z-index-negative: -1; +$z-index-ui-base: 10; +$z-index-ui-overlay: 20; +$z-index-ui-popup: 30; +$z-index-ui-highest: 50; -// ======================================================================== -// Z-Index Levels -// ======================================================================== +$box-shadow-light: 0px 2px 4px $shadow-color; +$box-shadow-medium: 0px 4px 8px $shadow-color; +$box-shadow-heavy: 0px 8px 16px $shadow-color; -// Z-index variables for layering -$z-index-drei-html: 1; // For drei's Html components -$z-index-default: 1; // For drei's Html components -$z-index-marketplace: 2; // For drei's Html components -$z-index-tools: 3; // For drei's Html components -$z-index-negative: -1; // For drei's Html components -$z-index-ui-base: 10; // Base UI elements -$z-index-ui-overlay: 20; // Overlay UI elements (e.g., modals, tooltips) -$z-index-ui-popup: 30; // Popups, dialogs, or higher-priority UI elements -$z-index-ui-highest: 50; // Highest priority elements (e.g., notifications, loading screens) - -// ======================================================================== -// Shadows -// ======================================================================== - -// Box shadow variables -$box-shadow-light: 0px 2px 4px $shadow-color; // Light shadow -$box-shadow-medium: 0px 4px 8px $shadow-color; // Medium shadow -$box-shadow-heavy: 0px 8px 16px $shadow-color; // Heavy shadow - -// ======================================================================== -// Border Radius -// ======================================================================== - -// Border radius variables -$border-radius-small: 4px; // Small rounded corners -$border-radius-medium: 6px; // Medium rounded corners -$border-radius-large: 12px; // Large rounded corners -$border-radius-circle: 50%; // Fully circular -$border-radius-extra-large: 20px; // Extra-large rounded corners +$border-radius-small: 4px; +$border-radius-medium: 6px; +$border-radius-large: 12px; +$border-radius-circle: 50%; +$border-radius-extra-large: 20px; diff --git a/app/src/styles/base/global.scss b/app/src/styles/base/global.scss new file mode 100644 index 0000000..9b4e1e8 --- /dev/null +++ b/app/src/styles/base/global.scss @@ -0,0 +1,3 @@ +section{ + +} \ No newline at end of file diff --git a/app/src/styles/main.scss b/app/src/styles/main.scss index 5e46dd4..fe77adb 100644 --- a/app/src/styles/main.scss +++ b/app/src/styles/main.scss @@ -1,12 +1,12 @@ // abstracts @use 'abstracts/variables'; @use 'abstracts/mixins'; -@use 'abstracts/placeholders'; @use 'abstracts/functions'; // base @use 'base/reset'; @use 'base/typography'; +@use 'base/global'; @use 'base/base'; // components From e64840a4e77fe379dc59bc44d85b85b9a1f90504 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Mon, 28 Apr 2025 09:25:51 +0530 Subject: [PATCH 03/30] feat: Update logo component and refactor UserAuth for improved readability and consistency --- app/src/components/icons/Logo.tsx | 1 - app/src/pages/UserAuth.tsx | 218 ++++++++++++------------ app/src/styles/abstracts/variables.scss | 124 ++++++-------- app/src/styles/base/global.scss | 8 +- 4 files changed, 170 insertions(+), 181 deletions(-) diff --git a/app/src/components/icons/Logo.tsx b/app/src/components/icons/Logo.tsx index 06ed750..d15398c 100644 --- a/app/src/components/icons/Logo.tsx +++ b/app/src/components/icons/Logo.tsx @@ -124,7 +124,6 @@ export function LogoIconLarge() { fill="none" xmlns="http://www.w3.org/2000/svg" > - { const handleLogin = async (e: FormEvent) => { e.preventDefault(); - const organization = (email.split("@")[1]).split(".")[0]; + const organization = email.split("@")[1].split(".")[0]; try { const res = await signInApi(email, password, organization); @@ -39,7 +43,7 @@ const UserAuth: React.FC = () => { } else if (res.message === "User Not Found!!! Kindly signup...") { setError("Account not found"); } - } catch (error) { } + } catch (error) {} }; const handleRegister = async (e: FormEvent) => { @@ -47,7 +51,7 @@ const UserAuth: React.FC = () => { if (email && password && userName) { setError(""); try { - const organization = (email.split("@")[1]).split(".")[0]; + const organization = email.split("@")[1].split(".")[0]; const res = await signUpApi(userName, email, password, organization); if (res.message === "New User created") { @@ -56,123 +60,121 @@ const UserAuth: React.FC = () => { if (res.message === "User already exists") { setError("User already exists"); } - } catch (error) { } + } catch (error) {} } else { setError("Please fill all the fields!"); } }; return ( - <> -
-
- -
-

Welcome to Dwinzo

-

- {isSignIn ? ( - <> - Don’t have an account?{" "} - setIsSignIn(false)} - style={{ cursor: "pointer" }} - > - Register here! - - - ) : ( - <> - Already have an account?{" "} - setIsSignIn(true)} - style={{ cursor: "pointer" }} - > - Login here! - - - )} -

+
+
+ +
+

Welcome to Dwinzo

+

+ {isSignIn ? ( + <> + Don’t have an account?{" "} + setIsSignIn(false)} + style={{ cursor: "pointer" }} + > + Register here! + + + ) : ( + <> + Already have an account?{" "} + setIsSignIn(true)} + style={{ cursor: "pointer" }} + > + Login here! + + + )} +

- + - {error &&
🛈 {error}
} + {error &&
🛈 {error}
} -
- {!isSignIn && ( - setUserName(e.target.value)} - required - /> - )} + + {!isSignIn && ( setEmail(e.target.value)} + type="text" + value={userName} + placeholder="Username" + onChange={(e) => setUserName(e.target.value)} required /> -
- setPassword(e.target.value)} - required - /> - -
- {!isSignIn && ( -
- -
- I have read and agree to the terms of service -
-
- )} - -
-

- By signing up for, or logging into, an account, you agree to our{" "} - navigate("/privacy")} - style={{ cursor: "pointer" }} - > - privacy policy - {" "} - &{" "} - navigate("/terms")} - style={{ cursor: "pointer" }} - > - terms of service - {" "} - whether you read them or not. You can also find these terms on our - website. -

-
- +
+ {!isSignIn && ( +
+ +
+ I have read and agree to the terms of service +
+
+ )} + + +

+ By signing up for, or logging into, an account, you agree to our{" "} + navigate("/privacy")} + style={{ cursor: "pointer" }} + > + privacy policy + {" "} + &{" "} + navigate("/terms")} + style={{ cursor: "pointer" }} + > + terms of service + {" "} + whether you read them or not. You can also find these terms on our + website. +

+
); }; diff --git a/app/src/styles/abstracts/variables.scss b/app/src/styles/abstracts/variables.scss index 24fe99a..6bb3d57 100644 --- a/app/src/styles/abstracts/variables.scss +++ b/app/src/styles/abstracts/variables.scss @@ -6,83 +6,69 @@ // text colors // ---------- light mode ---------- - -// $text-color: #2b3344; -// $text-disabled: #b7b7c6; -// $input-text-color: #595965; -// $highlight-text-color: #6f42c1; - -// ---------- dark mode ---------- - -// $text-color-dark: #f3f3fd; -// $text-disabled-dark: #6f6f7a; -// $input-text-color-dark: #b5b5c8; -// $highlight-text-color-dark: #B392F0; - -// background colors -// ---------- light mode ---------- - -// $background-color: linear-gradient(-45deg, #FCFDFDCC 0%, #FCFDFD99 100%); -// $background-color-secondary: #FCFDFD4D; -// $background-color-accent: #6f42c1; -// $background-color-button: #6f42c1; -// $background-color-drop-down: #6F42C14D; -// $background-color-input: #FFFFFF4D; -// $background-color-input-focus: #F2F2F7; -// $background-color-drop-down-gradient: linear-gradient(-45deg, #75649366 0%, #40257266 100%); -// $background-color-selected: #E0DFFF; -// $background-radial-gray-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%); - -// ---------- dark mode ---------- - -// $background-color-dark: linear-gradient(-45deg, #333333B3 0%, #2D2437B3 100%); -// $background-color-secondary-dark: #19191D99; -// $background-color-accent-dark: #6f42c1; -// $background-color-button-dark: #6f42c1; -// $background-color-drop-down-dark: #50505080; -// $background-color-input-dark: #FFFFFF33; -// $background-color-input-focus-dark: #333333; -// $background-color-drop-down-gradient-dark: linear-gradient(-45deg, #8973B166 0%, #53427366 100%); -// $background-color-selected-dark: #403E66; -// $background-radial-gray-gradient-dark: radial-gradient(circle, #31373b 0%, #48494b 46%, #52415c 100%); - -// border colors -// ---------- light mode ---------- - -// $border-color: #E0DFFF; -// $border-color-accent: #6F42C1; - -// ---------- dark mode ---------- -// $border-color-dark: #564B69; -// $border-color-accent-dark: #6F42C1; - -// highlight colors -// ---------- light mode ---------- - -// $highlight-accent-color: #e0dfff; -// $highlight-secondary-color: #c4abf1; - -// ---------- dark mode ---------- -// $highlight-accent-color-dark: #403e6a; -// $highlight-secondary-color-dark: #c4abf1; - -// colors -// $color1: #A392CD; -// $color2: #7b4cd3; -// $color3: #B186FF; -// $color4: #8752E8; -// $color5: #C7A8FF; - - -// old variables $text-color: #2b3344; $text-disabled: #b7b7c6; $input-text-color: #595965; +$highlight-text-color: #6f42c1; +// ---------- dark mode ---------- $text-color-dark: #f3f3fd; $text-disabled-dark: #6f6f7a; $input-text-color-dark: #b5b5c8; +$highlight-text-color-dark: #B392F0; +// background colors +// ---------- light mode ---------- +$background-color: linear-gradient(-45deg, #FCFDFDCC 0%, #FCFDFD99 100%); +$background-color-secondary: #FCFDFD4D; +$background-color-accent: #6f42c1; +$background-color-button: #6f42c1; +$background-color-drop-down: #6F42C14D; +$background-color-input: #FFFFFF4D; +$background-color-input-focus: #F2F2F7; +$background-color-drop-down-gradient: linear-gradient(-45deg, #75649366 0%, #40257266 100%); +$background-color-selected: #E0DFFF; +$background-radial-gray-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%); + +// ---------- dark mode ---------- +$background-color-dark: linear-gradient(-45deg, #333333B3 0%, #2D2437B3 100%); +$background-color-secondary-dark: #19191D99; +$background-color-accent-dark: #6f42c1; +$background-color-button-dark: #6f42c1; +$background-color-drop-down-dark: #50505080; +$background-color-input-dark: #FFFFFF33; +$background-color-input-focus-dark: #333333; +$background-color-drop-down-gradient-dark: linear-gradient(-45deg, #8973B166 0%, #53427366 100%); +$background-color-selected-dark: #403E66; +$background-radial-gray-gradient-dark: radial-gradient(circle, #31373b 0%, #48494b 46%, #52415c 100%); + +// border colors +// ---------- light mode ---------- +$border-color: #E0DFFF; +$border-color-accent: #6F42C1; + +// ---------- dark mode ---------- +$border-color-dark: #564B69; +$border-color-accent-dark: #6F42C1; + +// highlight colors +// ---------- light mode ---------- +$highlight-accent-color: #E0DFFF; +$highlight-secondary-color: #6F42C1; + +// ---------- dark mode ---------- +$highlight-accent-color-dark: #403E6A; +$highlight-secondary-color-dark: #C4ABF1; + +// colors +$color1: #A392CD; +$color2: #7b4cd3; +$color3: #B186FF; +$color4: #8752E8; +$color5: #C7A8FF; + + +// old variables $accent-color: #6f42c1; $accent-color-dark: #c4abf1; $highlight-accent-color: #e0dfff; diff --git a/app/src/styles/base/global.scss b/app/src/styles/base/global.scss index 9b4e1e8..3ba017e 100644 --- a/app/src/styles/base/global.scss +++ b/app/src/styles/base/global.scss @@ -1,3 +1,5 @@ -section{ - -} \ No newline at end of file +section, .section{ + padding: 12px; + outline: 1px solid var(--border-color); + border-radius: 16px; +} From 5b6badaa5287a8ea7be688c03cea4bc6da1111f8 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Mon, 28 Apr 2025 09:51:07 +0530 Subject: [PATCH 04/30] refactor: Improve code readability and structure in EventProperties, DelayAction, SwapAction, and PreviewSelectionWithUpload components --- .../eventProperties/EventProperties.tsx | 111 ++++++++++-------- .../eventProperties/actions/DelayAction.tsx | 46 ++++---- .../eventProperties/actions/SwapAction.tsx | 34 +++--- .../ui/inputs/PreviewSelectionWithUpload.tsx | 93 ++++++++++----- 4 files changed, 167 insertions(+), 117 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index f8a8eeb..621a096 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -1,5 +1,8 @@ -import React, { useEffect, useRef, useState } from "react"; -import { useSelectedEventData, useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; +import React, { useEffect, useState } from "react"; +import { + useSelectedEventData, + useSelectedProduct, +} from "../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import ConveyorMechanics from "./mechanics/conveyorMechanics"; import VehicleMechanics from "./mechanics/vehicleMechanics"; @@ -8,55 +11,69 @@ import MachineMechanics from "./mechanics/machineMechanics"; import StorageMechanics from "./mechanics/storageMechanics"; const EventProperties: React.FC = () => { - const { selectedEventData } = useSelectedEventData(); - const { getEventByModelUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); - const [currentEventData, setCurrentEventData] = useState(null); - const [assetType, setAssetType] = useState(null); + const { selectedEventData } = useSelectedEventData(); + const { getEventByModelUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + const [currentEventData, setCurrentEventData] = useState( + null + ); + const [assetType, setAssetType] = useState(null); - useEffect(() => { - const event = getCurrentEventData(); - setCurrentEventData(event); + useEffect(() => { + const event = getCurrentEventData(); + setCurrentEventData(event); - const type = determineAssetType(event); - setAssetType(type); - - }, [selectedEventData, selectedProduct]); - - const getCurrentEventData = () => { - if (!selectedEventData?.data || !selectedProduct) return null; - return getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid) || null; - }; - - const determineAssetType = (event: EventsSchema | null) => { - if (!event) return null; - - switch (event.type) { - case 'transfer': return 'conveyor'; - case 'vehicle': return 'vehicle'; - case 'roboticArm': return 'roboticArm'; - case 'machine': return 'machine'; - case 'storageUnit': return 'storageUnit'; - default: return null; - } - }; + const type = determineAssetType(event); + setAssetType(type); + }, [selectedEventData, selectedProduct]); + const getCurrentEventData = () => { + if (!selectedEventData?.data || !selectedProduct) return null; return ( -
- {currentEventData && - <> -
-
{selectedEventData?.data.modelName}
-
- {assetType === 'conveyor' && } - {assetType === 'vehicle' && } - {assetType === 'roboticArm' && } - {assetType === 'machine' && } - {assetType === 'storageUnit' && } - - } -
+ getEventByModelUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid + ) ?? null ); + }; + + const determineAssetType = (event: EventsSchema | null) => { + if (!event) return null; + + switch (event.type) { + case "transfer": + return "conveyor"; + case "vehicle": + return "vehicle"; + case "roboticArm": + return "roboticArm"; + case "machine": + return "machine"; + case "storageUnit": + return "storageUnit"; + default: + return null; + } + }; + + return ( +
+ {currentEventData && ( + <> +
+
+ {selectedEventData?.data.modelName} +
+
+ {assetType === "conveyor" && } + {assetType === "vehicle" && } + {assetType === "roboticArm" && } + {assetType === "machine" && } + {assetType === "storageUnit" && } + + )} +
+ ); }; -export default EventProperties; \ No newline at end of file +export default EventProperties; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx index 2bb63d4..6c33583 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/DelayAction.tsx @@ -2,29 +2,33 @@ import React from "react"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; interface DelayActionProps { - value: string; - defaultValue: string; - min: number; - max: number; - onChange: (value: string) => void; + value: string; + defaultValue: string; + min: number; + max: number; + onChange: (value: string) => void; } -const DelayAction: React.FC = ({ value, defaultValue, min, max, onChange }) => { - return ( - <> - { }} - onChange={onChange} - /> - - ); +const DelayAction: React.FC = ({ + value, + defaultValue, + min, + max, + onChange, +}) => { + return ( + {}} + onChange={onChange} + /> + ); }; export default DelayAction; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx index 23b203f..5eaf991 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/SwapAction.tsx @@ -1,27 +1,25 @@ import React from "react"; import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload"; -import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; interface SwapActionProps { - onSelect: (option: string) => void; - defaultOption: string; - options: string[]; + onSelect: (option: string) => void; + defaultOption: string; + options: string[]; } -const SwapAction: React.FC = ({ onSelect, defaultOption, options }) => { - - return ( - <> - {/* */} - - - - ); +const SwapAction: React.FC = ({ + onSelect, + defaultOption, + options, +}) => { + return ( + + ); }; export default SwapAction; diff --git a/app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx b/app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx index 3e14517..53e03ce 100644 --- a/app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx +++ b/app/src/components/ui/inputs/PreviewSelectionWithUpload.tsx @@ -1,41 +1,72 @@ import React, { useState } from "react"; -import LabledDropdown from "./LabledDropdown"; import { ArrowIcon } from "../../icons/ExportCommonIcons"; +import LabledDropdown from "./LabledDropdown"; -const PreviewSelectionWithUpload: React.FC = () => { - const [showPreview, setSetshowPreview] = useState(false); +interface PreviewSelectionWithUploadProps { + preview?: boolean; + upload?: boolean; + label?: string; + onSelect: (option: string) => void; + defaultOption: string; + options: string[]; +} + +const PreviewSelectionWithUpload: React.FC = ({ + preview = false, + upload = false, + onSelect, + label, + defaultOption, + options, +}) => { + const [showPreview, setShowPreview] = useState(false); return (
-
setSetshowPreview(!showPreview)} - > -
Preview
-
- -
-
- {showPreview && ( -
-
+ {preview && ( + <> + + {showPreview && ( +
+
+
+ )} + + )} + {upload && ( +
+
+
Upload Product
+ + +
)} -
-
-
Upload Product
- - -
-
+
); }; From 29d38b4b40a7a179f828b37fe5dd8a34c6490a34 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Mon, 28 Apr 2025 11:43:06 +0530 Subject: [PATCH 05/30] merged with v2 --- .../instances/animator/vehicleAnimator.tsx | 149 +++++++++++++++--- .../instances/instance/vehicleInstance.tsx | 17 +- 2 files changed, 140 insertions(+), 26 deletions(-) diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index a0eeabd..dbc5064 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -9,12 +9,13 @@ import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore interface VehicleAnimatorProps { path: [number, number, number][]; handleCallBack: () => void; + reset: () => void; currentPhase: string; agvUuid: number; agvDetail: any; } -function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail }: VehicleAnimatorProps) { +function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) { const { decrementVehicleLoad, vehicles } = useVehicleStore(); const { isPaused } = usePauseButtonStore(); const { speed } = useAnimationPlaySpeed(); @@ -44,8 +45,118 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai setProgress(0); completedRef.current = false; }, [currentPath]); + // useEffect(() => { + // console.log('isReset: ', isReset); + // if (isReset) { + // reset(); + // setCurrentPath([]); + // setProgress(0); + // completedRef.current = false; + // decrementVehicleLoad(agvDetail.modelUuid, 0) + // } + // }, [isReset]) + + // useFrame((_, delta) => { + // const object = scene.getObjectByProperty('uuid', agvUuid); + // if (!object || currentPath.length < 2) return; + // if (isPaused) return; + + // let totalDistance = 0; + // const distances = []; + + // for (let i = 0; i < currentPath.length - 1; i++) { + // const start = new THREE.Vector3(...currentPath[i]); + // const end = new THREE.Vector3(...currentPath[i + 1]); + // const segmentDistance = start.distanceTo(end); + // distances.push(segmentDistance); + // totalDistance += segmentDistance; + // } + + // let coveredDistance = progressRef.current; + // let accumulatedDistance = 0; + // let index = 0; + + // while ( + // index < distances.length && + // coveredDistance > accumulatedDistance + distances[index] + // ) { + // accumulatedDistance += distances[index]; + // index++; + // } + + // if (index < distances.length) { + // const start = new THREE.Vector3(...currentPath[index]); + // const end = new THREE.Vector3(...currentPath[index + 1]); + // const segmentDistance = distances[index]; + + // const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); + // const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); + // const rotationSpeed = 2.0; + // const currentAngle = object.rotation.y; + + // let angleDifference = targetAngle - currentAngle; + // if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; + // if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; + + // const maxRotationStep = rotationSpeed * delta; + // object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); + + // const isAligned = Math.abs(angleDifference) < 0.01; + + // if (isAligned) { + // progressRef.current += delta * (speed * agvDetail.speed); + // coveredDistance = progressRef.current; + + // const t = (coveredDistance - accumulatedDistance) / segmentDistance; + // const position = start.clone().lerp(end, t); + // object.position.copy(position); + // } + // } + + // if (progressRef.current >= totalDistance) { + // if (restRotation) { + // const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); + // object.quaternion.slerp(targetQuaternion, delta * 2); + // const angleDiff = object.quaternion.angleTo(targetQuaternion); + // if (angleDiff < 0.01) { + // let objectRotation = agvDetail.point.rotation + // object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + // setRestingRotation(false); + // } + // return; + // } + // } + + // if (progressRef.current >= totalDistance) { + // setRestingRotation(true); + // progressRef.current = 0; + // movingForward.current = !movingForward.current; + // setCurrentPath([]); + // handleCallBack(); + // if (currentPhase === 'pickup-drop') { + // requestAnimationFrame(firstFrame); + // } + // } + // }); + useEffect(() => { + console.log('isReset: ', isReset); + if (isReset) { + reset(); + setCurrentPath([]); + setProgress(0); + progressRef.current = 0; + completedRef.current = false; + movingForward.current = true; + setRestingRotation(false); + decrementVehicleLoad(agvDetail.modelUuid, 0); + console.log('agvDetail: ', vehicles); + } + }, [isReset]); useFrame((_, delta) => { + // If reset is active, don't run anything in frame + if (isReset) return; + const object = scene.getObjectByProperty('uuid', agvUuid); if (!object || currentPath.length < 2) return; if (isPaused) return; @@ -65,10 +176,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai let accumulatedDistance = 0; let index = 0; - while ( - index < distances.length && - coveredDistance > accumulatedDistance + distances[index] - ) { + while (index < distances.length && coveredDistance > accumulatedDistance + distances[index]) { accumulatedDistance += distances[index]; index++; } @@ -80,15 +188,16 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); - const rotationSpeed = 2.0; const currentAngle = object.rotation.y; let angleDifference = targetAngle - currentAngle; if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; + const rotationSpeed = 2.0; const maxRotationStep = rotationSpeed * delta; - object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); + const rotationStep = Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); + object.rotation.y += rotationStep; const isAligned = Math.abs(angleDifference) < 0.01; @@ -108,22 +217,19 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai object.quaternion.slerp(targetQuaternion, delta * 2); const angleDiff = object.quaternion.angleTo(targetQuaternion); if (angleDiff < 0.01) { - let objectRotation = agvDetail.point.rotation + const objectRotation = agvDetail.point.rotation; object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); setRestingRotation(false); } - return; - } - } - - if (progressRef.current >= totalDistance) { - setRestingRotation(true); - progressRef.current = 0; - movingForward.current = !movingForward.current; - setCurrentPath([]); - handleCallBack(); - if (currentPhase === 'pickup-drop') { - requestAnimationFrame(firstFrame); + } else { + setRestingRotation(true); + progressRef.current = 0; + movingForward.current = !movingForward.current; + setCurrentPath([]); + handleCallBack(); + if (currentPhase === 'pickup-drop') { + requestAnimationFrame(firstFrame); + } } } }); @@ -137,8 +243,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai } function step(droppedMaterial: number) { - const elapsedTime = performance.now() - startTime; - + const elapsedTime = (performance.now() - startTime) * speed; if (elapsedTime >= fixedInterval) { console.log('fixedInterval: ', fixedInterval); console.log('elapsedTime: ', elapsedTime); diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index d0691f9..44a8ad8 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -3,12 +3,13 @@ import VehicleAnimator from '../animator/vehicleAnimator'; import * as THREE from 'three'; import { NavMeshQuery } from '@recast-navigation/core'; import { useNavMesh } from '../../../../../store/store'; -import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; +import { usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; function VehicleInstance({ agvDetail }: any) { const { navMesh } = useNavMesh(); - const { isPlaying } = usePlayButtonStore(); + const { isPlaying, setIsPlaying } = usePlayButtonStore(); + const { isReset } = useResetButtonStore(); const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore(); const [currentPhase, setCurrentPhase] = useState('stationed'); const [path, setPath] = useState<[number, number, number][]>([]); @@ -31,6 +32,13 @@ function VehicleInstance({ agvDetail }: any) { function vehicleStatus(modelid: string, status: string) { // console.log(`AGV ${modelid}: ${status}`); } + function reset() { + console.log("runs"); + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setPath([]); + setCurrentPhase('stationed') + } useEffect(() => { if (isPlaying) { @@ -50,7 +58,7 @@ function VehicleInstance({ agvDetail }: any) { agvDetail.state === 'idle' && currentPhase === 'picking' ) { - + setTimeout(() => { incrementVehicleLoad(agvDetail.modelUuid, 2); }, 5000); @@ -83,7 +91,7 @@ function VehicleInstance({ agvDetail }: any) { vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); } } - }, [vehicles, currentPhase, path, isPlaying]); + }, [vehicles, currentPhase, path, isPlaying, isReset]); function handleCallBack() { if (currentPhase === 'stationed-pickup') { @@ -115,6 +123,7 @@ function VehicleInstance({ agvDetail }: any) { currentPhase={currentPhase} agvUuid={agvDetail?.modelUuid} agvDetail={agvDetail} + reset={reset} /> ); From 897633d4cc712f55cc84cb7eb27c9fa638699b81 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Mon, 28 Apr 2025 18:08:27 +0530 Subject: [PATCH 06/30] Refactor mechanics components to use ActionsList for action management - Consolidated action handling logic into a new ActionsList component for better code organization and reusability. - Updated RoboticArmMechanics, StorageMechanics, and VehicleMechanics to utilize the new ActionsList component. - Improved state management and action updates within the mechanics components. - Enhanced UI responsiveness and styling in sidebar and real-time visualization pages. --- .../layout/sidebarRight/SideBarRight.tsx | 263 ++++++----- .../eventProperties/EventProperties.tsx | 39 +- .../components/ActionsList.tsx | 197 ++++++++ .../mechanics/conveyorMechanics.tsx | 386 ++++++++-------- .../mechanics/machineMechanics.tsx | 216 ++++----- .../mechanics/roboticArmMechanics.tsx | 426 +++++++----------- .../mechanics/storageMechanics.tsx | 201 +++++---- .../mechanics/vehicleMechanics.tsx | 344 +++++++------- app/src/styles/layout/sidebar.scss | 62 ++- app/src/styles/pages/realTimeViz.scss | 6 +- 10 files changed, 1192 insertions(+), 948 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index 38f0b18..cb9b5dc 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -1,148 +1,161 @@ import React, { useEffect } from "react"; import Header from "./Header"; import useModuleStore, { - useSubModuleStore, + useSubModuleStore, } from "../../../store/useModuleStore"; import { - AnalysisIcon, - MechanicsIcon, - PropertiesIcon, - SimulationIcon, + AnalysisIcon, + MechanicsIcon, + PropertiesIcon, + SimulationIcon, } from "../../icons/SimulationIcons"; import useToggleStore from "../../../store/useUIToggleStore"; import Visualization from "./visualization/Visualization"; import Analysis from "./analysis/Analysis"; import Simulations from "./simulation/Simulations"; import { useSelectedFloorItem } from "../../../store/store"; -import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; +import { + useSelectedEventData, + useSelectedEventSphere, +} from "../../../store/simulation/useSimulationStore"; import GlobalProperties from "./properties/GlobalProperties"; import AsstePropertiies from "./properties/AssetProperties"; import ZoneProperties from "./properties/ZoneProperties"; import EventProperties from "./properties/eventProperties/EventProperties"; const SideBarRight: React.FC = () => { - const { activeModule } = useModuleStore(); - const { toggleUI } = useToggleStore(); - const { subModule, setSubModule } = useSubModuleStore(); - const { selectedFloorItem } = useSelectedFloorItem(); - const { selectedEventData } = useSelectedEventData(); - const { selectedEventSphere } = useSelectedEventSphere(); + const { activeModule } = useModuleStore(); + const { toggleUI } = useToggleStore(); + const { subModule, setSubModule } = useSubModuleStore(); + const { selectedFloorItem } = useSelectedFloorItem(); + const { selectedEventData } = useSelectedEventData(); + const { selectedEventSphere } = useSelectedEventSphere(); - // Reset activeList whenever activeModule changes - useEffect(() => { - if (activeModule !== "simulation") setSubModule("properties"); - if (activeModule === "simulation") setSubModule("simulations"); - }, [activeModule]); + // Reset activeList whenever activeModule changes + useEffect(() => { + if (activeModule !== "simulation") setSubModule("properties"); + if (activeModule === "simulation") setSubModule("simulations"); + }, [activeModule, setSubModule]); - useEffect(() => { - if (activeModule !== "mechanics" && selectedEventData && selectedEventSphere) { - setSubModule("mechanics"); - } else if (!selectedEventData && !selectedEventSphere) { - if (activeModule === 'simulation') { - setSubModule("simulations"); - } - }; - }, [activeModule, selectedEventData, selectedEventSphere]) + useEffect(() => { + if ( + activeModule !== "mechanics" && + selectedEventData && + selectedEventSphere + ) { + setSubModule("mechanics"); + } else if (!selectedEventData && !selectedEventSphere) { + if (activeModule === "simulation") { + setSubModule("simulations"); + } + } + }, [activeModule, selectedEventData, selectedEventSphere, setSubModule]); - return ( -
-
- {toggleUI && ( -
-
setSubModule("properties")} - > - -
- {activeModule === "simulation" && ( - <> -
setSubModule("mechanics")} - > - -
-
setSubModule("simulations")} - > - -
-
setSubModule("analysis")} - > - -
- - )} -
- )} - {/* process builder */} - {toggleUI && - subModule === "properties" && - activeModule !== "visualization" && - !selectedFloorItem && ( -
-
- -
-
- )} - {toggleUI && - subModule === "properties" && - activeModule !== "visualization" && - selectedFloorItem && ( -
-
- -
-
- )} - {toggleUI && - subModule === "zoneProperties" && - (activeModule === "builder" || activeModule === "simulation") && ( -
-
- -
-
- )} - {/* simulation */} - {toggleUI && activeModule === "simulation" && ( - <> - {subModule === "simulations" && ( -
-
- -
-
- )} - {subModule === "mechanics" && ( -
-
- -
-
- )} - {subModule === "analysis" && ( -
-
- -
-
- )} - - )} - {/* realtime visualization */} - {toggleUI && activeModule === "visualization" && } + return ( +
+
+ {toggleUI && ( +
+ {activeModule !== "simulation" && ( + + )} + {activeModule === "simulation" && ( + <> + + + + + )}
- ); + )} + {/* process builder */} + {toggleUI && + subModule === "properties" && + activeModule !== "visualization" && + !selectedFloorItem && ( +
+
+ +
+
+ )} + {toggleUI && + subModule === "properties" && + activeModule !== "visualization" && + selectedFloorItem && ( +
+
+ +
+
+ )} + {toggleUI && + subModule === "zoneProperties" && + (activeModule === "builder" || activeModule === "simulation") && ( +
+
+ +
+
+ )} + {/* simulation */} + {toggleUI && activeModule === "simulation" && ( + <> + {subModule === "simulations" && ( +
+
+ +
+
+ )} + {subModule === "mechanics" && ( +
+
+ +
+
+ )} + {subModule === "analysis" && ( +
+
+ +
+
+ )} + + )} + {/* realtime visualization */} + {toggleUI && activeModule === "visualization" && } +
+ ); }; -export default SideBarRight; \ No newline at end of file +export default SideBarRight; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 621a096..847d035 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useState } from "react"; import { useSelectedEventData, + useSelectedEventSphere, useSelectedProduct, } from "../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; @@ -9,6 +10,7 @@ import VehicleMechanics from "./mechanics/vehicleMechanics"; import RoboticArmMechanics from "./mechanics/roboticArmMechanics"; import MachineMechanics from "./mechanics/machineMechanics"; import StorageMechanics from "./mechanics/storageMechanics"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; const EventProperties: React.FC = () => { const { selectedEventData } = useSelectedEventData(); @@ -18,13 +20,15 @@ const EventProperties: React.FC = () => { null ); const [assetType, setAssetType] = useState(null); - + const { products } = useProductStore(); + const { selectedEventSphere } = useSelectedEventSphere(); useEffect(() => { const event = getCurrentEventData(); setCurrentEventData(event); const type = determineAssetType(event); setAssetType(type); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedEventData, selectedProduct]); const getCurrentEventData = () => { @@ -72,6 +76,39 @@ const EventProperties: React.FC = () => { {assetType === "storageUnit" && } )} + {!currentEventData && selectedEventSphere && ( +
+

+ Oops! It looks like this object doesn't have an + event assigned yet. To continue, please link it to one of the + products below. +

+ +
+

+ Here are some products you can add it to: +

+
    + {products.map((product) => ( +
  • + +
  • + ))} +
+
+
+ )} + {!selectedEventSphere && ( +
+

+ Oops! It looks like you haven't selected an event + point yet. Please select an event to view its properties. +

+
+ )}
); }; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx new file mode 100644 index 0000000..56626c8 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx @@ -0,0 +1,197 @@ +import React, { useRef } from "react"; +import { + AddIcon, + RemoveIcon, + ResizeHeightIcon, +} from "../../../../../icons/ExportCommonIcons"; +import RenameInput from "../../../../../ui/inputs/RenameInput"; +import { handleResize } from "../../../../../../functions/handleResizePannel"; +import { + useSelectedAction, + useSelectedEventData, + useSelectedProduct, +} from "../../../../../../store/simulation/useSimulationStore"; +import { MathUtils } from "three"; +import { useProductStore } from "../../../../../../store/simulation/useProductStore"; + +interface ActionsListProps { + setSelectedPointData: (data: any) => void; // You can replace `any` with a more specific type if you have one + selectedPointData: any; // You can replace `any` with a more specific type if you have one + // ui control props + multipleAction?: boolean; +} + +const ActionsList: React.FC = ({ + setSelectedPointData, + selectedPointData, + multipleAction = false, +}) => { + const actionsContainerRef = useRef(null); + + // store + const { selectedEventData } = useSelectedEventData(); + const { updateAction, addAction, removeAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + const { selectedAction, setSelectedAction, clearSelectedAction } = + useSelectedAction(); + + const handleAddAction = () => { + if (!selectedEventData || !selectedPointData) return; + + const newAction = { + actionUuid: MathUtils.generateUUID(), + actionName: `Action ${selectedPointData.actions.length + 1}`, + actionType: "pickAndPlace" as const, + process: { + startPoint: null, + endPoint: null, + }, + triggers: [] as TriggerSchema[], + }; + + addAction( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint, + newAction + ); + + const updatedPoint = { + ...selectedPointData, + actions: [...selectedPointData.actions, newAction], + }; + setSelectedPointData(updatedPoint); + setSelectedAction(newAction.actionUuid, newAction.actionName); + }; + + const handleDeleteAction = (actionUuid: string) => { + if (!selectedPointData) return; + + removeAction(actionUuid); + const newActions = selectedPointData.actions.filter( + (a: any) => a.actionUuid !== actionUuid + ); + + const updatedPoint = { + ...selectedPointData, + actions: newActions, + }; + setSelectedPointData(updatedPoint); + + if (selectedAction.actionId === actionUuid) { + if (newActions.length > 0) { + setSelectedAction(newActions[0].actionUuid, newActions[0].actionName); + } else { + clearSelectedAction(); + } + } + }; + + const handleRenameAction = (newName: string) => { + if (!selectedAction.actionId) return; + updateAction(selectedAction.actionId, { actionName: newName }); + + if (selectedPointData?.actions) { + const updatedActions = selectedPointData.actions.map((action: any) => + action.actionUuid === selectedAction.actionId + ? { ...action, actionName: newName } + : action + ); + setSelectedPointData({ + ...selectedPointData, + actions: updatedActions, + }); + } else { + // write logic for single action + return; + } + }; + + const handleActionSelect = (actionUuid: string, actionName: string) => { + setSelectedAction(actionUuid, actionName); + }; + + return ( +
+
+
+
Actions
+ {multipleAction && ( + + )} +
+
+
+ {multipleAction && + selectedPointData.actions.map((action: any) => ( +
+ + {selectedPointData.actions.length > 1 && ( + + )} +
+ ))} + {!multipleAction && selectedPointData && ( +
+ +
+ )} +
+ +
+
+
+ ); +}; + +export default ActionsList; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx index c13bd75..b370b3e 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -1,212 +1,224 @@ -import { useEffect, useState } from 'react' -import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' -import DelayAction from '../actions/DelayAction' -import RenameInput from '../../../../../ui/inputs/RenameInput' -import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' -import DespawnAction from '../actions/DespawnAction' -import SwapAction from '../actions/SwapAction' -import SpawnAction from '../actions/SpawnAction' -import DefaultAction from '../actions/DefaultAction' -import Trigger from '../trigger/Trigger' -import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useEffect, useState } from "react"; +import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; +import DelayAction from "../actions/DelayAction"; +import RenameInput from "../../../../../ui/inputs/RenameInput"; +import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; +import DespawnAction from "../actions/DespawnAction"; +import SwapAction from "../actions/SwapAction"; +import SpawnAction from "../actions/SpawnAction"; +import DefaultAction from "../actions/DefaultAction"; +import Trigger from "../trigger/Trigger"; +import { + useSelectedEventData, + useSelectedProduct, +} from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; +import ActionsList from "../components/ActionsList"; function ConveyorMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default"); - const [selectedPointData, setSelectedPointData] = useState(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateEvent, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState< + "default" | "spawn" | "swap" | "delay" | "despawn" + >("default"); + const [selectedPointData, setSelectedPointData] = useState< + ConveyorPointSchema | undefined + >(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateEvent, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint - ) as ConveyorPointSchema | undefined; - if (point && 'action' in point) { - setSelectedPointData(point); - setActiveOption(point.action.actionType as "default" | "spawn" | "swap" | "delay" | "despawn"); - } - } - }, [selectedProduct, selectedEventData]) - - const handleSpeedChange = (value: string) => { - if (!selectedEventData) return; - updateEvent( - selectedProduct.productId, - selectedEventData.data.modelUuid, - { speed: parseFloat(value) } + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as ConveyorPointSchema | undefined; + if (point && "action" in point) { + setSelectedPointData(point); + setActiveOption( + point.action.actionType as + | "default" + | "spawn" + | "swap" + | "delay" + | "despawn" ); - }; + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as "default" | "spawn" | "swap" | "delay" | "despawn"; - setActiveOption(validOption); + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { + speed: parseFloat(value), + }); + }; - updateAction( - selectedPointData.action.actionUuid, - { actionType: validOption } - ); - }; + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as + | "default" + | "spawn" + | "swap" + | "delay" + | "despawn"; + setActiveOption(validOption); - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { actionName: newName } - ); - }; + updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); + }; - const handleSpawnCountChange = (value: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { spawnCount: value === "inherit" ? "inherit" : parseFloat(value) } - ); - }; + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + }; - const handleSpawnIntervalChange = (value: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { spawnInterval: value === "inherit" ? "inherit" : parseFloat(value) } - ); - }; + const handleSpawnCountChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + spawnCount: value === "inherit" ? "inherit" : parseFloat(value), + }); + }; - const handleMaterialSelect = (material: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { material } - ); - }; + const handleSpawnIntervalChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + spawnInterval: value === "inherit" ? "inherit" : parseFloat(value), + }); + }; - const handleDelayChange = (value: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { delay: value === "inherit" ? "inherit" : parseFloat(value) } - ); - }; + const handleMaterialSelect = (material: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { material }); + }; - const availableActions = { - defaultOption: "default", - options: ["default", "spawn", "swap", "delay", "despawn"], - }; + const handleDelayChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + delay: value === "inherit" ? "inherit" : parseFloat(value), + }); + }; - // Get current values from store - const currentSpeed = selectedEventData?.data.type === "transfer" - ? selectedEventData.data.speed.toString() - : "0.5"; + const availableActions = { + defaultOption: "default", + options: ["default", "spawn", "swap", "delay", "despawn"], + }; - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + // Get current values from store + const currentSpeed = + selectedEventData?.data.type === "transfer" + ? selectedEventData.data.speed.toString() + : "0.5"; - const currentMaterial = selectedPointData - ? selectedPointData.action.material - : "Default material"; + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; - const currentSpawnCount = selectedPointData - ? selectedPointData.action.spawnCount?.toString() || "1" - : "1"; + const currentMaterial = selectedPointData + ? selectedPointData.action.material + : "Default material"; - const currentSpawnInterval = selectedPointData - ? selectedPointData.action.spawnInterval?.toString() || "1" - : "1"; + const currentSpawnCount = selectedPointData + ? selectedPointData.action.spawnCount?.toString() || "1" + : "1"; - const currentDelay = selectedPointData - ? selectedPointData.action.delay?.toString() || "0" - : "0"; + const currentSpawnInterval = selectedPointData + ? selectedPointData.action.spawnInterval?.toString() || "1" + : "1"; - return ( + const currentDelay = selectedPointData + ? selectedPointData.action.delay?.toString() || "0" + : "0"; + + return ( + <> + {selectedEventData && ( <> - {selectedEventData && - <> -
-
-
- { }} - onChange={handleSpeedChange} - /> -
-
-
+
+
+
+ {}} + onChange={handleSpeedChange} + /> +
+
+
-
-
- -
-
- - {activeOption === "default" && - - } - {activeOption === "spawn" && - - } - {activeOption === "swap" && - - } - {activeOption === "despawn" && - - } - {activeOption === "delay" && - - } -
-
-
- -
- - } + + +
+
+ +
+
+ + {activeOption === "default" && } + {activeOption === "spawn" && ( + + )} + {activeOption === "swap" && ( + + )} + {activeOption === "despawn" && } + {activeOption === "delay" && ( + + )} +
+
+
+ +
- ) + )} + + ); } -export default ConveyorMechanics \ No newline at end of file +export default ConveyorMechanics; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx index e131864..fa2cfdf 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -1,123 +1,129 @@ -import { useEffect, useState } from 'react' -import RenameInput from '../../../../../ui/inputs/RenameInput' -import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' -import Trigger from '../trigger/Trigger' -import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useEffect, useState } from "react"; +import RenameInput from "../../../../../ui/inputs/RenameInput"; +import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; +import Trigger from "../trigger/Trigger"; +import { + useSelectedEventData, + useSelectedProduct, +} from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; -import ProcessAction from '../actions/ProcessAction' +import ProcessAction from "../actions/ProcessAction"; +import ActionsList from "../components/ActionsList"; function MachineMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "process">("default"); - const [selectedPointData, setSelectedPointData] = useState(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState<"default" | "process">( + "default" + ); + const [selectedPointData, setSelectedPointData] = useState< + MachinePointSchema | undefined + >(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint - ) as MachinePointSchema | undefined; - if (point && 'action' in point) { - setSelectedPointData(point); - setActiveOption(point.action.actionType as "process"); - } - } - }, [selectedProduct, selectedEventData]) + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as MachinePointSchema | undefined; + if (point && "action" in point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "process"); + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as "process"; - setActiveOption(validOption); + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "process"; + setActiveOption(validOption); - updateAction( - selectedPointData.action.actionUuid, - { actionType: validOption } - ); - }; + updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); + }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { actionName: newName } - ); - }; + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + }; - const handleProcessTimeChange = (value: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { processTime: parseFloat(value) } - ); - }; + const handleProcessTimeChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + processTime: parseFloat(value), + }); + }; - const handleMaterialSelect = (material: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { swapMaterial: material } - ); - }; + const handleMaterialSelect = (material: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + swapMaterial: material, + }); + }; - // Get current values from store - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + // Get current values from store + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; - const currentProcessTime = selectedPointData - ? selectedPointData.action.processTime.toString() - : "1"; + const currentProcessTime = selectedPointData + ? selectedPointData.action.processTime.toString() + : "1"; - const currentMaterial = selectedPointData - ? selectedPointData.action.swapMaterial - : "Default material"; + const currentMaterial = selectedPointData + ? selectedPointData.action.swapMaterial + : "Default material"; - const availableActions = { - defaultOption: "process", - options: ["process"], - }; + const availableActions = { + defaultOption: "process", + options: ["process"], + }; - return ( + return ( + <> + {selectedEventData && ( <> - {selectedEventData && - <> -
-
- -
-
- - {activeOption === "process" && - - } -
-
-
- -
- - } +
+
+ +
+ +
+ + {activeOption === "process" && ( + + )} +
+
+
+ +
- ) + )} + + ); } -export default MachineMechanics \ No newline at end of file +export default MachineMechanics; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx index 78a32f5..a4ced23 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -1,276 +1,194 @@ -import { useEffect, useRef, useState } from 'react' -import * as THREE from 'three'; -import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' -import RenameInput from '../../../../../ui/inputs/RenameInput' -import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' -import Trigger from '../trigger/Trigger' -import { useSelectedEventData, useSelectedProduct, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore"; +import { useEffect, useState } from "react"; +import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; +import RenameInput from "../../../../../ui/inputs/RenameInput"; +import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; +import Trigger from "../trigger/Trigger"; +import { + useSelectedEventData, + useSelectedProduct, + useSelectedAction, +} from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; -import { AddIcon, RemoveIcon, ResizeHeightIcon } from '../../../../../icons/ExportCommonIcons' -import { handleResize } from '../../../../../../functions/handleResizePannel' -import PickAndPlaceAction from '../actions/PickAndPlaceAction' +import PickAndPlaceAction from "../actions/PickAndPlaceAction"; +import ActionsList from "../components/ActionsList"; function RoboticArmMechanics() { - const actionsContainerRef = useRef(null); - const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default"); - const [selectedPointData, setSelectedPointData] = useState(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateEvent, updateAction, addAction, removeAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); - const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction(); + const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">( + "default" + ); + const [selectedPointData, setSelectedPointData] = useState< + RoboticArmPointSchema | undefined + >(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateEvent, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + const { selectedAction, setSelectedAction, clearSelectedAction } = + useSelectedAction(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData.data.modelUuid, - selectedEventData.selectedPoint - ) as RoboticArmPointSchema | undefined; - if (point) { - setSelectedPointData(point); - setActiveOption(point.actions[0].actionType as "default" | "pickAndPlace"); - if (point.actions.length > 0 && !selectedAction.actionId) { - setSelectedAction(point.actions[0].actionUuid, point.actions[0].actionName); - } - } - } else { - clearSelectedAction(); + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint + ) as RoboticArmPointSchema | undefined; + if (point) { + setSelectedPointData(point); + setActiveOption( + point.actions[0].actionType as "default" | "pickAndPlace" + ); + if (point.actions.length > 0 && !selectedAction.actionId) { + setSelectedAction( + point.actions[0].actionUuid, + point.actions[0].actionName + ); } - }, [selectedEventData, selectedProduct]); + } + } else { + clearSelectedAction(); + } + }, [ + clearSelectedAction, + getPointByUuid, + selectedAction.actionId, + selectedEventData, + selectedProduct, + setSelectedAction, + ]); - const handleActionSelect = (actionUuid: string, actionName: string) => { - setSelectedAction(actionUuid, actionName); - }; + const handleRenameAction = (newName: string) => { + if (!selectedAction.actionId) return; + updateAction(selectedAction.actionId, { actionName: newName }); - const handleAddAction = () => { - if (!selectedEventData || !selectedPointData) return; + if (selectedPointData) { + const updatedActions = selectedPointData.actions.map((action) => + action.actionUuid === selectedAction.actionId + ? { ...action, actionName: newName } + : action + ); + setSelectedPointData({ + ...selectedPointData, + actions: updatedActions, + }); + } + }; - const newAction = { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: `Action ${selectedPointData.actions.length + 1}`, - actionType: "pickAndPlace" as "pickAndPlace", - process: { - startPoint: null, - endPoint: null - }, - triggers: [] as TriggerSchema[] - }; + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { + speed: parseFloat(value), + }); + }; - addAction( - selectedProduct.productId, - selectedEventData.data.modelUuid, - selectedEventData.selectedPoint, - newAction - ); + const handlePickPointChange = (value: string) => { + if (!selectedAction.actionId || !selectedPointData) return; + const [x, y, z] = value.split(",").map(Number); - const updatedPoint = { - ...selectedPointData, - actions: [...selectedPointData.actions, newAction] - }; - setSelectedPointData(updatedPoint); - setSelectedAction(newAction.actionUuid, newAction.actionName); - }; + updateAction(selectedAction.actionId, { + process: { + startPoint: [x, y, z] as [number, number, number], + endPoint: + selectedPointData.actions.find( + (a) => a.actionUuid === selectedAction.actionId + )?.process.endPoint || null, + }, + }); + }; - const handleDeleteAction = (actionUuid: string) => { - if (!selectedPointData) return; + const handlePlacePointChange = (value: string) => { + if (!selectedAction.actionId || !selectedPointData) return; + const [x, y, z] = value.split(",").map(Number); - removeAction(actionUuid); - const newActions = selectedPointData.actions.filter(a => a.actionUuid !== actionUuid); + updateAction(selectedAction.actionId, { + process: { + startPoint: + selectedPointData.actions.find( + (a) => a.actionUuid === selectedAction.actionId + )?.process.startPoint || null, + endPoint: [x, y, z] as [number, number, number], + }, + }); + }; - const updatedPoint = { - ...selectedPointData, - actions: newActions - }; - setSelectedPointData(updatedPoint); + const availableActions = { + defaultOption: "pickAndPlace", + options: ["pickAndPlace"], + }; - if (selectedAction.actionId === actionUuid) { - if (newActions.length > 0) { - setSelectedAction(newActions[0].actionUuid, newActions[0].actionName); - } else { - clearSelectedAction(); - } - } - }; + const currentSpeed = + selectedEventData?.data.type === "roboticArm" + ? selectedEventData.data.speed.toString() + : "0.5"; - const handleRenameAction = (newName: string) => { - if (!selectedAction.actionId) return; - updateAction( - selectedAction.actionId, - { actionName: newName } - ); + const currentAction = selectedPointData?.actions.find( + (a) => a.actionUuid === selectedAction.actionId + ); + const currentPickPoint = currentAction?.process.startPoint + ? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}` + : ""; + const currentPlacePoint = currentAction?.process.endPoint + ? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}` + : ""; - if (selectedPointData) { - const updatedActions = selectedPointData.actions.map(action => - action.actionUuid === selectedAction.actionId - ? { ...action, actionName: newName } - : action - ); - setSelectedPointData({ - ...selectedPointData, - actions: updatedActions - }); - } - }; - - const handleSpeedChange = (value: string) => { - if (!selectedEventData) return; - updateEvent( - selectedProduct.productId, - selectedEventData.data.modelUuid, - { speed: parseFloat(value) } - ); - }; - - const handlePickPointChange = (value: string) => { - if (!selectedAction.actionId || !selectedPointData) return; - const [x, y, z] = value.split(',').map(Number); - - updateAction( - selectedAction.actionId, - { - process: { - startPoint: [x, y, z] as [number, number, number], - endPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.endPoint || null - } - } - ); - }; - - const handlePlacePointChange = (value: string) => { - if (!selectedAction.actionId || !selectedPointData) return; - const [x, y, z] = value.split(',').map(Number); - - updateAction( - selectedAction.actionId, - { - process: { - startPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.startPoint || null, - endPoint: [x, y, z] as [number, number, number] - } - } - ); - }; - - const availableActions = { - defaultOption: "pickAndPlace", - options: ["pickAndPlace"], - }; - - const currentSpeed = selectedEventData?.data.type === "roboticArm" - ? selectedEventData.data.speed.toString() - : "0.5"; - - const currentAction = selectedPointData?.actions.find(a => a.actionUuid === selectedAction.actionId); - const currentPickPoint = currentAction?.process.startPoint - ? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}` - : ""; - const currentPlacePoint = currentAction?.process.endPoint - ? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}` - : ""; - - return ( + return ( + <> + {selectedEventData && selectedPointData && ( <> - {selectedEventData && selectedPointData && ( - <> -
-
-
- { }} - onChange={handleSpeedChange} - /> -
-
-
+
+
+
+ {}} + onChange={handleSpeedChange} + /> +
+
+
-
-
-
-
Actions
-
- Add -
-
-
-
- {selectedPointData.actions.map((action) => ( -
-
handleActionSelect(action.actionUuid, action.actionName)} - > - -
- {selectedPointData.actions.length > 1 && ( -
handleDeleteAction(action.actionUuid)} - > - -
- )} -
- ))} -
-
handleResize(e, actionsContainerRef)} - > - -
-
-
-
+ - {selectedAction.actionId && currentAction && ( -
-
- -
-
- { }} - disabled={true} - /> - -
-
- -
-
- )} - - )} + {selectedAction.actionId && currentAction && ( +
+
+ +
+
+ {}} + disabled={true} + /> + +
+
+ +
+
+ )} - ) + )} + + ); } -export default RoboticArmMechanics \ No newline at end of file +export default RoboticArmMechanics; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index 593dcc3..d92ed80 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -1,113 +1,120 @@ -import { useEffect, useState } from 'react' -import RenameInput from '../../../../../ui/inputs/RenameInput' -import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' -import Trigger from '../trigger/Trigger' -import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useEffect, useState } from "react"; +import RenameInput from "../../../../../ui/inputs/RenameInput"; +import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; +import Trigger from "../trigger/Trigger"; +import { + useSelectedEventData, + useSelectedProduct, +} from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; -import StorageAction from '../actions/StorageAction'; +import StorageAction from "../actions/StorageAction"; +import ActionsList from "../components/ActionsList"; function StorageMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default"); - const [selectedPointData, setSelectedPointData] = useState(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState< + "default" | "store" | "spawn" + >("default"); + const [selectedPointData, setSelectedPointData] = useState< + StoragePointSchema | undefined + >(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint - ) as StoragePointSchema | undefined; - if (point && 'action' in point) { - setSelectedPointData(point); - setActiveOption(point.action.actionType as "store" | "spawn"); - } - } - }, [selectedProduct, selectedEventData]) + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as StoragePointSchema | undefined; + if (point && "action" in point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "store" | "spawn"); + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as "store" | "spawn"; - setActiveOption(validOption); + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "store" | "spawn"; + setActiveOption(validOption); - updateAction( - selectedPointData.action.actionUuid, - { actionType: validOption } - ); - }; + updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); + }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { actionName: newName } - ); - }; + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + }; - const handleCapacityChange = (value: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { storageCapacity: parseInt(value) } - ); - }; + const handleCapacityChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + storageCapacity: parseInt(value), + }); + }; - // Get current values from store - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + // Get current values from store + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; - const currentCapacity = selectedPointData - ? selectedPointData.action.storageCapacity.toString() - : "0"; + const currentCapacity = selectedPointData + ? selectedPointData.action.storageCapacity.toString() + : "0"; - const availableActions = { - defaultOption: "store", - options: ["store", "spawn"], - }; + const availableActions = { + defaultOption: "store", + options: ["store", "spawn"], + }; - return ( + return ( + <> + {selectedEventData && ( <> - {selectedEventData && - <> -
-
- -
-
- - {activeOption === "store" && - - } - {activeOption === "spawn" && ( -
-

Spawn configuration options would go here

-
- )} -
-
-
- -
- - } + +
+
+ +
+
+ + {activeOption === "store" && ( + + )} + {activeOption === "spawn" && ( +
+

Spawn configuration options would go here

+
+ )} +
+
+
+ +
- ) + )} + + ); } -export default StorageMechanics \ No newline at end of file +export default StorageMechanics; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index cc2bfa0..4524ceb 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -1,197 +1,199 @@ -import { useEffect, useState } from 'react' -import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown' -import RenameInput from '../../../../../ui/inputs/RenameInput' -import LabledDropdown from '../../../../../ui/inputs/LabledDropdown' -import Trigger from '../trigger/Trigger' -import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useEffect, useState } from "react"; +import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; +import RenameInput from "../../../../../ui/inputs/RenameInput"; +import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; +import Trigger from "../trigger/Trigger"; +import { + useSelectedEventData, + useSelectedProduct, +} from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; -import TravelAction from '../actions/TravelAction' +import TravelAction from "../actions/TravelAction"; +import ActionsList from "../components/ActionsList"; function VehicleMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "travel">("default"); - const [selectedPointData, setSelectedPointData] = useState(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateEvent, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState<"default" | "travel">( + "default" + ); + const [selectedPointData, setSelectedPointData] = useState< + VehiclePointSchema | undefined + >(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateEvent, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData.data.modelUuid, - selectedEventData.selectedPoint - ) as VehiclePointSchema | undefined; + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint + ) as VehiclePointSchema | undefined; - if (point) { - setSelectedPointData(point); - setActiveOption(point.action.actionType as "travel"); - } - } - }, [selectedProduct, selectedEventData]) + if (point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "travel"); + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleSpeedChange = (value: string) => { - if (!selectedEventData) return; - updateEvent( - selectedProduct.productId, - selectedEventData.data.modelUuid, - { speed: parseFloat(value) } - ); - }; + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { + speed: parseFloat(value), + }); + }; - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as "travel"; - setActiveOption(validOption); + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "travel"; + setActiveOption(validOption); - updateAction( - selectedPointData.action.actionUuid, - { actionType: validOption } - ); - }; + updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); + }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { actionName: newName } - ); - }; + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + }; - const handleLoadCapacityChange = (value: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { loadCapacity: parseFloat(value) } - ); - }; + const handleLoadCapacityChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + loadCapacity: parseFloat(value), + }); + }; - const handleUnloadDurationChange = (value: string) => { - if (!selectedPointData) return; - updateAction( - selectedPointData.action.actionUuid, - { unLoadDuration: parseFloat(value) } - ); - }; + const handleUnloadDurationChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + unLoadDuration: parseFloat(value), + }); + }; - const handlePickPointChange = (value: string) => { - if (!selectedPointData) return; - const [x, y, z] = value.split(',').map(Number); - updateAction( - selectedPointData.action.actionUuid, - { pickUpPoint: { x, y, z } } - ); - }; + const handlePickPointChange = (value: string) => { + if (!selectedPointData) return; + const [x, y, z] = value.split(",").map(Number); + updateAction(selectedPointData.action.actionUuid, { + pickUpPoint: { x, y, z }, + }); + }; - const handleUnloadPointChange = (value: string) => { - if (!selectedPointData) return; - const [x, y, z] = value.split(',').map(Number); - updateAction( - selectedPointData.action.actionUuid, - { unLoadPoint: { x, y, z } } - ); - }; + const handleUnloadPointChange = (value: string) => { + if (!selectedPointData) return; + const [x, y, z] = value.split(",").map(Number); + updateAction(selectedPointData.action.actionUuid, { + unLoadPoint: { x, y, z }, + }); + }; - // Get current values from store - const currentSpeed = selectedEventData?.data.type === "vehicle" - ? selectedEventData.data.speed.toString() - : "0.5"; + // Get current values from store + const currentSpeed = + selectedEventData?.data.type === "vehicle" + ? selectedEventData.data.speed.toString() + : "0.5"; - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; - const currentLoadCapacity = selectedPointData - ? selectedPointData.action.loadCapacity.toString() - : "1"; + const currentLoadCapacity = selectedPointData + ? selectedPointData.action.loadCapacity.toString() + : "1"; - const currentUnloadDuration = selectedPointData - ? selectedPointData.action.unLoadDuration.toString() - : "1"; + const currentUnloadDuration = selectedPointData + ? selectedPointData.action.unLoadDuration.toString() + : "1"; - const currentPickPoint = selectedPointData?.action.pickUpPoint - ? `${selectedPointData.action.pickUpPoint.x},${selectedPointData.action.pickUpPoint.y},${selectedPointData.action.pickUpPoint.z}` - : ""; + const currentPickPoint = selectedPointData?.action.pickUpPoint + ? `${selectedPointData.action.pickUpPoint.x},${selectedPointData.action.pickUpPoint.y},${selectedPointData.action.pickUpPoint.z}` + : ""; - const currentUnloadPoint = selectedPointData?.action.unLoadPoint - ? `${selectedPointData.action.unLoadPoint.x},${selectedPointData.action.unLoadPoint.y},${selectedPointData.action.unLoadPoint.z}` - : ""; + const currentUnloadPoint = selectedPointData?.action.unLoadPoint + ? `${selectedPointData.action.unLoadPoint.x},${selectedPointData.action.unLoadPoint.y},${selectedPointData.action.unLoadPoint.z}` + : ""; - const availableActions = { - defaultOption: "travel", - options: ["travel"], - }; + const availableActions = { + defaultOption: "travel", + options: ["travel"], + }; - return ( + return ( + <> + {selectedEventData && ( <> - {selectedEventData && - <> -
-
-
- { }} - onChange={handleSpeedChange} - /> -
-
-
+
+
+
+ {}} + onChange={handleSpeedChange} + /> +
+
+
+ +
+
+ +
+
+ -
-
- -
-
- - - {activeOption === 'travel' && - - } -
-
-
- -
- - } + {activeOption === "travel" && ( + + )} +
+
+
+ +
- ) + )} + + ); } -export default VehicleMechanics \ No newline at end of file +export default VehicleMechanics; diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 76d2933..c284c42 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -366,15 +366,66 @@ min-height: 50vh; padding-bottom: 12px; position: relative; - display: flex; - flex-direction: column; + overflow: auto; .sidebar-right-content-container { border-bottom: 1px solid var(--border-color); - // flex: 1; height: calc(100% - 36px); position: relative; - overflow: auto; + width: 320px; + .no-event-selected { + color: #666; + padding: 1.8rem 1rem; + grid-column: 1 / -1; + .products-list { + padding-top: 1rem; + .products-list-title{ + text-align: start; + color: var(--accent-color); + font-size: var(--font-size-regular); + } + ul { + li { + text-align: start; + margin: 8px 0; + padding: 2px 0; + text-decoration: none; + &::marker { + content: ""; + } + button { + width: fit-content; + position: relative; + transition: all 0.2s ease; + @include flex-center; + gap: 4px; + &:before { + content: ""; + position: absolute; + left: 0; + bottom: -4px; + background: var(--accent-color); + height: 1px; + width: 0%; + transition: all 0.3s ease; + } + } + &:hover { + button { + path { + stroke: var(--accent-color); + stroke-width: 1.5px; + } + color: var(--accent-color); + &:before { + width: 100%; + } + } + } + } + } + } + } } } @@ -707,7 +758,7 @@ } .selected-actions-list { margin-bottom: 8px; - .eye-dropper-input-container{ + .eye-dropper-input-container { padding: 6px 12px; .regularDropdown-container { padding: 5px 8px; @@ -798,6 +849,7 @@ @include flex-center; padding: 4px; cursor: grab; + width: 100%; &:active { cursor: grabbing; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index 0d4f98d..1efa2d4 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -776,13 +776,13 @@ border-radius: 6px; overflow: hidden; padding: 4px; - min-width: 150px; .option { padding: 4px 10px; border-radius: #{$border-radius-small}; color: var(--text-color); + text-wrap: nowrap; cursor: pointer; &:hover { @@ -794,8 +794,8 @@ color: #f65648; &:hover { - background-color: #f65648; - color: white; + background-color: #f657484d; + color: #f65648; } } } From 2da211f464b370f73d549e0fe105c20c14fe1762 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Mon, 28 Apr 2025 18:25:25 +0530 Subject: [PATCH 07/30] feat: Enable add button in ActionsList based on multipleAction prop and style disabled state in sidebar --- .../components/ActionsList.tsx | 13 +++++--- app/src/styles/layout/sidebar.scss | 31 +++++++++++-------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx index 56626c8..d009307 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx @@ -116,11 +116,14 @@ const ActionsList: React.FC = ({
Actions
- {multipleAction && ( - - )} + +
Date: Mon, 28 Apr 2025 18:34:50 +0530 Subject: [PATCH 08/30] feat: Conditionally render resize button in ActionsList based on multipleAction prop --- .../eventProperties/components/ActionsList.tsx | 16 +++++++++------- .../mechanics/roboticArmMechanics.tsx | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx index d009307..6d2c3de 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx @@ -184,13 +184,15 @@ const ActionsList: React.FC = ({
)}
- + {multipleAction && ( + + )}
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx index a4ced23..7c20ce5 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -32,7 +32,7 @@ function RoboticArmMechanics() { selectedEventData.data.modelUuid, selectedEventData.selectedPoint ) as RoboticArmPointSchema | undefined; - if (point) { + if (point?.actions) { setSelectedPointData(point); setActiveOption( point.actions[0].actionType as "default" | "pickAndPlace" From 7282107cd57dbbafc84023469252a9bf9df24504 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Mon, 28 Apr 2025 18:50:11 +0530 Subject: [PATCH 09/30] feat: Enhance Trigger component with rename functionality and resize option --- .../eventProperties/trigger/Trigger.tsx | 140 +++++++++++------- 1 file changed, 86 insertions(+), 54 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx index f87a852..3b2549a 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx @@ -1,11 +1,19 @@ -import React, { useState } from "react"; -import { AddIcon, RemoveIcon } from "../../../../../icons/ExportCommonIcons"; +import React, { useRef, useState } from "react"; +import { + AddIcon, + RemoveIcon, + ResizeHeightIcon, +} from "../../../../../icons/ExportCommonIcons"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; +import RenameInput from "../../../../../ui/inputs/RenameInput"; +import { handleResize } from "../../../../../../functions/handleResizePannel"; const Trigger: React.FC = () => { // State to hold the list of triggers - const [triggers, setTriggers] = useState([]); + const [triggers, setTriggers] = useState(["Trigger 1"]); + const [selectedTrigger, setSelectedTrigger] = useState("Trigger 1"); const [activeOption, setActiveOption] = useState("onComplete"); + const triggersContainerRef = useRef(null); // States for dropdowns const [triggeredModel, setTriggeredModel] = useState([]); @@ -44,61 +52,85 @@ const Trigger: React.FC = () => {
- {/* Map over triggers and render them */} - {triggers.map((trigger, index) => ( -
-
- {trigger} - + + {triggers.length > 1 && ( + + )} +
+ ))} +
+ +
+
+
{selectedTrigger}
+ setActiveOption(option)} + /> +
+
+ { + const newModel = [...triggeredModel]; + newModel[0] = option; + setTriggeredModel(newModel); + }} + />
- setActiveOption(option)} - /> -
-
- { - const newModel = [...triggeredModel]; - newModel[index] = option; - setTriggeredModel(newModel); - }} - /> -
-
- { - const newPoint = [...triggeredPoint]; - newPoint[index] = option; - setTriggeredPoint(newPoint); - }} - /> -
-
- { - const newAction = [...triggeredAction]; - newAction[index] = option; - setTriggeredAction(newAction); - }} - /> -
+
+ { + const newPoint = [...triggeredPoint]; + newPoint[0] = option; + setTriggeredPoint(newPoint); + }} + /> +
+
+ { + const newAction = [...triggeredAction]; + newAction[0] = option; + setTriggeredAction(newAction); + }} + />
- ))} +
); From 4b4fe53ee483764581e90e4c58f432aad18727c7 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Mon, 28 Apr 2025 18:51:16 +0530 Subject: [PATCH 10/30] play-pause-rest actions --- .../ui/simulation/simulationPlayer.tsx | 1 + .../armInstance/roboticArmInstance.tsx | 12 +- .../instances/animator/vehicleAnimator.tsx | 262 +++++++++--------- .../instances/instance/vehicleInstance.tsx | 20 +- .../modules/simulation/vehicle/vehicles.tsx | 9 +- 5 files changed, 160 insertions(+), 144 deletions(-) diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index 528fbc2..fb59d3a 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -21,6 +21,7 @@ const SimulationPlayer: React.FC = () => { // Button functions const handleReset = () => { setReset(true); + // setReset(!isReset); setSpeed(1); }; const handlePlayStop = () => { diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 86eee6a..399962e 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -66,7 +66,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { } //Waiting for trigger. else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && !robot.currentAction) { - console.log("trigger"); + setTimeout(() => { addCurrentAction(robot.modelUuid, 'action-003'); }, 3000); @@ -133,28 +133,28 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { const HandleCallback = () => { if (robot.isActive && robot.state == "running" && currentPhase == "init-to-rest") { - console.log("Callback triggered: rest"); + setArmBotActive(robot.modelUuid, false) setArmBotState(robot.modelUuid, "idle") setCurrentPhase("rest"); setPath([]) } else if (robot.isActive && robot.state == "running" && currentPhase == "rest-to-start") { - console.log("Callback triggered: pick."); + setArmBotActive(robot.modelUuid, false) setArmBotState(robot.modelUuid, "idle") setCurrentPhase("picking"); setPath([]) } else if (robot.isActive && robot.state == "running" && currentPhase == "start-to-end") { - console.log("Callback triggered: drop."); + setArmBotActive(robot.modelUuid, false) setArmBotState(robot.modelUuid, "idle") setCurrentPhase("dropping"); setPath([]) } else if (robot.isActive && robot.state == "running" && currentPhase == "end-to-rest") { - console.log("Callback triggered: rest, cycle completed."); + setArmBotActive(robot.modelUuid, false) setArmBotState(robot.modelUuid, "idle") setCurrentPhase("rest"); @@ -163,7 +163,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { } } const logStatus = (id: string, status: string) => { - console.log(id +","+ status); + } return ( diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index dbc5064..1d21468 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -1,10 +1,11 @@ import { useEffect, useRef, useState } from 'react' import { useFrame, useThree } from '@react-three/fiber'; -import { useFloorItems } from '../../../../../store/store'; +import { useActiveTool, useFloorItems } from '../../../../../store/store'; import * as THREE from 'three'; import { Line } from '@react-three/drei'; -import { useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; +import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; +import useModuleStore from '../../../../../store/useModuleStore'; interface VehicleAnimatorProps { path: [number, number, number][]; @@ -18,8 +19,10 @@ interface VehicleAnimatorProps { function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) { const { decrementVehicleLoad, vehicles } = useVehicleStore(); const { isPaused } = usePauseButtonStore(); + const { isPlaying, setIsPlaying } = usePlayButtonStore(); + const { activeModule } = useModuleStore(); const { speed } = useAnimationPlaySpeed(); - const { isReset } = useResetButtonStore(); + const { isReset, setReset } = useResetButtonStore(); const [restRotation, setRestingRotation] = useState(true); const [progress, setProgress] = useState(0); const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); @@ -30,6 +33,12 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai let startTime: number; let pausedTime: number; let fixedInterval: number; + let coveredDistance = progressRef.current; + let accumulatedDistance = 0; + let index = 0; + const isPausedRef = useRef(false); + const pauseTimeRef = useRef(null); + useEffect(() => { if (currentPhase === 'stationed-pickup' && path.length > 0) { @@ -45,118 +54,52 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai setProgress(0); completedRef.current = false; }, [currentPath]); - // useEffect(() => { - // console.log('isReset: ', isReset); - // if (isReset) { - // reset(); - // setCurrentPath([]); - // setProgress(0); - // completedRef.current = false; - // decrementVehicleLoad(agvDetail.modelUuid, 0) - // } - // }, [isReset]) - - // useFrame((_, delta) => { - // const object = scene.getObjectByProperty('uuid', agvUuid); - // if (!object || currentPath.length < 2) return; - // if (isPaused) return; - - // let totalDistance = 0; - // const distances = []; - - // for (let i = 0; i < currentPath.length - 1; i++) { - // const start = new THREE.Vector3(...currentPath[i]); - // const end = new THREE.Vector3(...currentPath[i + 1]); - // const segmentDistance = start.distanceTo(end); - // distances.push(segmentDistance); - // totalDistance += segmentDistance; - // } - - // let coveredDistance = progressRef.current; - // let accumulatedDistance = 0; - // let index = 0; - - // while ( - // index < distances.length && - // coveredDistance > accumulatedDistance + distances[index] - // ) { - // accumulatedDistance += distances[index]; - // index++; - // } - - // if (index < distances.length) { - // const start = new THREE.Vector3(...currentPath[index]); - // const end = new THREE.Vector3(...currentPath[index + 1]); - // const segmentDistance = distances[index]; - - // const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); - // const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); - // const rotationSpeed = 2.0; - // const currentAngle = object.rotation.y; - - // let angleDifference = targetAngle - currentAngle; - // if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; - // if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; - - // const maxRotationStep = rotationSpeed * delta; - // object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); - - // const isAligned = Math.abs(angleDifference) < 0.01; - - // if (isAligned) { - // progressRef.current += delta * (speed * agvDetail.speed); - // coveredDistance = progressRef.current; - - // const t = (coveredDistance - accumulatedDistance) / segmentDistance; - // const position = start.clone().lerp(end, t); - // object.position.copy(position); - // } - // } - - // if (progressRef.current >= totalDistance) { - // if (restRotation) { - // const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); - // object.quaternion.slerp(targetQuaternion, delta * 2); - // const angleDiff = object.quaternion.angleTo(targetQuaternion); - // if (angleDiff < 0.01) { - // let objectRotation = agvDetail.point.rotation - // object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); - // setRestingRotation(false); - // } - // return; - // } - // } - - // if (progressRef.current >= totalDistance) { - // setRestingRotation(true); - // progressRef.current = 0; - // movingForward.current = !movingForward.current; - // setCurrentPath([]); - // handleCallBack(); - // if (currentPhase === 'pickup-drop') { - // requestAnimationFrame(firstFrame); - // } - // } - // }); useEffect(() => { - console.log('isReset: ', isReset); if (isReset) { reset(); setCurrentPath([]); setProgress(0); - progressRef.current = 0; completedRef.current = false; movingForward.current = true; - setRestingRotation(false); + progressRef.current = 0; + startTime = 0; + coveredDistance = 0; + setReset(false); + setRestingRotation(true); decrementVehicleLoad(agvDetail.modelUuid, 0); - console.log('agvDetail: ', vehicles); + const object = scene.getObjectByProperty('uuid', agvUuid); + if (object) { + object.position.set(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]); + let objectRotation = agvDetail.point.rotation + object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + } } - }, [isReset]); + }, [isReset]) + + useEffect(() => { + console.log('isPlaying: ', isPlaying); + if (!isPlaying) { + reset(); + setCurrentPath([]); + setProgress(0); + completedRef.current = false; + movingForward.current = true; + progressRef.current = 0; + startTime = 0; + coveredDistance = 0; + setReset(false); + setRestingRotation(true); + decrementVehicleLoad(agvDetail.modelUuid, 0); + const object = scene.getObjectByProperty('uuid', agvUuid); + if (object) { + object.position.set(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]) + let objectRotation = agvDetail.point.rotation + object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + } + } + }, [isPlaying]) useFrame((_, delta) => { - // If reset is active, don't run anything in frame - if (isReset) return; - const object = scene.getObjectByProperty('uuid', agvUuid); if (!object || currentPath.length < 2) return; if (isPaused) return; @@ -172,11 +115,11 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai totalDistance += segmentDistance; } - let coveredDistance = progressRef.current; - let accumulatedDistance = 0; - let index = 0; - while (index < distances.length && coveredDistance > accumulatedDistance + distances[index]) { + while ( + index < distances.length && + coveredDistance > accumulatedDistance + distances[index] + ) { accumulatedDistance += distances[index]; index++; } @@ -188,17 +131,16 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); + + const rotationSpeed = speed; const currentAngle = object.rotation.y; let angleDifference = targetAngle - currentAngle; if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; - const rotationSpeed = 2.0; const maxRotationStep = rotationSpeed * delta; - const rotationStep = Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); - object.rotation.y += rotationStep; - + object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); const isAligned = Math.abs(angleDifference) < 0.01; if (isAligned) { @@ -217,46 +159,104 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai object.quaternion.slerp(targetQuaternion, delta * 2); const angleDiff = object.quaternion.angleTo(targetQuaternion); if (angleDiff < 0.01) { - const objectRotation = agvDetail.point.rotation; + let objectRotation = agvDetail.point.rotation object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); setRestingRotation(false); } - } else { - setRestingRotation(true); - progressRef.current = 0; - movingForward.current = !movingForward.current; - setCurrentPath([]); - handleCallBack(); - if (currentPhase === 'pickup-drop') { - requestAnimationFrame(firstFrame); - } + return; + } + } + + if (progressRef.current >= totalDistance) { + setRestingRotation(true); + progressRef.current = 0; + movingForward.current = !movingForward.current; + setCurrentPath([]); + handleCallBack(); + if (currentPhase === 'pickup-drop') { + requestAnimationFrame(firstFrame); } } }); + let pauseTime: number = 0; + + + useEffect(() => { + // Update the pause state in the ref + isPausedRef.current = isPaused; + }, [isPaused]); function firstFrame() { const unLoadDuration = agvDetail.point.action.unLoadDuration; const droppedMaterial = agvDetail.currentLoad; - fixedInterval = (unLoadDuration / droppedMaterial) * 1000; + fixedInterval = ((unLoadDuration / droppedMaterial) * 1000) / speed; + // fixedInterval = (unLoadDuration / droppedMaterial) * 1000; startTime = performance.now(); step(droppedMaterial); } function step(droppedMaterial: number) { - const elapsedTime = (performance.now() - startTime) * speed; + if (isPausedRef.current) { + // Handle pause logic + if (!pauseTimeRef.current) { + pauseTimeRef.current = performance.now(); // Set pause time only once + } + requestAnimationFrame(() => step(droppedMaterial)); // Continue calling step during pause + return; + } + + if (pauseTimeRef.current) { + // Adjust start time after resuming from pause + const pauseDuration = performance.now() - pauseTimeRef.current; + startTime += pauseDuration; + pauseTimeRef.current = null; // Clear pause time + } + + const elapsedTime = performance.now() - startTime; // Calculate elapsed time + if (elapsedTime >= fixedInterval) { - console.log('fixedInterval: ', fixedInterval); - console.log('elapsedTime: ', elapsedTime); + + let droppedMat = droppedMaterial - 1; - decrementVehicleLoad(agvDetail.modelUuid, 1); - if (droppedMat === 0) return; - startTime = performance.now(); - requestAnimationFrame(() => step(droppedMat)); + decrementVehicleLoad(agvDetail.modelUuid, 1); // Decrement vehicle load + + if (droppedMat > 0) { + // Reset start time for the next step + startTime = performance.now(); + requestAnimationFrame(() => step(droppedMat)); // Continue with the next step + } else { + + return; // Exit when all materials are dropped + } } else { - requestAnimationFrame(() => step(droppedMaterial)); + requestAnimationFrame(() => step(droppedMaterial)); // Continue animation } } + + // function firstFrame() { + // const unLoadDuration = agvDetail.point.action.unLoadDuration; + // const droppedMaterial = agvDetail.currentLoad; + // fixedInterval = (unLoadDuration / droppedMaterial) * 1000; + // startTime = performance.now(); + // step(droppedMaterial); + // } + + // function step(droppedMaterial: number) { + // const elapsedTime = (performance.now() - startTime) * speed; + // if (elapsedTime >= fixedInterval) { + // + // + // let droppedMat = droppedMaterial - 1; + // decrementVehicleLoad(agvDetail.modelUuid, 1); + // if (droppedMat === 0) return; + // startTime = performance.now(); + // requestAnimationFrame(() => step(droppedMat)); + // } else { + // requestAnimationFrame(() => step(droppedMaterial)); + // } + // } + return ( <> {currentPath.length > 0 && ( diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 44a8ad8..a78101e 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -29,17 +29,27 @@ function VehicleInstance({ agvDetail }: any) { [navMesh] ); - function vehicleStatus(modelid: string, status: string) { - // console.log(`AGV ${modelid}: ${status}`); + function vehicleStatus(modelId: string, status: string) { + // console.log(`AGV ${modelId}: ${status}`); } + // Function to reset everything function reset() { - console.log("runs"); + setCurrentPhase('stationed'); setVehicleActive(agvDetail.modelUuid, false); setVehicleState(agvDetail.modelUuid, 'idle'); setPath([]); - setCurrentPhase('stationed') } + // useEffect(() => { + // console.log('isReset: ', isReset); + // if (isReset) { + // reset(); + // } + // }, [isReset]); + + + + useEffect(() => { if (isPlaying) { if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { @@ -90,6 +100,8 @@ function VehicleInstance({ agvDetail }: any) { setCurrentPhase('drop-pickup'); vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); } + } else { + reset() } }, [vehicles, currentPhase, path, isPlaying, isReset]); diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index f0b4d17..1b05888 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -2,11 +2,12 @@ import React, { useEffect } from 'react' import VehicleInstances from './instances/vehicleInstances'; import { useVehicleStore } from '../../../store/simulation/useVehicleStore'; import { useFloorItems } from '../../../store/store'; - +import { useSelectedEventSphere } from '../../../store/simulation/useSimulationStore'; +import * as THREE from "three" function Vehicles() { const { vehicles, addVehicle } = useVehicleStore(); - + const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere(); const { floorItems } = useFloorItems(); const vehicleStatusSample: VehicleEventSchema[] = [ @@ -95,7 +96,9 @@ function Vehicles() { ] } } - }, { + }, + + { modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79", modelName: "forklift", position: [98.85729337188162, 0, 38.36616546567653], From 2f65ee6a71747574301ab76df1230ca0001bd096 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 29 Apr 2025 09:29:18 +0530 Subject: [PATCH 11/30] feat: Implement handleAddEventToProduct function and integrate it into EventProperties and Simulations components --- .../eventProperties/EventProperties.tsx | 20 +- .../sidebarRight/simulation/Simulations.tsx | 342 +++++++++--------- .../functions/handleAddEventToProduct.ts | 28 ++ 3 files changed, 223 insertions(+), 167 deletions(-) create mode 100644 app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 847d035..87d3bf6 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from "react"; import { + useSelectedAsset, useSelectedEventData, useSelectedEventSphere, useSelectedProduct, @@ -11,6 +12,7 @@ import RoboticArmMechanics from "./mechanics/roboticArmMechanics"; import MachineMechanics from "./mechanics/machineMechanics"; import StorageMechanics from "./mechanics/storageMechanics"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import { handleAddEventToProduct } from "../../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; const EventProperties: React.FC = () => { const { selectedEventData } = useSelectedEventData(); @@ -20,8 +22,10 @@ const EventProperties: React.FC = () => { null ); const [assetType, setAssetType] = useState(null); - const { products } = useProductStore(); + const { products, addEvent } = useProductStore(); const { selectedEventSphere } = useSelectedEventSphere(); + + const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); useEffect(() => { const event = getCurrentEventData(); setCurrentEventData(event); @@ -91,7 +95,19 @@ const EventProperties: React.FC = () => {
    {products.map((product) => (
  • - diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index 926ce44..b037098 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -1,204 +1,216 @@ import React, { useEffect, useRef } from "react"; import { - AddIcon, - ArrowIcon, - RemoveIcon, - ResizeHeightIcon, + AddIcon, + ArrowIcon, + RemoveIcon, + ResizeHeightIcon, } from "../../../icons/ExportCommonIcons"; import RenameInput from "../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../functions/handleResizePannel"; -import { useSelectedAsset, useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; +import { + useSelectedAsset, + useSelectedProduct, +} from "../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { generateUUID } from "three/src/math/MathUtils"; import RenderOverlay from "../../../templates/Overlay"; import EditWidgetOption from "../../../ui/menu/EditWidgetOption"; import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi"; +import { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; interface Event { - pathName: string; + pathName: string; } interface ListProps { - val: Event; + val: Event; } const List: React.FC = ({ val }) => { - return ( -
    -
    - {val.pathName} -
    -
    - ); + return ( +
    +
    {val.pathName}
    +
    + ); }; const Simulations: React.FC = () => { - const productsContainerRef = useRef(null); - const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent } = useProductStore(); - const { selectedProduct, setSelectedProduct } = useSelectedProduct(); - const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); + const productsContainerRef = useRef(null); + const { + products, + addProduct, + removeProduct, + renameProduct, + addEvent, + removeEvent, + } = useProductStore(); + const { selectedProduct, setSelectedProduct } = useSelectedProduct(); + const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); - const handleAddProduct = () => { - addProduct(`Product ${products.length + 1}`, generateUUID()); - }; + const handleAddProduct = () => { + addProduct(`Product ${products.length + 1}`, generateUUID()); + }; - const handleRemoveProduct = (productId: string) => { - const currentIndex = products.findIndex(p => p.productId === productId); - const isSelected = selectedProduct.productId === productId; + const handleRemoveProduct = (productId: string) => { + const currentIndex = products.findIndex((p) => p.productId === productId); + const isSelected = selectedProduct.productId === productId; - const updatedProducts = products.filter(p => p.productId !== productId); + const updatedProducts = products.filter((p) => p.productId !== productId); - if (isSelected) { - if (updatedProducts.length > 0) { - let newSelectedIndex = currentIndex; - if (currentIndex >= updatedProducts.length) { - newSelectedIndex = updatedProducts.length - 1; - } - setSelectedProduct( - updatedProducts[newSelectedIndex].productId, - updatedProducts[newSelectedIndex].productName - ); - } else { - setSelectedProduct('', ''); - } + if (isSelected) { + if (updatedProducts.length > 0) { + let newSelectedIndex = currentIndex; + if (currentIndex >= updatedProducts.length) { + newSelectedIndex = updatedProducts.length - 1; } + setSelectedProduct( + updatedProducts[newSelectedIndex].productId, + updatedProducts[newSelectedIndex].productName + ); + } else { + setSelectedProduct("", ""); + } + } - removeProduct(productId); - }; + removeProduct(productId); + }; - const handleRenameProduct = (productId: string, newName: string) => { - renameProduct(productId, newName); - if (selectedProduct.productId === productId) { - setSelectedProduct(productId, newName); - } - }; + const handleRenameProduct = (productId: string, newName: string) => { + renameProduct(productId, newName); + if (selectedProduct.productId === productId) { + setSelectedProduct(productId, newName); + } + }; - const handleAddEventToProduct = () => { - if (selectedAsset) { - addEvent(selectedProduct.productId, selectedAsset); - // upsertProductOrEventApi({ - // productName: selectedProduct.productName, - // productId: selectedProduct.productId, - // eventDatas: selectedAsset - // }); - clearSelectedAsset(); - } - }; + const handleRemoveEventFromProduct = () => { + if (selectedAsset) { + removeEvent(selectedProduct.productId, selectedAsset.modelUuid); + clearSelectedAsset(); + } + }; - const handleRemoveEventFromProduct = () => { - if (selectedAsset) { - removeEvent(selectedProduct.productId, selectedAsset.modelUuid); - clearSelectedAsset(); - } - }; + const selectedProductData = products.find( + (product) => product.productId === selectedProduct.productId + ); - const selectedProductData = products.find( - (product) => product.productId === selectedProduct.productId - ); - - const events: Event[] = selectedProductData?.eventDatas.map((event) => ({ - pathName: event.modelName, + const events: Event[] = + selectedProductData?.eventDatas.map((event) => ({ + pathName: event.modelName, })) || []; - return ( -
    -
    Simulations
    -
    -
    -
    -
    Products
    -
    - Add -
    -
    -
    -
    - {products.map((product, index) => ( -
    -
    setSelectedProduct(product.productId, product.productName)} - > - - handleRenameProduct(product.productId, newName)} - /> -
    - {products.length > 1 && ( -
    handleRemoveProduct(product.productId)} - > - -
    - )} -
    - ))} -
    -
    handleResize(e, productsContainerRef)} - > - -
    -
    -
    - -
    -
    -
    Events
    -
    - -
    -
    - {events.map((event, index) => ( - - ))} -
    - -
    -
    - Need to Compare Layout? -
    -
    - Click 'Compare' to review and analyze the layout differences between them. -
    -
    - -
    -
    + return ( +
    +
    Simulations
    +
    +
    +
    +
    Products
    +
    + Add
    - - {selectedAsset && - - { - if (option === 'Add to Product') { - handleAddEventToProduct(); - } else { - handleRemoveEventFromProduct(); - } - }} +
    +
    +
    + {products.map((product, index) => ( +
    +
    + setSelectedProduct(product.productId, product.productName) + } + > + - - } + + handleRenameProduct(product.productId, newName) + } + /> +
    + {products.length > 1 && ( +
    handleRemoveProduct(product.productId)} + > + +
    + )} +
    + ))} +
    +
    handleResize(e, productsContainerRef)} + > + +
    +
    - ); + +
    +
    +
    Events
    +
    + +
    +
    + {events.map((event, index) => ( + + ))} +
    + +
    +
    + Need to Compare Layout? +
    +
    + Click 'Compare' to review and analyze the layout + differences between them. +
    +
    + +
    +
    +
    + + {selectedAsset && ( + + { + if (option === "Add to Product") { + handleAddEventToProduct({ + selectedAsset, + addEvent, + selectedProduct, + clearSelectedAsset, + }); + } else { + handleRemoveEventFromProduct(); + } + }} + /> + + )} +
    + ); }; export default Simulations; diff --git a/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts b/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts new file mode 100644 index 0000000..7943c1c --- /dev/null +++ b/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts @@ -0,0 +1,28 @@ +interface HandleAddEventToProductParams { + selectedAsset: any; // Replace `any` with specific type if you have it + addEvent: (productId: string, asset: any) => void; + selectedProduct: { + productId: string; + productName: string; + // Add other fields if needed + }; + clearSelectedAsset: () => void; +} + +export const handleAddEventToProduct = ({ + selectedAsset, + addEvent, + selectedProduct, + clearSelectedAsset, +}: HandleAddEventToProductParams) => { + console.log('selectedProduct: ', selectedProduct); + if (selectedAsset) { + addEvent(selectedProduct.productId, selectedAsset); + // upsertProductOrEventApi({ + // productName: selectedProduct.productName, + // productId: selectedProduct.productId, + // eventDatas: selectedAsset + // }); + clearSelectedAsset(); + } +}; From 979f71d43f8c8bdd7dafd6db822275d98e7ca15a Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Tue, 29 Apr 2025 10:18:05 +0530 Subject: [PATCH 12/30] Added vehicle UI --- app/package-lock.json | 66 +-- app/src/assets/gltf-glb/arrow_green.glb | Bin 0 -> 4580 bytes app/src/assets/gltf-glb/arrow_red.glb | Bin 0 -> 4580 bytes app/src/modules/scene/scene.tsx | 45 +- .../events/points/creator/pointsCreator.tsx | 392 ++++++++++-------- .../simulation/ui/vehicle/useDraggableGLTF.ts | 131 ++++++ .../simulation/ui/vehicle/vehicleUI.tsx | 283 +++++++++++++ .../modules/simulation/vehicle/vehicles.tsx | 286 ++++++------- 8 files changed, 817 insertions(+), 386 deletions(-) create mode 100644 app/src/assets/gltf-glb/arrow_green.glb create mode 100644 app/src/assets/gltf-glb/arrow_red.glb create mode 100644 app/src/modules/simulation/ui/vehicle/useDraggableGLTF.ts create mode 100644 app/src/modules/simulation/ui/vehicle/vehicleUI.tsx diff --git a/app/package-lock.json b/app/package-lock.json index fa04c9f..3d5aea4 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -30,7 +30,6 @@ "glob": "^11.0.0", "gsap": "^3.12.5", "html2canvas": "^1.4.1", - "immer": "^10.1.1", "leva": "^0.10.0", "mqtt": "^5.10.4", "postprocessing": "^6.36.4", @@ -2022,7 +2021,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2034,7 +2033,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -4137,26 +4136,6 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@testing-library/dom": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", - "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@testing-library/jest-dom": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", @@ -4268,25 +4247,25 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true + "dev": true }, "node_modules/@turf/along": { "version": "7.2.0", @@ -9040,7 +9019,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true + "dev": true }, "node_modules/cross-env": { "version": "7.0.3", @@ -9917,7 +9896,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.3.1" } @@ -12747,10 +12726,9 @@ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "node_modules/immer": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", - "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", - "license": "MIT", + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -15281,7 +15259,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true + "dev": true }, "node_modules/makeerror": { "version": "1.0.12", @@ -18012,16 +17990,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-dev-utils/node_modules/immer": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, "node_modules/react-dev-utils/node_modules/loader-utils": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", @@ -20759,7 +20727,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "devOptional": true, + "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -20802,7 +20770,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "devOptional": true, + "dev": true, "dependencies": { "acorn": "^8.11.0" }, @@ -20814,7 +20782,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true + "dev": true }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -21310,7 +21278,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true + "dev": true }, "node_modules/v8-to-istanbul": { "version": "8.1.1", @@ -22369,7 +22337,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "engines": { "node": ">=6" } diff --git a/app/src/assets/gltf-glb/arrow_green.glb b/app/src/assets/gltf-glb/arrow_green.glb new file mode 100644 index 0000000000000000000000000000000000000000..8e02527b34c890ef80210fd869ef7fd103ac2cf4 GIT binary patch literal 4580 zcmc&%eOOdg8b5O{AHxj8hoVNJ&|M`L$MK%~eWw&q!7p$K(6x+UfU8Wx49*Nj;%p=7 zqGgHs=wi0XVzn-%rB>`_7{s$in^usmwryr6Nj_V-nps%RzITQZEG?~lp8bQlGv}Q5 z>-YP;@3|~0&(9HB zV3IVYT(Orb&ZLXK`&ODUzy3#i#M zatlkH))Gfyh2knJEOAs+Iu)1S%IM#$u(}ne&06j%R4Qz+u~aE^xt)rAk-Lm480;}u zSyE+l{-js1ag{(Bl$q}T=7KzGD7&=+)~G!Ho{_RUN)>g3HsS&g*aUyqP->oj<9>^r zaw~Wh@O)Mzl$!MNA7KEprmhNW5SiSd@YOX|2Fx45o!4(?B6*R(mNp{{Q9$^Rqvz4kmxt&$YrF^sd zc{b5BhO8@#o!N@pT3&7|$#qmMDzk$qR0S4WUCLBPxx<-hE%ECRfTLNFrda@t=Qs%q zvIxKlqDTueO-n2f+YAd!G|O-@%Sr-=MS&4nmIrPj!TvBohad}QFyf^(6Yo($zC!vz zRR)i$`N%Bh7@(2iG3I4KG-3$Puq+mMmSIJfVE zF$HQlgNGBe6syYN+Sro@;>(v8jOkxcG4nsD7^_wG&xyFmUMIMVhOazz;Jm&mE7mFMX9SmJ8V0~e;P&%3JM0eMi>SER8rL_m^hw+mjjWZ8IhMn8BpXvpa2ah zQ|5RX^hKLk39c0^Nt`HyNI_ngfaFaA4|)bQax&(?NQLnS9$?Myf`N;Q!!#U~uUCy~ z&esFu<>!AIMuvki_&qg3l>_%dpveQj{iC4xUbm7Jcr7&Z0*q>P!Lo3n|IHN!SMW0V z!C{VrK|1&_FGxRfT;RUv8-p6vYcr5be_n%38eI$Ge-GMq4J04)tkbeFUDN{*gX7jS$#qPy~q( zn8QOuYRCuzsm?Sgnv5_EwGyo%qr%sd*;?|m&~Jte+mrJ3*Ufb=#_j1;KHOl<=zRa4 zy{6i8so*Lh#Jf>z^=$OU%wKmd`>TNhkqSWE_@R>~P zz84*Pt^2SBCCpFoo;Vg36CI7b!-k`xNsrE38IIa?4^jvv{~DoV(^e#+hQ(c{Nz`y> z4ca}7MB2k;x1h@Csi8$RL%dNC+j~?_%Ng>Ip=j@X&jX*J_QzqdbpvweXpUsQukpTN z!N^_nHySk4I*iXX zr=aHMokZ`U7mLv&arzk=wEVvD=;`L2P0jIp;#u~c&Fq1uv$u`uS$z7%VN@*4BmHN87erM%&|h1a12gb&E^0ZlrU5PDhs;h%_lblQ>ha!V7ui$XY z@QW>vp4xf`@)6V0e8ib4>fbfVr9zu%2yG1`tz^YG-N7Bi!9Aaze{kuOFWh=zeeW$N zP@3mZJ&A_KLFjM4jgrxGe-}<5uV-2XiI$|i9F30L-5HC#Cu3y-b)Hz7h*rN2#7@6^ zBs#r3D;yQIfZh0Zy*F!<{X1P*rv_cn!pe}W>O^=P^}vVsyat611@qIl7HwY^PDL`(!6@toQljXFy|n~Y*M0C4L*pNxvmZ;C>TLtxV{f(uBl}`(m|92Sf{W5W0+@NHQZndY2}gk82GZrHhO;%O^^2GbKkX zh+Yx@X%hOEz8;+-ZwxOC?&EeQITC4s&DgdKh%x4| zz*Ef)7;HPIpQMI{;K1Nu{!(*@oLF?D&*!roo;=o*@@d}8t+V>_4^Ph6+GOea({_!& z^;@Rtd5Gt)A2ft+#7QXbQ1#KuFAcYU zY%rI0vfCT>f7Cl(K;yQDg~sn`WHRSAO>EJ$HP#NVGw4d(TwlyPSbwUx>8{YwS}DP^ z>!XH{C$V&A&d6=s4&Br6uq`KH=s9M4%$SF2m-U=&+Lu3X;{Cez$9|u_>X>1~p@*x) zb6uIs;`6ml*ziC}?yA1Zz3LY~wZ2h6Cd1nS8~U`Oq`t>m=KA)AvUDdq>pRt zD7Ezz4tqa-MMvb83v})IuBLx_kIek;+mAHbhOo^JU%@x#W9C+hEB zvhjg48_8e!UK9T^ci9ue+g_Nm=)+B`Q^mJB@}F!@>DC{eUUBmg-GK=gUlYq>ZDVQ+ z$;RD%)M^pkOzje0ChI)wd-v|v9yheDnemLlak3+|{mW0b+)UxSDt=e}?DC$rPTzkF z_Kl;@YmdKm@GSj3skTq#4I?9nP>ntcT^PM)(t@0xLhn0sd+%J?tWVQzkGUg;cx1hn a*iSUAU5SRP-R4)J`urv~9N-Adk^cgSWrJG) literal 0 HcmV?d00001 diff --git a/app/src/assets/gltf-glb/arrow_red.glb b/app/src/assets/gltf-glb/arrow_red.glb new file mode 100644 index 0000000000000000000000000000000000000000..02bfea4e3c8da0dde04aa66041f4817b7849bf37 GIT binary patch literal 4580 zcmc&%3s_WT8vbSucNh>C!&HP$XoN7H|J)C$Fd`y`fPm&DgK;>>xGCY4YLb^+XTLMU2vk(oKF^-#IdjhW&;Ngy z_kF+bKQpJgbi5t_PR0UcMFLDLDJ-a`%}%H4qBH90IjT){m|b=Uok8DR<*?iA&ZIfG zBx!85YO7EkNqHj+lNRts&d5u28ofYuIIVUYPG*e^?M|cBg)Y^m4LPSc)e1UeCVlgS z;<5^d*2kEofG4zr)}mM9HUEo@6u?Sy+YMqFll6#8`lJ$>uD`c-{P(n zMb&1TYGfD=6L#2LW|uExT*w$DMk0(T@`@}8BF`vk-Gj0$vkK3$zHrRd=z1n&B&@*l z0^t;fVP#z3^(^23r-+2~81v7WfGed9xjpRF}EB+G;7b*UqW3p$Ig^%{DvLY|Z(!YY%&!`)x z1e}!w6raIjTmhncK&XlDDj?K^s0mwBwx(yF)UVV)PespjSZk~w zd#tC63QO`z^9l=mw9CESV_ELTY;yvT_x$7sERumszLh;3J7 z6jl=CG-4EFMV1AL5K&YV>@Ks=f)zKjndxXk;1xyY6iH?!!eeJi_uJqZPUHkmW<`PJ z($digt8lzTWWuowQ5YVLxO~ykQ**L8+!O0D!e0*i_s?hhu#Yv-1q;g|E?o{vvQ7D> z;y#viBgvs!{74d`!b=kFO)}3aEP@w6QWA+EVn5^s7CSM5Km(8Wl<5kkwg=+ zC}O{sI3h42$IE>p$)gR1AQd7fbD}6+C6Zd$SA%5l`M-`NAyjswnkn{KL-{07Ay8W}s&5ON!&By6;|J)o0 zI$b}no=nhA%8M%iaGegqDF8Hq7agUe!u6mT)Ikj84*!!`-x}l&*G}qTYFONW!P8&w z7jxg?2M#Ro1Q&k~W3%b!VwPOUgolnA?&_SZ_jKs8`b|C95xjib=wYKmf$t25rU`Aq zS#RE}yVS00$gjH-;1To(<(q>6o=Q1ILF2%!i{R5e_!l9e4B(}gD5%~n!`?Ou%9nl~ z(sIY%jz{&-GIY`i<`W7=q)8167XrM{asrYM9nyg*DicopV-%dS=yCw^KWs>ZX_SPww*LIW<>*~gGege5KnY_V|7V}xn*l_O4(^IIvSn(((?SpZTq&= z!2UJS4UcnA?vh?!xotbQe`|9pG&gVF+T4-a`~-QDaNL9gE$JD<@`}ISUzJHevMk7R zE{Nd<8_IX@$5pA#&D-}y9UU`OfLC5wKxHK66z>SJkBFXrXR`i|O(p%Oo#*})<;4WN z7-fV;Pb9TeB)a&7P@)UHb*)T|@YYk%&@i8YHV6wXXS8Gng_jLkG5Ia+Ry({g{;U7D zAv3C%eufX%4-W>z;!PVbZ+ypFdZ_corIc4cF3YPwGgdo)lVlPi5)HwIV9F4@Yk1_5 z?K@^)bHnuiEP1XW11bEbE)hL{>V~Xc;~oGQ_2BBybujb(BO!32{h0({UhzaW{#lYJY0G?;?=5XtClxNTf4^i+v{*8p>)c`-7{_due;7L8|8+_FOZ*M#` z2Ff>GmkaQ8?#VDndgQ1Zl7=H_LpRod=R1-B4WFR>7lK9ttGtWjE3>1aJ=dTBW4c0q z`^3vTHS#kb-@cPNP#++F?WjaE6(rvu(+Fq+kIR~x5YwKVL{T}{#%$4r3URF=2@z2z zYtP&n&pkf&<0Fwv23|Mhvt8`)C}8ppJ@hc;N_R_*z0p6T>z&Bz8c zk~HL_CNTsy#E|)~H_793BU7uUEWKzuN(^%?03pKDa=ttJi}Q`q7fwf{uD7qgxZD6y z&897@LtZ5t$GW%u^|sK?CC`|Pwye1AgU9yyTsPffawkO(Zhv4=-Pyg%ZXeJd`WA_d zu(;Zr?wUGfUE#Kbmz(%ykdpGHO}@Co01^94;TrB*bGUxd0nd2y-j0G{Z968ANtyoU zka%OnfZ%tS2;tJ*qu=kiKV{A9rR$bQ96tmPuR3u4(!{#P+b7h;ouS%VuW!s{?^%AH z_89u#(0I$%<+PiOUjbQGX@y3}ml(TKmjAL_i^tX;kdTp5d zVEScd)GaU0=*(+8H~GH95e@Ghp5L~|_G;MBaPQqw$Ca;NuHNy++xJ#EH=J8my7|pZ zo@1xBT(fP(L3`eD=Y5$`2d8YB_@QXoV@RZW3D!Wpkv=+RaJZfd) [ - { name: "forward", keys: ["ArrowUp", "w", "W"] }, - { name: "backward", keys: ["ArrowDown", "s", "S"] }, - { name: "left", keys: ["ArrowLeft", "a", "A"] }, - { name: "right", keys: ["ArrowRight", "d", "D"] },], - []); + const map = useMemo( + () => [ + { name: "forward", keys: ["ArrowUp", "w", "W"] }, + { name: "backward", keys: ["ArrowDown", "s", "S"] }, + { name: "left", keys: ["ArrowLeft", "a", "A"] }, + { name: "right", keys: ["ArrowRight", "d", "D"] }, + ], + [] + ); - return ( - - { e.preventDefault(); }}> + return ( + + { + e.preventDefault(); + }} + > + - + - + - + - - - - - - - ); + + + + ); } diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index bc2f4db..e503419 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -1,173 +1,237 @@ -import React, { useEffect, useRef, useState } from 'react'; -import * as THREE from 'three'; -import { useEventsStore } from '../../../../../store/simulation/useEventsStore'; -import useModuleStore from '../../../../../store/useModuleStore'; -import { TransformControls } from '@react-three/drei'; -import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys'; -import { useSelectedEventSphere, useSelectedEventData } from '../../../../../store/simulation/useSimulationStore'; +import React, { useEffect, useRef, useState } from "react"; +import * as THREE from "three"; +import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; +import useModuleStore from "../../../../../store/useModuleStore"; +import { TransformControls } from "@react-three/drei"; +import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys"; +import { + useSelectedEventSphere, + useSelectedEventData, +} from "../../../../../store/simulation/useSimulationStore"; function PointsCreator() { - const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore(); - const { activeModule } = useModuleStore(); - const transformRef = useRef(null); - const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); - const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); - const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere(); - const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData(); + const { events, updatePoint, getPointByUuid, getEventByModelUuid } = + useEventsStore(); + const { activeModule } = useModuleStore(); + const transformRef = useRef(null); + const [transformMode, setTransformMode] = useState< + "translate" | "rotate" | null + >(null); + const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); + const { + selectedEventSphere, + setSelectedEventSphere, + clearSelectedEventSphere, + } = useSelectedEventSphere(); + const { setSelectedEventData, clearSelectedEventData } = + useSelectedEventData(); - useEffect(() => { - if (selectedEventSphere) { - const eventData = getEventByModelUuid(selectedEventSphere.userData.modelUuid); - if (eventData) { - setSelectedEventData( - eventData, - selectedEventSphere.userData.pointUuid - ); - } else { - clearSelectedEventData(); - } - } else { - clearSelectedEventData(); - } - }, [selectedEventSphere]); - - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - const keyCombination = detectModifierKeys(e); - if (!selectedEventSphere) return; - if (keyCombination === "G") { - setTransformMode((prev) => (prev === "translate" ? null : "translate")); - } - if (keyCombination === "R") { - setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); - } - }; - - window.addEventListener("keydown", handleKeyDown); - return () => window.removeEventListener("keydown", handleKeyDown); - }, [selectedEventSphere]); - - const updatePointToState = (selectedEventSphere: THREE.Mesh) => { - let point = JSON.parse(JSON.stringify(getPointByUuid(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid))); - if (point) { - point.position = [selectedEventSphere.position.x, selectedEventSphere.position.y, selectedEventSphere.position.z]; - updatePoint(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid, point) - } + useEffect(() => { + if (selectedEventSphere) { + const eventData = getEventByModelUuid( + selectedEventSphere.userData.modelUuid + ); + if (eventData) { + setSelectedEventData(eventData, selectedEventSphere.userData.pointUuid); + } else { + clearSelectedEventData(); + } + } else { + clearSelectedEventData(); } + }, [selectedEventSphere]); - return ( - <> - {activeModule === 'simulation' && - <> - - {events.map((event, i) => { - if (event.type === 'transfer') { - return ( - - {event.points.map((point, j) => ( - (sphereRefs.current[point.uuid] = el!)} - onClick={(e) => { - e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[point.uuid]); - }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} - key={`${i}-${j}`} - position={new THREE.Vector3(...point.position)} - userData={{ modelUuid: event.modelUuid, pointUuid: point.uuid }} - > - - - - ))} - - ); - } else if (event.type === 'vehicle') { - return ( - - (sphereRefs.current[event.point.uuid] = el!)} - onClick={(e) => { - e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[event.point.uuid]); - }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} - position={new THREE.Vector3(...event.point.position)} - userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} - > - - - - - ); - } else if (event.type === 'roboticArm') { - return ( - - (sphereRefs.current[event.point.uuid] = el!)} - onClick={(e) => { - e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[event.point.uuid]); - }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} - position={new THREE.Vector3(...event.point.position)} - userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} - > - - - - - ); - } else if (event.type === 'machine') { - return ( - - (sphereRefs.current[event.point.uuid] = el!)} - onClick={(e) => { - e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[event.point.uuid]); - }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} - position={new THREE.Vector3(...event.point.position)} - userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} - > - - - - - ); - } else { - return null; - } - })} - - {(selectedEventSphere && transformMode) && - { updatePointToState(selectedEventSphere) }} /> - } - - } - + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + const keyCombination = detectModifierKeys(e); + if (!selectedEventSphere) return; + if (keyCombination === "G") { + setTransformMode((prev) => (prev === "translate" ? null : "translate")); + } + if (keyCombination === "R") { + setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [selectedEventSphere]); + + const updatePointToState = (selectedEventSphere: THREE.Mesh) => { + let point = JSON.parse( + JSON.stringify( + getPointByUuid( + selectedEventSphere.userData.modelUuid, + selectedEventSphere.userData.pointUuid + ) + ) ); + if (point) { + point.position = [ + selectedEventSphere.position.x, + selectedEventSphere.position.y, + selectedEventSphere.position.z, + ]; + updatePoint( + selectedEventSphere.userData.modelUuid, + selectedEventSphere.userData.pointUuid, + point + ); + } + }; + + return ( + <> + {activeModule === "simulation" && ( + <> + + {events.map((event, i) => { + if (event.type === "transfer") { + return ( + + {event.points.map((point, j) => ( + (sphereRefs.current[point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[point.uuid] + ); + }} + onPointerMissed={() => { + // clearSelectedEventSphere(); + setTransformMode(null); + }} + key={`${i}-${j}`} + position={new THREE.Vector3(...point.position)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: point.uuid, + }} + > + + + + ))} + + ); + } else if (event.type === "vehicle") { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); + }} + onPointerMissed={() => { + // clearSelectedEventSphere(); + setTransformMode(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: event.point.uuid, + }} + > + + + + + ); + } else if (event.type === "roboticArm") { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); + }} + onPointerMissed={() => { + // clearSelectedEventSphere(); + setTransformMode(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: event.point.uuid, + }} + > + + + + + ); + } else if (event.type === "machine") { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); + }} + onPointerMissed={() => { + // clearSelectedEventSphere(); + setTransformMode(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: event.point.uuid, + }} + > + + + + + ); + } else { + return null; + } + })} + + {selectedEventSphere && transformMode && ( + { + updatePointToState(selectedEventSphere); + }} + /> + )} + + )} + + ); } export default PointsCreator; diff --git a/app/src/modules/simulation/ui/vehicle/useDraggableGLTF.ts b/app/src/modules/simulation/ui/vehicle/useDraggableGLTF.ts new file mode 100644 index 0000000..b7e9272 --- /dev/null +++ b/app/src/modules/simulation/ui/vehicle/useDraggableGLTF.ts @@ -0,0 +1,131 @@ +import { useRef } from "react"; +import * as THREE from "three"; +import { ThreeEvent, useThree } from "@react-three/fiber"; + +type OnUpdateCallback = (object: THREE.Object3D) => void; + +export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { + const { camera, gl, controls, scene } = useThree(); + const activeObjRef = useRef(null); + const planeRef = useRef( + new THREE.Plane(new THREE.Vector3(0, 1, 0), 0) + ); + const offsetRef = useRef(new THREE.Vector3()); + const initialPositionRef = useRef(new THREE.Vector3()); + + const raycaster = new THREE.Raycaster(); + const pointer = new THREE.Vector2(); + + const handlePointerDown = (e: ThreeEvent) => { + e.stopPropagation(); + + let obj: THREE.Object3D | null = e.object; + + // Traverse up until we find modelUuid in userData + while (obj && !obj.userData?.modelUuid) { + obj = obj.parent; + } + + if (!obj) return; + + // Disable orbit controls while dragging + if (controls) (controls as any).enabled = false; + + activeObjRef.current = obj; + initialPositionRef.current.copy(obj.position); + + // Get world position + const objectWorldPos = new THREE.Vector3(); + obj.getWorldPosition(objectWorldPos); + + // Set plane at the object's Y level + planeRef.current.set(new THREE.Vector3(0, 1, 0), -objectWorldPos.y); + + // Convert pointer to NDC + const rect = gl.domElement.getBoundingClientRect(); + pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1; + pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1; + + // Raycast to intersection + raycaster.setFromCamera(pointer, camera); + const intersection = new THREE.Vector3(); + raycaster.ray.intersectPlane(planeRef.current, intersection); + + // Calculate offset + offsetRef.current.copy(objectWorldPos).sub(intersection); + + // Start listening for drag + gl.domElement.addEventListener("pointermove", handlePointerMove); + gl.domElement.addEventListener("pointerup", handlePointerUp); + }; + + const handlePointerMove = (e: PointerEvent) => { + if (!activeObjRef.current) return; + + // Check if Shift key is pressed + const isShiftKeyPressed = e.shiftKey; + + // Get the mouse position relative to the canvas + const rect = gl.domElement.getBoundingClientRect(); + pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1; + pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1; + + // Update raycaster to point to the mouse position + raycaster.setFromCamera(pointer, camera); + + // Create a vector to store intersection point + const intersection = new THREE.Vector3(); + const intersects = raycaster.ray.intersectPlane(planeRef.current, intersection); + if (!intersects) return; + + // Add offset for dragging + intersection.add(offsetRef.current); + console.log('intersection: ', intersection); + + // Get the parent's world matrix if exists + const parent = activeObjRef.current.parent; + const targetPosition = new THREE.Vector3(); + + if (isShiftKeyPressed) { + console.log('isShiftKeyPressed: ', isShiftKeyPressed); + // For Y-axis only movement, maintain original X and Z + console.log('initialPositionRef: ', initialPositionRef); + console.log('intersection.y: ', intersection); + targetPosition.set( + initialPositionRef.current.x, + intersection.y, + initialPositionRef.current.z + ); + } else { + // For free movement + targetPosition.copy(intersection); + } + + // Convert world position to local if object is nested inside a parent + if (parent) { + parent.worldToLocal(targetPosition); + } + + // Update object position + activeObjRef.current.position.copy(targetPosition); + }; + + const handlePointerUp = () => { + if (controls) (controls as any).enabled = true; + + if (activeObjRef.current) { + // Pass the updated position to the onUpdate callback to persist it + onUpdate(activeObjRef.current); + } + + gl.domElement.removeEventListener("pointermove", handlePointerMove); + gl.domElement.removeEventListener("pointerup", handlePointerUp); + + activeObjRef.current = null; + }; + + return { handlePointerDown }; +} + + + diff --git a/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx new file mode 100644 index 0000000..f927c33 --- /dev/null +++ b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx @@ -0,0 +1,283 @@ +import React, { useRef, useEffect, useState } from "react"; +import startPoint from "../../../../assets/gltf-glb/arrow_green.glb"; +import startEnd from "../../../../assets/gltf-glb/arrow_red.glb"; +import { useGLTF } from "@react-three/drei"; +import { useSelectedEventSphere } from "../../../../store/simulation/useSimulationStore"; +import * as THREE from "three"; +import { useThree } from "@react-three/fiber"; + +type VehicleUIProps = { + vehicleStatusSample: VehicleEventSchema[]; + setVehicleStatusSample: React.Dispatch< + React.SetStateAction + >; +}; + +const VehicleUI: React.FC = ({ + vehicleStatusSample, + setVehicleStatusSample, +}) => { + const { scene: startScene } = useGLTF(startPoint) as any; + const { scene: endScene } = useGLTF(startEnd) as any; + const { camera, gl, controls } = useThree(); + const { selectedEventSphere } = useSelectedEventSphere(); + + const startMarker = useRef(null); + const endMarker = useRef(null); + const hasInitialized = useRef(false); + + const [draggedMarker, setDraggedMarker] = useState<"start" | "end" | null>( + null + ); + const [dragOffset, setDragOffset] = useState(null); + const [isRotating, setIsRotating] = useState(false); + + const raycaster = useRef(new THREE.Raycaster()); + const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Y = 0 plane + const mouse = useRef(new THREE.Vector2()); + const prevMousePos = useRef({ x: 0, y: 0 }); + + // Initialize start/end markers + useEffect(() => { + if ( + selectedEventSphere && + startMarker.current && + endMarker.current && + !hasInitialized.current + ) { + startMarker.current.clear(); + endMarker.current.clear(); + + const startClone = startScene.clone(); + const endClone = endScene.clone(); + + startClone.name = "start-marker"; + endClone.name = "end-marker"; + + startClone.traverse((child: any) => { + if (child.isMesh && child.name.toLowerCase().includes("handle")) { + child.name = "handle"; + } + }); + endClone.traverse((child: any) => { + if (child.isMesh && child.name.toLowerCase().includes("handle")) { + child.name = "handle"; + } + }); + + startMarker.current.add(startClone); + endMarker.current.add(endClone); + + hasInitialized.current = true; + } + }, [selectedEventSphere, startScene, endScene]); + + // Position start/end markers + useEffect(() => { + if (!selectedEventSphere || !startMarker.current || !endMarker.current) + return; + + const selectedVehicle = vehicleStatusSample.find( + (vehicle) => vehicle.modelUuid === selectedEventSphere.userData.modelUuid + ); + + if (selectedVehicle?.point?.action) { + const { pickUpPoint, unLoadPoint } = selectedVehicle.point.action; + + // Update start marker position + if (pickUpPoint) { + const localPos = new THREE.Vector3( + pickUpPoint.x, + pickUpPoint.y, + pickUpPoint.z + ); + const worldPos = selectedEventSphere.localToWorld(localPos); + worldPos.y = 0; // Force y to 0 + startMarker.current.position.copy(worldPos); + } else { + const defaultLocal = new THREE.Vector3(0, 0, 1.5); + const defaultWorld = selectedEventSphere.localToWorld(defaultLocal); + defaultWorld.y = 0; // Force y to 0 + startMarker.current.position.copy(defaultWorld); + } + + // Update end marker position + if (unLoadPoint) { + const localPos = new THREE.Vector3( + unLoadPoint.x, + unLoadPoint.y, + unLoadPoint.z + ); + const worldPos = selectedEventSphere.localToWorld(localPos); + worldPos.y = 0; // Force y to 0 + endMarker.current.position.copy(worldPos); + } else { + const defaultLocal = new THREE.Vector3(0, 0, -1.5); + const defaultWorld = selectedEventSphere.localToWorld(defaultLocal); + defaultWorld.y = 0; // Force y to 0 + endMarker.current.position.copy(defaultWorld); + } + } + }, [selectedEventSphere, vehicleStatusSample]); + + // Handle dragging and rotation + const handlePointerDown = (e: any, markerType: "start" | "end") => { + if (!selectedEventSphere) return; + + if (e.object.name === "handle") { + setIsRotating(true); + prevMousePos.current = { x: e.clientX, y: e.clientY }; + if (controls) (controls as any).enabled = false; + e.stopPropagation(); + setDraggedMarker(markerType); + return; + } + + setDraggedMarker(markerType); + if (controls) (controls as any).enabled = false; + + const marker = + markerType === "start" ? startMarker.current : endMarker.current; + if (!marker) return; + + mouse.current.x = (e.clientX / gl.domElement.clientWidth) * 2 - 1; + mouse.current.y = -(e.clientY / gl.domElement.clientHeight) * 2 + 1; + + raycaster.current.setFromCamera(mouse.current, camera); + + const intersectPoint = new THREE.Vector3(); + raycaster.current.ray.intersectPlane(plane.current, intersectPoint); + + const offset = new THREE.Vector3().subVectors( + marker.position, + intersectPoint + ); + setDragOffset(offset); + }; + + const handlePointerMove = (e: PointerEvent) => { + if (!selectedEventSphere) return; + + if (isRotating) { + const deltaX = e.clientX - prevMousePos.current.x; + prevMousePos.current = { x: e.clientX, y: e.clientY }; + + const rotationSpeed = 0.01; + const marker = + draggedMarker === "start" ? startMarker.current : endMarker.current; + + if (marker) { + marker.rotation.y -= deltaX * rotationSpeed; + } + return; + } + + if (!draggedMarker || !dragOffset) return; + + mouse.current.x = (e.clientX / gl.domElement.clientWidth) * 2 - 1; + mouse.current.y = -(e.clientY / gl.domElement.clientHeight) * 2 + 1; + + raycaster.current.setFromCamera(mouse.current, camera); + + const intersectPoint = new THREE.Vector3(); + raycaster.current.ray.intersectPlane(plane.current, intersectPoint); + + if (!intersectPoint) return; + + const newPos = { + x: intersectPoint.x + dragOffset.x, + y: 0, + z: intersectPoint.z + dragOffset.z, + }; + + if (draggedMarker === "start" && startMarker.current) { + startMarker.current.position.set(newPos.x, newPos.y, newPos.z); + } else if (draggedMarker === "end" && endMarker.current) { + endMarker.current.position.set(newPos.x, newPos.y, newPos.z); + } + }; + + const handlePointerUp = () => { + if (isRotating) { + setIsRotating(false); + if (controls) (controls as any).enabled = true; + return; + } + + if (!selectedEventSphere || !draggedMarker || !dragOffset) { + if (controls) (controls as any).enabled = true; + return; + } + + if (controls) (controls as any).enabled = true; + + const marker = + draggedMarker === "start" ? startMarker.current : endMarker.current; + if (!marker) return; + + const worldPos = marker.position.clone(); + const localPos = selectedEventSphere.worldToLocal(worldPos); + + // Direct update (no snapping, ground level forced at y = 0) + const updatedLocalPos = { x: localPos.x, y: 0, z: localPos.z }; + + setVehicleStatusSample((prev) => + prev.map((vehicle) => { + if ( + vehicle.modelUuid === selectedEventSphere.userData.modelUuid && + selectedEventSphere + ) { + const updatedVehicle = { + ...vehicle, + point: { + ...vehicle.point, + action: { + ...vehicle.point?.action, + ...(draggedMarker === "start" + ? { pickUpPoint: updatedLocalPos } + : { unLoadPoint: updatedLocalPos }), + }, + }, + }; + return updatedVehicle; + } + return vehicle; + }) + ); + + setDraggedMarker(null); + setDragOffset(null); + }; + + useEffect(() => { + window.addEventListener("pointermove", handlePointerMove); + window.addEventListener("pointerup", handlePointerUp); + + return () => { + window.removeEventListener("pointermove", handlePointerMove); + window.removeEventListener("pointerup", handlePointerUp); + }; + }, [draggedMarker, dragOffset, isRotating]); + + if (!selectedEventSphere) { + hasInitialized.current = false; + return null; + } + + return ( + + handlePointerDown(e, "start")} + /> + handlePointerDown(e, "end")} + /> + + ); +}; + +export default VehicleUI; diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index f0b4d17..65376f2 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -1,162 +1,140 @@ -import React, { useEffect } from 'react' -import VehicleInstances from './instances/vehicleInstances'; -import { useVehicleStore } from '../../../store/simulation/useVehicleStore'; -import { useFloorItems } from '../../../store/store'; - +import React, { useEffect, useState } from "react"; +import VehicleInstances from "./instances/vehicleInstances"; +import { useVehicleStore } from "../../../store/simulation/useVehicleStore"; +import { useFloorItems } from "../../../store/store"; +import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; +import VehicleUI from "../ui/vehicle/vehicleUI"; function Vehicles() { + const { vehicles, addVehicle } = useVehicleStore(); + const { selectedEventSphere } = useSelectedEventSphere(); - const { vehicles, addVehicle } = useVehicleStore(); + const { floorItems } = useFloorItems(); - const { floorItems } = useFloorItems(); - - const vehicleStatusSample: VehicleEventSchema[] = [ - { - modelUuid: "9356f710-4727-4b50-bdb2-9c1e747ecc74", - modelName: "AGV", - position: [97.9252965204558, 0, 37.96138815638661], - rotation: [0, 0, 0], - state: "idle", - type: "vehicle", - speed: 2.5, - point: { - uuid: "point-789", - position: [0, 1, 0], - rotation: [0, 0, 0], - action: { - actionUuid: "action-456", - actionName: "Deliver to Zone A", - actionType: "travel", - unLoadDuration: 10, - loadCapacity: 2, - pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, - unLoadPoint: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, - triggers: [ - { - triggerUuid: "trig-001", - triggerName: "Start Travel", - triggerType: "onComplete", - delay: 0, - triggeredAsset: { - triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, - triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } - } - }, - { - triggerUuid: "trig-002", - triggerName: "Complete Travel", - triggerType: "onComplete", - delay: 2, - triggeredAsset: null - } - ] - } - } + const [vehicleStatusSample, setVehicleStatusSample] = useState< + VehicleEventSchema[] + >([ + + { + modelUuid: "68f8dc55-7802-47fe-aa1c-eade54b4320a", + modelName: "AGV", + position: [89.61609306554463, 0, 33.634136622267356], + rotation: [0, 0, 0], + state: "idle", + type: "vehicle", + speed: 2.5, + point: { + uuid: "point-789", + position: [0, 1, 0], + rotation: [0, 0, 0], + action: { + actionUuid: "action-456", + actionName: "Deliver to Zone A", + actionType: "travel", + unLoadDuration: 10, + loadCapacity: 2, + pickUpPoint: null, + unLoadPoint: null, + triggers: [ + { + triggerUuid: "trig-001", + triggerName: "Start Travel", + triggerType: "onStart", + delay: 0, + triggeredAsset: { + triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, + triggeredPoint: { + pointName: "Pickup Arm Point", + pointUuid: "arm-point-01", + }, + triggeredAction: { + actionName: "Grab Widget", + actionUuid: "grab-001", + }, + }, + }, + { + triggerUuid: "trig-002", + triggerName: "Complete Travel", + triggerType: "onComplete", + delay: 2, + triggeredAsset: null, + }, + ], }, - { - modelUuid: "b06960bb-3d2e-41f7-a646-335f389c68b4", - modelName: "AGV", - position: [89.61609306554463, 0, 33.634136622267356], - rotation: [0, 0, 0], - state: "idle", - type: "vehicle", - speed: 2.5, - point: { - uuid: "point-789", - position: [0, 1, 0], - rotation: [0, 0, 0], - action: { - actionUuid: "action-456", - actionName: "Deliver to Zone A", - actionType: "travel", - unLoadDuration: 10, - loadCapacity: 2, - pickUpPoint: { x: 90, y: 0, z: 28 }, - unLoadPoint: { x: 20, y: 0, z: 10 }, - triggers: [ - { - triggerUuid: "trig-001", - triggerName: "Start Travel", - triggerType: "onStart", - delay: 0, - triggeredAsset: { - triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, - triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } - } - }, - { - triggerUuid: "trig-002", - triggerName: "Complete Travel", - triggerType: "onComplete", - delay: 2, - triggeredAsset: null - } - ] - } - } - }, { - modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79", - modelName: "forklift", - position: [98.85729337188162, 0, 38.36616546567653], - rotation: [0, 0, 0], - state: "idle", - type: "vehicle", - speed: 2.5, - point: { - uuid: "point-789", - position: [0, 1, 0], - rotation: [0, 0, 0], - action: { - actionUuid: "action-456", - actionName: "Deliver to Zone A", - actionType: "travel", - unLoadDuration: 15, - loadCapacity: 5, - pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, - unLoadPoint: { x: 20, y: 0, z: 10 }, - triggers: [ - { - triggerUuid: "trig-001", - triggerName: "Start Travel", - triggerType: "onStart", - delay: 0, - triggeredAsset: { - triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, - triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } - } - }, - { - triggerUuid: "trig-002", - triggerName: "Complete Travel", - triggerType: "onComplete", - delay: 2, - triggeredAsset: null - } - ] - } - } - } - ]; + }, + }, + { + modelUuid: "3a8f6da6-da57-4ef5-91e3-b8daf89e5753", + modelName: "forklift", + position: [98.85729337188162, 0, 38.36616546567653], + rotation: [0, 0, 0], + state: "idle", + type: "vehicle", + speed: 2.5, + point: { + uuid: "point-789", + position: [0, 1, 0], + rotation: [0, 0, 0], + action: { + actionUuid: "action-456", + actionName: "Deliver to Zone A", + actionType: "travel", + unLoadDuration: 15, + loadCapacity: 5, + pickUpPoint: null, + unLoadPoint: null, + triggers: [ + { + triggerUuid: "trig-001", + triggerName: "Start Travel", + triggerType: "onStart", + delay: 0, + triggeredAsset: { + triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, + triggeredPoint: { + pointName: "Pickup Arm Point", + pointUuid: "arm-point-01", + }, + triggeredAction: { + actionName: "Grab Widget", + actionUuid: "grab-001", + }, + }, + }, + { + triggerUuid: "trig-002", + triggerName: "Complete Travel", + triggerType: "onComplete", + delay: 2, + triggeredAsset: null, + }, + ], + }, + }, + }, + ]); + // useEffect(()) + console.log("vehicleStatusSample", vehicleStatusSample); + useEffect(() => { + addVehicle("123", vehicleStatusSample[0]); + // addVehicle('123', vehicleStatusSample[1]); + // addVehicle('123', vehicleStatusSample[2]); + }, []); + useEffect(() => {}, [vehicles]); - useEffect(() => { - addVehicle('123', vehicleStatusSample[0]); - // addVehicle('123', vehicleStatusSample[1]); - // addVehicle('123', vehicleStatusSample[2]); - }, []) - - useEffect(() => { - console.log('vehicles: ', vehicles); - }, [vehicles]) - - - return ( - <> - - - ) + return ( + <> + + + + ); } -export default Vehicles; \ No newline at end of file +export default Vehicles; + + + From 3e1fc1c91909d5c81a099233f6a91a5f92795623 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Tue, 29 Apr 2025 10:20:58 +0530 Subject: [PATCH 13/30] added pause-play-rest-exit functionality --- .../instances/animator/vehicleAnimator.tsx | 424 ++++++++---------- .../instances/instance/vehicleInstance.tsx | 239 +++++----- .../modules/simulation/vehicle/vehicles.tsx | 3 +- 3 files changed, 300 insertions(+), 366 deletions(-) diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index 1d21468..6e2093e 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -8,270 +8,212 @@ import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore import useModuleStore from '../../../../../store/useModuleStore'; interface VehicleAnimatorProps { - path: [number, number, number][]; - handleCallBack: () => void; - reset: () => void; - currentPhase: string; - agvUuid: number; - agvDetail: any; + path: [number, number, number][]; + handleCallBack: () => void; + reset: () => void; + currentPhase: string; + agvUuid: number; + agvDetail: any; } function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) { - const { decrementVehicleLoad, vehicles } = useVehicleStore(); - const { isPaused } = usePauseButtonStore(); - const { isPlaying, setIsPlaying } = usePlayButtonStore(); - const { activeModule } = useModuleStore(); - const { speed } = useAnimationPlaySpeed(); - const { isReset, setReset } = useResetButtonStore(); - const [restRotation, setRestingRotation] = useState(true); - const [progress, setProgress] = useState(0); - const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); - const { scene } = useThree(); - const progressRef = useRef(0); - const movingForward = useRef(true); - const completedRef = useRef(false); - let startTime: number; - let pausedTime: number; - let fixedInterval: number; - let coveredDistance = progressRef.current; - let accumulatedDistance = 0; - let index = 0; - const isPausedRef = useRef(false); - const pauseTimeRef = useRef(null); + const { decrementVehicleLoad } = useVehicleStore(); + const { isPaused } = usePauseButtonStore(); + const { isPlaying } = usePlayButtonStore(); + const { speed } = useAnimationPlaySpeed(); + const { isReset, setReset } = useResetButtonStore(); + const [restRotation, setRestingRotation] = useState(true); + const [progress, setProgress] = useState(0); + const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); + const { scene } = useThree(); + const progressRef = useRef(0); + const movingForward = useRef(true); + const completedRef = useRef(false); + let startTime: number; + let fixedInterval: number; + let coveredDistance = progressRef.current; + const isPausedRef = useRef(false); + const pauseTimeRef = useRef(null); - useEffect(() => { - if (currentPhase === 'stationed-pickup' && path.length > 0) { - setCurrentPath(path); - } else if (currentPhase === 'pickup-drop' && path.length > 0) { - setCurrentPath(path); - } else if (currentPhase === 'drop-pickup' && path.length > 0) { - setCurrentPath(path); - } - }, [currentPhase, path]); - - useEffect(() => { - setProgress(0); - completedRef.current = false; - }, [currentPath]); - useEffect(() => { - if (isReset) { - reset(); - setCurrentPath([]); - setProgress(0); - completedRef.current = false; - movingForward.current = true; - progressRef.current = 0; - startTime = 0; - coveredDistance = 0; - setReset(false); - setRestingRotation(true); - decrementVehicleLoad(agvDetail.modelUuid, 0); - const object = scene.getObjectByProperty('uuid', agvUuid); - if (object) { - object.position.set(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]); - let objectRotation = agvDetail.point.rotation - object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); - } - } - }, [isReset]) - - useEffect(() => { - console.log('isPlaying: ', isPlaying); - if (!isPlaying) { - reset(); - setCurrentPath([]); - setProgress(0); - completedRef.current = false; - movingForward.current = true; - progressRef.current = 0; - startTime = 0; - coveredDistance = 0; - setReset(false); - setRestingRotation(true); - decrementVehicleLoad(agvDetail.modelUuid, 0); - const object = scene.getObjectByProperty('uuid', agvUuid); - if (object) { - object.position.set(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]) - let objectRotation = agvDetail.point.rotation - object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); - } - } - }, [isPlaying]) - - useFrame((_, delta) => { - const object = scene.getObjectByProperty('uuid', agvUuid); - if (!object || currentPath.length < 2) return; - if (isPaused) return; - - let totalDistance = 0; - const distances = []; - - for (let i = 0; i < currentPath.length - 1; i++) { - const start = new THREE.Vector3(...currentPath[i]); - const end = new THREE.Vector3(...currentPath[i + 1]); - const segmentDistance = start.distanceTo(end); - distances.push(segmentDistance); - totalDistance += segmentDistance; - } - - - while ( - index < distances.length && - coveredDistance > accumulatedDistance + distances[index] - ) { - accumulatedDistance += distances[index]; - index++; - } - - if (index < distances.length) { - const start = new THREE.Vector3(...currentPath[index]); - const end = new THREE.Vector3(...currentPath[index + 1]); - const segmentDistance = distances[index]; - - const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); - const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); - - const rotationSpeed = speed; - const currentAngle = object.rotation.y; - - let angleDifference = targetAngle - currentAngle; - if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; - if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; - - const maxRotationStep = rotationSpeed * delta; - object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); - const isAligned = Math.abs(angleDifference) < 0.01; - - if (isAligned) { - progressRef.current += delta * (speed * agvDetail.speed); - coveredDistance = progressRef.current; - - const t = (coveredDistance - accumulatedDistance) / segmentDistance; - const position = start.clone().lerp(end, t); - object.position.copy(position); - } - } - - if (progressRef.current >= totalDistance) { - if (restRotation) { - const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); - object.quaternion.slerp(targetQuaternion, delta * 2); - const angleDiff = object.quaternion.angleTo(targetQuaternion); - if (angleDiff < 0.01) { - let objectRotation = agvDetail.point.rotation - object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); - setRestingRotation(false); + useEffect(() => { + if (currentPhase === 'stationed-pickup' && path.length > 0) { + setCurrentPath(path); + } else if (currentPhase === 'pickup-drop' && path.length > 0) { + setCurrentPath(path); + } else if (currentPhase === 'drop-pickup' && path.length > 0) { + setCurrentPath(path); } - return; - } - } + }, [currentPhase, path]); - if (progressRef.current >= totalDistance) { - setRestingRotation(true); - progressRef.current = 0; - movingForward.current = !movingForward.current; - setCurrentPath([]); - handleCallBack(); - if (currentPhase === 'pickup-drop') { - requestAnimationFrame(firstFrame); - } - } - }); - let pauseTime: number = 0; + useEffect(() => { + setProgress(0); + completedRef.current = false; + }, [currentPath]); + + useEffect(() => { + if (isReset || !isPlaying) { + reset(); + setCurrentPath([]); + setProgress(0); + completedRef.current = false; + movingForward.current = true; + progressRef.current = 0; + startTime = 0; + coveredDistance = 0; + setReset(false); + setRestingRotation(true); + decrementVehicleLoad(agvDetail.modelUuid, 0); + const object = scene.getObjectByProperty('uuid', agvUuid); + if (object) { + object.position.set(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]); + let objectRotation = agvDetail.point.rotation + object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + } + } + }, [isReset, isPlaying]) + useFrame((_, delta) => { + const object = scene.getObjectByProperty('uuid', agvUuid); + if (!object || currentPath.length < 2) return; + if (isPaused) return; - useEffect(() => { - // Update the pause state in the ref - isPausedRef.current = isPaused; - }, [isPaused]); - function firstFrame() { - const unLoadDuration = agvDetail.point.action.unLoadDuration; - const droppedMaterial = agvDetail.currentLoad; - fixedInterval = ((unLoadDuration / droppedMaterial) * 1000) / speed; - // fixedInterval = (unLoadDuration / droppedMaterial) * 1000; - startTime = performance.now(); - step(droppedMaterial); - } + let totalDistance = 0; + const distances = []; + let accumulatedDistance = 0; + let index = 0; - function step(droppedMaterial: number) { - if (isPausedRef.current) { - // Handle pause logic - if (!pauseTimeRef.current) { - pauseTimeRef.current = performance.now(); // Set pause time only once - } - requestAnimationFrame(() => step(droppedMaterial)); // Continue calling step during pause - return; - } + for (let i = 0; i < currentPath.length - 1; i++) { + const start = new THREE.Vector3(...currentPath[i]); + const end = new THREE.Vector3(...currentPath[i + 1]); + const segmentDistance = start.distanceTo(end); + distances.push(segmentDistance); + totalDistance += segmentDistance; + } - if (pauseTimeRef.current) { - // Adjust start time after resuming from pause - const pauseDuration = performance.now() - pauseTimeRef.current; - startTime += pauseDuration; - pauseTimeRef.current = null; // Clear pause time - } + while (index < distances.length && coveredDistance > accumulatedDistance + distances[index]) { + accumulatedDistance += distances[index]; + index++; + } - const elapsedTime = performance.now() - startTime; // Calculate elapsed time + if (index < distances.length) { + const start = new THREE.Vector3(...currentPath[index]); + const end = new THREE.Vector3(...currentPath[index + 1]); + const segmentDistance = distances[index]; - if (elapsedTime >= fixedInterval) { + const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); + const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); + const rotationSpeed = speed; + const currentAngle = object.rotation.y; - let droppedMat = droppedMaterial - 1; - decrementVehicleLoad(agvDetail.modelUuid, 1); // Decrement vehicle load + let angleDifference = targetAngle - currentAngle; + if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; + if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; - if (droppedMat > 0) { - // Reset start time for the next step + const maxRotationStep = rotationSpeed * delta; + object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); + const isAligned = Math.abs(angleDifference) < 0.01; + + if (isAligned) { + progressRef.current += delta * (speed * agvDetail.speed); + coveredDistance = progressRef.current; + + const t = (coveredDistance - accumulatedDistance) / segmentDistance; + const position = start.clone().lerp(end, t); + object.position.copy(position); + } + } + + if (progressRef.current >= totalDistance) { + if (restRotation) { + const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); + object.quaternion.slerp(targetQuaternion, delta * 2); + const angleDiff = object.quaternion.angleTo(targetQuaternion); + if (angleDiff < 0.01) { + let objectRotation = agvDetail.point.rotation + object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + setRestingRotation(false); + } + return; + } + } + + if (progressRef.current >= totalDistance) { + setRestingRotation(true); + progressRef.current = 0; + movingForward.current = !movingForward.current; + setCurrentPath([]); + handleCallBack(); + if (currentPhase === 'pickup-drop') { + requestAnimationFrame(firstFrame); + } + } + }); + + useEffect(() => { + isPausedRef.current = isPaused; + }, [isPaused]); + + function firstFrame() { + const droppedMaterial = agvDetail.currentLoad; startTime = performance.now(); - requestAnimationFrame(() => step(droppedMat)); // Continue with the next step - } else { - - return; // Exit when all materials are dropped - } - } else { - requestAnimationFrame(() => step(droppedMaterial)); // Continue animation + step(droppedMaterial); + } + + function step(droppedMaterial: number) { + if (isPausedRef.current) { + if (!pauseTimeRef.current) { + pauseTimeRef.current = performance.now(); + } + requestAnimationFrame(() => step(droppedMaterial)); + return; + } + + if (pauseTimeRef.current) { + const pauseDuration = performance.now() - pauseTimeRef.current; + startTime += pauseDuration; + pauseTimeRef.current = null; + } + + const elapsedTime = performance.now() - startTime; + const unLoadDuration = agvDetail.point.action.unLoadDuration; + fixedInterval = ((unLoadDuration / agvDetail.currentLoad) * (1000 / speed)); + + if (elapsedTime >= fixedInterval) { + console.log('elapsedTime: ', elapsedTime); + + let droppedMat = droppedMaterial - 1; + decrementVehicleLoad(agvDetail.modelUuid, 1); + + if (droppedMat > 0) { + startTime = performance.now(); + requestAnimationFrame(() => step(droppedMat)); + } else { + return; + } + } else { + requestAnimationFrame(() => step(droppedMaterial)); + } } - } - // function firstFrame() { - // const unLoadDuration = agvDetail.point.action.unLoadDuration; - // const droppedMaterial = agvDetail.currentLoad; - // fixedInterval = (unLoadDuration / droppedMaterial) * 1000; - // startTime = performance.now(); - // step(droppedMaterial); - // } - - // function step(droppedMaterial: number) { - // const elapsedTime = (performance.now() - startTime) * speed; - // if (elapsedTime >= fixedInterval) { - // - // - // let droppedMat = droppedMaterial - 1; - // decrementVehicleLoad(agvDetail.modelUuid, 1); - // if (droppedMat === 0) return; - // startTime = performance.now(); - // requestAnimationFrame(() => step(droppedMat)); - // } else { - // requestAnimationFrame(() => step(droppedMaterial)); - // } - // } - - return ( - <> - {currentPath.length > 0 && ( + return ( <> - - {currentPath.map((point, index) => ( - - - - - ))} + {currentPath.length > 0 && ( + <> + + {currentPath.map((point, index) => ( + + + + + ))} + + )} - )} - - ); + ); } export default VehicleAnimator; \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index a78101e..3f692d9 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import VehicleAnimator from '../animator/vehicleAnimator'; import * as THREE from 'three'; import { NavMeshQuery } from '@recast-navigation/core'; @@ -7,138 +7,131 @@ import { usePlayButtonStore, useResetButtonStore } from '../../../../../store/us import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; function VehicleInstance({ agvDetail }: any) { - const { navMesh } = useNavMesh(); - const { isPlaying, setIsPlaying } = usePlayButtonStore(); - const { isReset } = useResetButtonStore(); - const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore(); - const [currentPhase, setCurrentPhase] = useState('stationed'); - const [path, setPath] = useState<[number, number, number][]>([]); + const { navMesh } = useNavMesh(); + const { isPlaying } = usePlayButtonStore(); + const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore(); + const [currentPhase, setCurrentPhase] = useState('stationed'); + const [path, setPath] = useState<[number, number, number][]>([]); + let isIncrememtable = useRef(true); - const computePath = useCallback( - (start: any, end: any) => { - try { - const navMeshQuery = new NavMeshQuery(navMesh); - const { path: segmentPath } = navMeshQuery.computePath(start, end); - return ( - segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || [] - ); - } catch { - return []; - } - }, - [navMesh] - ); + const computePath = useCallback( + (start: any, end: any) => { + try { + const navMeshQuery = new NavMeshQuery(navMesh); + const { path: segmentPath } = navMeshQuery.computePath(start, end); + return ( + segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || [] + ); + } catch { + return []; + } + }, + [navMesh] + ); - function vehicleStatus(modelId: string, status: string) { - // console.log(`AGV ${modelId}: ${status}`); - } - // Function to reset everything - function reset() { - setCurrentPhase('stationed'); - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); - setPath([]); - } + function vehicleStatus(modelId: string, status: string) { + console.log(`AGV ${modelId}: ${status}`); + } - // useEffect(() => { - // console.log('isReset: ', isReset); - // if (isReset) { - // reset(); - // } - // }, [isReset]); + // Function to reset everything + function reset() { + setCurrentPhase('stationed'); + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setPath([]); + } - - - useEffect(() => { - if (isPlaying) { - if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { - const toPickupPath = computePath( - new THREE.Vector3(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]), - agvDetail.point.action.pickUpPoint - ); - setPath(toPickupPath); - setVehicleActive(agvDetail.modelUuid, true); - setVehicleState(agvDetail.modelUuid, 'running'); - setCurrentPhase('stationed-pickup'); - vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup'); - return; - } else if ( - !agvDetail.isActive && - agvDetail.state === 'idle' && - currentPhase === 'picking' - ) { - - setTimeout(() => { - incrementVehicleLoad(agvDetail.modelUuid, 2); - }, 5000); - - if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) { - const toDrop = computePath( - agvDetail.point.action.pickUpPoint, - agvDetail.point.action.unLoadPoint - ); - setPath(toDrop); - setVehicleActive(agvDetail.modelUuid, true); - setVehicleState(agvDetail.modelUuid, 'running'); - setCurrentPhase('pickup-drop'); - vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point'); + const increment = () => { + if (isIncrememtable.current) { + console.log('called'); + incrementVehicleLoad(agvDetail.modelUuid, 2); + isIncrememtable.current = false; } - } else if ( - !agvDetail.isActive && - agvDetail.state === 'idle' && - currentPhase === 'dropping' && - agvDetail.currentLoad === 0 - ) { - const dropToPickup = computePath( - agvDetail.point.action.unLoadPoint, - agvDetail.point.action.pickUpPoint - ); - setPath(dropToPickup); - setVehicleActive(agvDetail.modelUuid, true); - setVehicleState(agvDetail.modelUuid, 'running'); - setCurrentPhase('drop-pickup'); - vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); - } - } else { - reset() } - }, [vehicles, currentPhase, path, isPlaying, isReset]); - function handleCallBack() { - if (currentPhase === 'stationed-pickup') { - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); - setCurrentPhase('picking'); - vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material'); - setPath([]); - } else if (currentPhase === 'pickup-drop') { - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); - setCurrentPhase('dropping'); - vehicleStatus(agvDetail.modelUuid, 'Reached drop point'); - setPath([]); - } else if (currentPhase === 'drop-pickup') { - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); - setCurrentPhase('picking'); - setPath([]); - vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete'); + useEffect(() => { + if (isPlaying) { + if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { + const toPickupPath = computePath( + new THREE.Vector3(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]), + agvDetail.point.action.pickUpPoint + ); + setPath(toPickupPath); + setCurrentPhase('stationed-pickup'); + setVehicleState(agvDetail.modelUuid, 'running'); + setVehicleActive(agvDetail.modelUuid, true); + vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup'); + return; + } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'picking') { + + setTimeout(() => { + increment(); + }, 5000); + + if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) { + const toDrop = computePath( + agvDetail.point.action.pickUpPoint, + agvDetail.point.action.unLoadPoint + ); + setPath(toDrop); + setCurrentPhase('pickup-drop'); + setVehicleState(agvDetail.modelUuid, 'running'); + setVehicleActive(agvDetail.modelUuid, true); + vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point'); + } + } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'dropping' && agvDetail.currentLoad === 0) { + const dropToPickup = computePath( + agvDetail.point.action.unLoadPoint, + agvDetail.point.action.pickUpPoint + ); + setPath(dropToPickup); + setCurrentPhase('drop-pickup'); + setVehicleState(agvDetail.modelUuid, 'running'); + setVehicleActive(agvDetail.modelUuid, true); + vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); + + isIncrememtable.current = true; + } + } else { + reset() + } + }, [vehicles, currentPhase, path, isPlaying]); + + function handleCallBack() { + if (currentPhase === 'stationed-pickup') { + setCurrentPhase('picking'); + setVehicleState(agvDetail.modelUuid, 'idle'); + setVehicleActive(agvDetail.modelUuid, false); + vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material'); + setPath([]); + } else if (currentPhase === 'pickup-drop') { + setCurrentPhase('dropping'); + setVehicleState(agvDetail.modelUuid, 'idle'); + setVehicleActive(agvDetail.modelUuid, false); + vehicleStatus(agvDetail.modelUuid, 'Reached drop point'); + setPath([]); + } else if (currentPhase === 'drop-pickup') { + setCurrentPhase('picking'); + setVehicleState(agvDetail.modelUuid, 'idle'); + setVehicleActive(agvDetail.modelUuid, false); + setPath([]); + vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete'); + } } - } - return ( - <> - - - ); + return ( + <> + + + ); } export default VehicleInstance; \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 1b05888..7749bf8 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -97,7 +97,6 @@ function Vehicles() { } } }, - { modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79", modelName: "forklift", @@ -151,7 +150,7 @@ function Vehicles() { }, []) useEffect(() => { - console.log('vehicles: ', vehicles); + // console.log('vehicles: ', vehicles); }, [vehicles]) From dd853a66d409acd8ff2ecaf2a661b9d475374a94 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 29 Apr 2025 10:30:28 +0530 Subject: [PATCH 14/30] feat: Refactor PointsCreator component for improved readability and maintainability --- .../events/points/creator/pointsCreator.tsx | 392 ++++++++++-------- 1 file changed, 228 insertions(+), 164 deletions(-) diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index bc2f4db..39fe257 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -1,173 +1,237 @@ -import React, { useEffect, useRef, useState } from 'react'; -import * as THREE from 'three'; -import { useEventsStore } from '../../../../../store/simulation/useEventsStore'; -import useModuleStore from '../../../../../store/useModuleStore'; -import { TransformControls } from '@react-three/drei'; -import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys'; -import { useSelectedEventSphere, useSelectedEventData } from '../../../../../store/simulation/useSimulationStore'; +import React, { useEffect, useRef, useState } from "react"; +import * as THREE from "three"; +import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; +import useModuleStore from "../../../../../store/useModuleStore"; +import { TransformControls } from "@react-three/drei"; +import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys"; +import { + useSelectedEventSphere, + useSelectedEventData, +} from "../../../../../store/simulation/useSimulationStore"; function PointsCreator() { - const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore(); - const { activeModule } = useModuleStore(); - const transformRef = useRef(null); - const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); - const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); - const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere(); - const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData(); + const { events, updatePoint, getPointByUuid, getEventByModelUuid } = + useEventsStore(); + const { activeModule } = useModuleStore(); + const transformRef = useRef(null); + const [transformMode, setTransformMode] = useState< + "translate" | "rotate" | null + >(null); + const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); + const { + selectedEventSphere, + setSelectedEventSphere, + clearSelectedEventSphere, + } = useSelectedEventSphere(); + const { setSelectedEventData, clearSelectedEventData } = + useSelectedEventData(); - useEffect(() => { - if (selectedEventSphere) { - const eventData = getEventByModelUuid(selectedEventSphere.userData.modelUuid); - if (eventData) { - setSelectedEventData( - eventData, - selectedEventSphere.userData.pointUuid - ); - } else { - clearSelectedEventData(); - } - } else { - clearSelectedEventData(); - } - }, [selectedEventSphere]); - - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - const keyCombination = detectModifierKeys(e); - if (!selectedEventSphere) return; - if (keyCombination === "G") { - setTransformMode((prev) => (prev === "translate" ? null : "translate")); - } - if (keyCombination === "R") { - setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); - } - }; - - window.addEventListener("keydown", handleKeyDown); - return () => window.removeEventListener("keydown", handleKeyDown); - }, [selectedEventSphere]); - - const updatePointToState = (selectedEventSphere: THREE.Mesh) => { - let point = JSON.parse(JSON.stringify(getPointByUuid(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid))); - if (point) { - point.position = [selectedEventSphere.position.x, selectedEventSphere.position.y, selectedEventSphere.position.z]; - updatePoint(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid, point) - } + useEffect(() => { + if (selectedEventSphere) { + const eventData = getEventByModelUuid( + selectedEventSphere.userData.modelUuid + ); + if (eventData) { + setSelectedEventData(eventData, selectedEventSphere.userData.pointUuid); + } else { + clearSelectedEventData(); + } + } else { + clearSelectedEventData(); } + }, [selectedEventSphere]); - return ( - <> - {activeModule === 'simulation' && - <> - - {events.map((event, i) => { - if (event.type === 'transfer') { - return ( - - {event.points.map((point, j) => ( - (sphereRefs.current[point.uuid] = el!)} - onClick={(e) => { - e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[point.uuid]); - }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} - key={`${i}-${j}`} - position={new THREE.Vector3(...point.position)} - userData={{ modelUuid: event.modelUuid, pointUuid: point.uuid }} - > - - - - ))} - - ); - } else if (event.type === 'vehicle') { - return ( - - (sphereRefs.current[event.point.uuid] = el!)} - onClick={(e) => { - e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[event.point.uuid]); - }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} - position={new THREE.Vector3(...event.point.position)} - userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} - > - - - - - ); - } else if (event.type === 'roboticArm') { - return ( - - (sphereRefs.current[event.point.uuid] = el!)} - onClick={(e) => { - e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[event.point.uuid]); - }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} - position={new THREE.Vector3(...event.point.position)} - userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} - > - - - - - ); - } else if (event.type === 'machine') { - return ( - - (sphereRefs.current[event.point.uuid] = el!)} - onClick={(e) => { - e.stopPropagation(); - setSelectedEventSphere(sphereRefs.current[event.point.uuid]); - }} - onPointerMissed={() => { - clearSelectedEventSphere(); - setTransformMode(null); - }} - position={new THREE.Vector3(...event.point.position)} - userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} - > - - - - - ); - } else { - return null; - } - })} - - {(selectedEventSphere && transformMode) && - { updatePointToState(selectedEventSphere) }} /> - } - - } - + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + const keyCombination = detectModifierKeys(e); + if (!selectedEventSphere) return; + if (keyCombination === "G") { + setTransformMode((prev) => (prev === "translate" ? null : "translate")); + } + if (keyCombination === "R") { + setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [selectedEventSphere]); + + const updatePointToState = (selectedEventSphere: THREE.Mesh) => { + let point = JSON.parse( + JSON.stringify( + getPointByUuid( + selectedEventSphere.userData.modelUuid, + selectedEventSphere.userData.pointUuid + ) + ) ); + if (point) { + point.position = [ + selectedEventSphere.position.x, + selectedEventSphere.position.y, + selectedEventSphere.position.z, + ]; + updatePoint( + selectedEventSphere.userData.modelUuid, + selectedEventSphere.userData.pointUuid, + point + ); + } + }; + + return ( + <> + {activeModule === "simulation" && ( + <> + + {events.map((event, i) => { + if (event.type === "transfer") { + return ( + + {event.points.map((point, j) => ( + (sphereRefs.current[point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[point.uuid] + ); + }} + onPointerMissed={() => { + clearSelectedEventSphere(); + setTransformMode(null); + }} + key={`${i}-${j}`} + position={new THREE.Vector3(...point.position)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: point.uuid, + }} + > + + + + ))} + + ); + } else if (event.type === "vehicle") { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); + }} + onPointerMissed={() => { + clearSelectedEventSphere(); + setTransformMode(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: event.point.uuid, + }} + > + + + + + ); + } else if (event.type === "machine") { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); + }} + onPointerMissed={() => { + clearSelectedEventSphere(); + setTransformMode(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: event.point.uuid, + }} + > + + + + + ); + } else if (event.type === "roboticArm") { + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); + }} + onPointerMissed={() => { + clearSelectedEventSphere(); + setTransformMode(null); + }} + position={new THREE.Vector3(...event.point.position)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: event.point.uuid, + }} + > + + + + + ); + } else { + return null; + } + })} + + {selectedEventSphere && transformMode && ( + { + updatePointToState(selectedEventSphere); + }} + /> + )} + + )} + + ); } export default PointsCreator; From ea53af62c49c936968438b6e47d31c7f4afa7c21 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 29 Apr 2025 10:33:30 +0530 Subject: [PATCH 15/30] Refactor vehicle simulation components for improved path handling and state management - Updated PointsCreator component to enhance event data selection and keyboard handling. - Refactored VehicleAnimator to streamline animation logic and reset handling. - Simplified VehicleInstance logic for better clarity and maintainability. - Modified vehicle data structure to include rotation information for pick-up and unload points. - Adjusted TypeScript types to reflect new vehicle point schema with nested position and rotation properties. --- .../mechanics/vehicleMechanics.tsx | 312 ++++++----- .../events/points/creator/pointsCreator.tsx | 56 +- .../instances/animator/vehicleAnimator.tsx | 500 +++++++++--------- .../instances/instance/vehicleInstance.tsx | 212 ++++---- .../modules/simulation/vehicle/vehicles.tsx | 15 +- app/src/types/simulationTypes.d.ts | 6 +- 6 files changed, 538 insertions(+), 563 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index 4524ceb..93fa3c7 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -4,196 +4,182 @@ import RenameInput from "../../../../../ui/inputs/RenameInput"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import Trigger from "../trigger/Trigger"; import { - useSelectedEventData, - useSelectedProduct, + useSelectedEventData, + useSelectedProduct, } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import TravelAction from "../actions/TravelAction"; import ActionsList from "../components/ActionsList"; function VehicleMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "travel">( - "default" - ); - const [selectedPointData, setSelectedPointData] = useState< - VehiclePointSchema | undefined - >(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateEvent, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState<"default" | "travel">( + "default" + ); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateEvent, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData.data.modelUuid, - selectedEventData.selectedPoint - ) as VehiclePointSchema | undefined; + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint + ) as VehiclePointSchema | undefined; - if (point) { - setSelectedPointData(point); - setActiveOption(point.action.actionType as "travel"); - } - } - }, [selectedProduct, selectedEventData, getPointByUuid]); + if (point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "travel"); + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleSpeedChange = (value: string) => { - if (!selectedEventData) return; - updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { - speed: parseFloat(value), - }); - }; + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { + speed: parseFloat(value), + }); + }; - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as "travel"; - setActiveOption(validOption); + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "travel"; + setActiveOption(validOption); - updateAction(selectedPointData.action.actionUuid, { - actionType: validOption, - }); - }; + updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); + }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { actionName: newName }); - }; + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + }; - const handleLoadCapacityChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - loadCapacity: parseFloat(value), - }); - }; + const handleLoadCapacityChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + loadCapacity: parseFloat(value), + }); + }; - const handleUnloadDurationChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - unLoadDuration: parseFloat(value), - }); - }; + const handleUnloadDurationChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + unLoadDuration: parseFloat(value), + }); + }; - const handlePickPointChange = (value: string) => { - if (!selectedPointData) return; - const [x, y, z] = value.split(",").map(Number); - updateAction(selectedPointData.action.actionUuid, { - pickUpPoint: { x, y, z }, - }); - }; + const handlePickPointChange = (value: string) => { + if (!selectedPointData) return; + }; - const handleUnloadPointChange = (value: string) => { - if (!selectedPointData) return; - const [x, y, z] = value.split(",").map(Number); - updateAction(selectedPointData.action.actionUuid, { - unLoadPoint: { x, y, z }, - }); - }; + const handleUnloadPointChange = (value: string) => { + if (!selectedPointData) return; + }; - // Get current values from store - const currentSpeed = - selectedEventData?.data.type === "vehicle" - ? selectedEventData.data.speed.toString() - : "0.5"; + // Get current values from store + const currentSpeed = + selectedEventData?.data.type === "vehicle" + ? selectedEventData.data.speed.toString() + : "0.5"; - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; - const currentLoadCapacity = selectedPointData - ? selectedPointData.action.loadCapacity.toString() - : "1"; + const currentLoadCapacity = selectedPointData + ? selectedPointData.action.loadCapacity.toString() + : "1"; - const currentUnloadDuration = selectedPointData - ? selectedPointData.action.unLoadDuration.toString() - : "1"; + const currentUnloadDuration = selectedPointData + ? selectedPointData.action.unLoadDuration.toString() + : "1"; - const currentPickPoint = selectedPointData?.action.pickUpPoint - ? `${selectedPointData.action.pickUpPoint.x},${selectedPointData.action.pickUpPoint.y},${selectedPointData.action.pickUpPoint.z}` - : ""; + const currentPickPoint = selectedPointData?.action.pickUpPoint; - const currentUnloadPoint = selectedPointData?.action.unLoadPoint - ? `${selectedPointData.action.unLoadPoint.x},${selectedPointData.action.unLoadPoint.y},${selectedPointData.action.unLoadPoint.z}` - : ""; + const currentUnloadPoint = selectedPointData?.action.unLoadPoint; - const availableActions = { - defaultOption: "travel", - options: ["travel"], - }; + const availableActions = { + defaultOption: "travel", + options: ["travel"], + }; - return ( - <> - {selectedEventData && ( + return ( <> -
    -
    -
    - {}} - onChange={handleSpeedChange} - /> -
    -
    -
    - -
    -
    - -
    -
    - + {selectedEventData && ( + <> +
    +
    +
    + { }} + onChange={handleSpeedChange} + /> +
    +
    +
    + +
    +
    + +
    +
    + - {activeOption === "travel" && ( - - )} -
    -
    -
    - -
    + {activeOption === "travel" && ( + + )} +
    +
    +
    + +
    + + )} - )} - - ); + ); } export default VehicleMechanics; diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index 033f2aa..c5025dd 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -15,36 +15,36 @@ function PointsCreator() { const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere(); const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData(); - useEffect(() => { - if (selectedEventSphere) { - const eventData = getEventByModelUuid( - selectedEventSphere.userData.modelUuid - ); - if (eventData) { - setSelectedEventData(eventData, selectedEventSphere.userData.pointUuid); - } else { - clearSelectedEventData(); - } - } else { - clearSelectedEventData(); - } - }, [selectedEventSphere]); + useEffect(() => { + if (selectedEventSphere) { + const eventData = getEventByModelUuid( + selectedEventSphere.userData.modelUuid + ); + if (eventData) { + setSelectedEventData(eventData, selectedEventSphere.userData.pointUuid); + } else { + clearSelectedEventData(); + } + } else { + clearSelectedEventData(); + } + }, [selectedEventSphere]); - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - const keyCombination = detectModifierKeys(e); - if (!selectedEventSphere) return; - if (keyCombination === "G") { - setTransformMode((prev) => (prev === "translate" ? null : "translate")); - } - if (keyCombination === "R") { - setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); - } - }; + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + const keyCombination = detectModifierKeys(e); + if (!selectedEventSphere) return; + if (keyCombination === "G") { + setTransformMode((prev) => (prev === "translate" ? null : "translate")); + } + if (keyCombination === "R") { + setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); + } + }; - window.addEventListener("keydown", handleKeyDown); - return () => window.removeEventListener("keydown", handleKeyDown); - }, [selectedEventSphere]); + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [selectedEventSphere]); const updatePointToState = (selectedEventSphere: THREE.Mesh) => { let point = JSON.parse(JSON.stringify(getPointByUuid(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid))); diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index db484d7..a8cfc39 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -7,269 +7,267 @@ import { useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; interface VehicleAnimatorProps { - path: [number, number, number][]; - handleCallBack: () => void; - reset: () => void; - currentPhase: string; - agvUuid: number; - agvDetail: any; + path: [number, number, number][]; + handleCallBack: () => void; + reset: () => void; + currentPhase: string; + agvUuid: number; + agvDetail: any; } function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) { - const { decrementVehicleLoad, vehicles } = useVehicleStore(); - const { isPaused } = usePauseButtonStore(); - const { speed } = useAnimationPlaySpeed(); - const { isReset } = useResetButtonStore(); - const [restRotation, setRestingRotation] = useState(true); - const [progress, setProgress] = useState(0); - const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); - const { scene } = useThree(); - const progressRef = useRef(0); - const movingForward = useRef(true); - const completedRef = useRef(false); - let startTime: number; - let pausedTime: number; - let fixedInterval: number; + const { decrementVehicleLoad, vehicles } = useVehicleStore(); + const { isPaused } = usePauseButtonStore(); + const { speed } = useAnimationPlaySpeed(); + const { isReset } = useResetButtonStore(); + const [restRotation, setRestingRotation] = useState(true); + const [progress, setProgress] = useState(0); + const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); + const { scene } = useThree(); + const progressRef = useRef(0); + const movingForward = useRef(true); + const completedRef = useRef(false); + let startTime: number; + let pausedTime: number; + let fixedInterval: number; - useEffect(() => { - if (currentPhase === 'stationed-pickup' && path.length > 0) { - setCurrentPath(path); - } else if (currentPhase === 'pickup-drop' && path.length > 0) { - setCurrentPath(path); - } else if (currentPhase === 'drop-pickup' && path.length > 0) { - setCurrentPath(path); - } - }, [currentPhase, path]); - - useEffect(() => { - setProgress(0); - completedRef.current = false; - }, [currentPath]); - // useEffect(() => { - // console.log('isReset: ', isReset); - // if (isReset) { - // reset(); - // setCurrentPath([]); - // setProgress(0); - // completedRef.current = false; - // decrementVehicleLoad(agvDetail.modelUuid, 0) - // } - // }, [isReset]) - - // useFrame((_, delta) => { - // const object = scene.getObjectByProperty('uuid', agvUuid); - // if (!object || currentPath.length < 2) return; - // if (isPaused) return; - - // let totalDistance = 0; - // const distances = []; - - // for (let i = 0; i < currentPath.length - 1; i++) { - // const start = new THREE.Vector3(...currentPath[i]); - // const end = new THREE.Vector3(...currentPath[i + 1]); - // const segmentDistance = start.distanceTo(end); - // distances.push(segmentDistance); - // totalDistance += segmentDistance; - // } - - // let coveredDistance = progressRef.current; - // let accumulatedDistance = 0; - // let index = 0; - - // while ( - // index < distances.length && - // coveredDistance > accumulatedDistance + distances[index] - // ) { - // accumulatedDistance += distances[index]; - // index++; - // } - - // if (index < distances.length) { - // const start = new THREE.Vector3(...currentPath[index]); - // const end = new THREE.Vector3(...currentPath[index + 1]); - // const segmentDistance = distances[index]; - - // const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); - // const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); - // const rotationSpeed = 2.0; - // const currentAngle = object.rotation.y; - - // let angleDifference = targetAngle - currentAngle; - // if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; - // if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; - - // const maxRotationStep = rotationSpeed * delta; - // object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); - - // const isAligned = Math.abs(angleDifference) < 0.01; - - // if (isAligned) { - // progressRef.current += delta * (speed * agvDetail.speed); - // coveredDistance = progressRef.current; - - // const t = (coveredDistance - accumulatedDistance) / segmentDistance; - // const position = start.clone().lerp(end, t); - // object.position.copy(position); - // } - // } - - // if (progressRef.current >= totalDistance) { - // if (restRotation) { - // const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); - // object.quaternion.slerp(targetQuaternion, delta * 2); - // const angleDiff = object.quaternion.angleTo(targetQuaternion); - // if (angleDiff < 0.01) { - // let objectRotation = agvDetail.point.rotation - // object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); - // setRestingRotation(false); - // } - // return; - // } - // } - - // if (progressRef.current >= totalDistance) { - // setRestingRotation(true); - // progressRef.current = 0; - // movingForward.current = !movingForward.current; - // setCurrentPath([]); - // handleCallBack(); - // if (currentPhase === 'pickup-drop') { - // requestAnimationFrame(firstFrame); - // } - // } - // }); - useEffect(() => { - console.log('isReset: ', isReset); - if (isReset) { - reset(); - setCurrentPath([]); - setProgress(0); - progressRef.current = 0; - completedRef.current = false; - movingForward.current = true; - setRestingRotation(false); - decrementVehicleLoad(agvDetail.modelUuid, 0); - console.log('agvDetail: ', vehicles); - } - }, [isReset]); - - useFrame((_, delta) => { - // If reset is active, don't run anything in frame - if (isReset) return; - - const object = scene.getObjectByProperty('uuid', agvUuid); - if (!object || currentPath.length < 2) return; - if (isPaused) return; - - let totalDistance = 0; - const distances = []; - - for (let i = 0; i < currentPath.length - 1; i++) { - const start = new THREE.Vector3(...currentPath[i]); - const end = new THREE.Vector3(...currentPath[i + 1]); - const segmentDistance = start.distanceTo(end); - distances.push(segmentDistance); - totalDistance += segmentDistance; - } - - let coveredDistance = progressRef.current; - let accumulatedDistance = 0; - let index = 0; - - while (index < distances.length && coveredDistance > accumulatedDistance + distances[index]) { - accumulatedDistance += distances[index]; - index++; - } - - if (index < distances.length) { - const start = new THREE.Vector3(...currentPath[index]); - const end = new THREE.Vector3(...currentPath[index + 1]); - const segmentDistance = distances[index]; - - const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); - const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); - const currentAngle = object.rotation.y; - - let angleDifference = targetAngle - currentAngle; - if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; - if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; - - const rotationSpeed = 2.0; - const maxRotationStep = rotationSpeed * delta; - const rotationStep = Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); - object.rotation.y += rotationStep; - - const isAligned = Math.abs(angleDifference) < 0.01; - - if (isAligned) { - progressRef.current += delta * (speed * agvDetail.speed); - coveredDistance = progressRef.current; - - const t = (coveredDistance - accumulatedDistance) / segmentDistance; - const position = start.clone().lerp(end, t); - object.position.copy(position); - } - } - - if (progressRef.current >= totalDistance) { - if (restRotation) { - const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); - object.quaternion.slerp(targetQuaternion, delta * 2); - const angleDiff = object.quaternion.angleTo(targetQuaternion); - if (angleDiff < 0.01) { - const objectRotation = agvDetail.point.rotation; - object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); - setRestingRotation(false); + useEffect(() => { + if (currentPhase === 'stationed-pickup' && path.length > 0) { + setCurrentPath(path); + } else if (currentPhase === 'pickup-drop' && path.length > 0) { + setCurrentPath(path); + } else if (currentPhase === 'drop-pickup' && path.length > 0) { + setCurrentPath(path); } - } else { - setRestingRotation(true); - progressRef.current = 0; - movingForward.current = !movingForward.current; - setCurrentPath([]); - handleCallBack(); - if (currentPhase === 'pickup-drop') { - requestAnimationFrame(firstFrame); + }, [currentPhase, path]); + + useEffect(() => { + setProgress(0); + completedRef.current = false; + }, [currentPath]); + // useEffect(() => { + // console.log('isReset: ', isReset); + // if (isReset) { + // reset(); + // setCurrentPath([]); + // setProgress(0); + // completedRef.current = false; + // decrementVehicleLoad(agvDetail.modelUuid, 0) + // } + // }, [isReset]) + + // useFrame((_, delta) => { + // const object = scene.getObjectByProperty('uuid', agvUuid); + // if (!object || currentPath.length < 2) return; + // if (isPaused) return; + + // let totalDistance = 0; + // const distances = []; + + // for (let i = 0; i < currentPath.length - 1; i++) { + // const start = new THREE.Vector3(...currentPath[i]); + // const end = new THREE.Vector3(...currentPath[i + 1]); + // const segmentDistance = start.distanceTo(end); + // distances.push(segmentDistance); + // totalDistance += segmentDistance; + // } + + // let coveredDistance = progressRef.current; + // let accumulatedDistance = 0; + // let index = 0; + + // while ( + // index < distances.length && + // coveredDistance > accumulatedDistance + distances[index] + // ) { + // accumulatedDistance += distances[index]; + // index++; + // } + + // if (index < distances.length) { + // const start = new THREE.Vector3(...currentPath[index]); + // const end = new THREE.Vector3(...currentPath[index + 1]); + // const segmentDistance = distances[index]; + + // const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); + // const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); + // const rotationSpeed = 2.0; + // const currentAngle = object.rotation.y; + + // let angleDifference = targetAngle - currentAngle; + // if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; + // if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; + + // const maxRotationStep = rotationSpeed * delta; + // object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); + + // const isAligned = Math.abs(angleDifference) < 0.01; + + // if (isAligned) { + // progressRef.current += delta * (speed * agvDetail.speed); + // coveredDistance = progressRef.current; + + // const t = (coveredDistance - accumulatedDistance) / segmentDistance; + // const position = start.clone().lerp(end, t); + // object.position.copy(position); + // } + // } + + // if (progressRef.current >= totalDistance) { + // if (restRotation) { + // const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); + // object.quaternion.slerp(targetQuaternion, delta * 2); + // const angleDiff = object.quaternion.angleTo(targetQuaternion); + // if (angleDiff < 0.01) { + // let objectRotation = agvDetail.point.rotation + // object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + // setRestingRotation(false); + // } + // return; + // } + // } + + // if (progressRef.current >= totalDistance) { + // setRestingRotation(true); + // progressRef.current = 0; + // movingForward.current = !movingForward.current; + // setCurrentPath([]); + // handleCallBack(); + // if (currentPhase === 'pickup-drop') { + // requestAnimationFrame(firstFrame); + // } + // } + // }); + useEffect(() => { + if (isReset) { + reset(); + setCurrentPath([]); + setProgress(0); + progressRef.current = 0; + completedRef.current = false; + movingForward.current = true; + setRestingRotation(false); + decrementVehicleLoad(agvDetail.modelUuid, 0); } - } + }, [isReset]); + + useFrame((_, delta) => { + // If reset is active, don't run anything in frame + if (isReset) return; + + const object = scene.getObjectByProperty('uuid', agvUuid); + if (!object || currentPath.length < 2) return; + if (isPaused) return; + + let totalDistance = 0; + const distances = []; + + for (let i = 0; i < currentPath.length - 1; i++) { + const start = new THREE.Vector3(...currentPath[i]); + const end = new THREE.Vector3(...currentPath[i + 1]); + const segmentDistance = start.distanceTo(end); + distances.push(segmentDistance); + totalDistance += segmentDistance; + } + + let coveredDistance = progressRef.current; + let accumulatedDistance = 0; + let index = 0; + + while (index < distances.length && coveredDistance > accumulatedDistance + distances[index]) { + accumulatedDistance += distances[index]; + index++; + } + + if (index < distances.length) { + const start = new THREE.Vector3(...currentPath[index]); + const end = new THREE.Vector3(...currentPath[index + 1]); + const segmentDistance = distances[index]; + + const currentDirection = new THREE.Vector3().subVectors(end, start).normalize(); + const targetAngle = Math.atan2(currentDirection.x, currentDirection.z); + const currentAngle = object.rotation.y; + + let angleDifference = targetAngle - currentAngle; + if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI; + if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI; + + const rotationSpeed = 2.0; + const maxRotationStep = rotationSpeed * delta; + const rotationStep = Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep); + object.rotation.y += rotationStep; + + const isAligned = Math.abs(angleDifference) < 0.01; + + if (isAligned) { + progressRef.current += delta * (speed * agvDetail.speed); + coveredDistance = progressRef.current; + + const t = (coveredDistance - accumulatedDistance) / segmentDistance; + const position = start.clone().lerp(end, t); + object.position.copy(position); + } + } + + if (progressRef.current >= totalDistance) { + if (restRotation) { + const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); + object.quaternion.slerp(targetQuaternion, delta * 2); + const angleDiff = object.quaternion.angleTo(targetQuaternion); + if (angleDiff < 0.01) { + const objectRotation = agvDetail.point.rotation; + object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + setRestingRotation(false); + } + } else { + setRestingRotation(true); + progressRef.current = 0; + movingForward.current = !movingForward.current; + setCurrentPath([]); + handleCallBack(); + if (currentPhase === 'pickup-drop') { + requestAnimationFrame(firstFrame); + } + } + } + }); + + function firstFrame() { + const unLoadDuration = agvDetail.point.action.unLoadDuration; + const droppedMaterial = agvDetail.currentLoad; + fixedInterval = (unLoadDuration / droppedMaterial) * 1000; + startTime = performance.now(); + step(droppedMaterial); } - }); - function firstFrame() { - const unLoadDuration = agvDetail.point.action.unLoadDuration; - const droppedMaterial = agvDetail.currentLoad; - fixedInterval = (unLoadDuration / droppedMaterial) * 1000; - startTime = performance.now(); - step(droppedMaterial); - } - - function step(droppedMaterial: number) { - const elapsedTime = (performance.now() - startTime) * speed; - if (elapsedTime >= fixedInterval) { - let droppedMat = droppedMaterial - 1; - decrementVehicleLoad(agvDetail.modelUuid, 1); - if (droppedMat === 0) return; - startTime = performance.now(); - requestAnimationFrame(() => step(droppedMat)); - } else { - requestAnimationFrame(() => step(droppedMaterial)); + function step(droppedMaterial: number) { + const elapsedTime = (performance.now() - startTime) * speed; + if (elapsedTime >= fixedInterval) { + let droppedMat = droppedMaterial - 1; + decrementVehicleLoad(agvDetail.modelUuid, 1); + if (droppedMat === 0) return; + startTime = performance.now(); + requestAnimationFrame(() => step(droppedMat)); + } else { + requestAnimationFrame(() => step(droppedMaterial)); + } } - } - return ( - <> - {currentPath.length > 0 && ( + return ( <> - - {currentPath.map((point, index) => ( - - - - - ))} + {currentPath.length > 0 && ( + <> + + {currentPath.map((point, index) => ( + + + + + ))} + + )} - )} - - ); + ); } export default VehicleAnimator; \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 44a8ad8..a7a41d3 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -7,126 +7,116 @@ import { usePlayButtonStore, useResetButtonStore } from '../../../../../store/us import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; function VehicleInstance({ agvDetail }: any) { - const { navMesh } = useNavMesh(); - const { isPlaying, setIsPlaying } = usePlayButtonStore(); - const { isReset } = useResetButtonStore(); - const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore(); - const [currentPhase, setCurrentPhase] = useState('stationed'); - const [path, setPath] = useState<[number, number, number][]>([]); + const { navMesh } = useNavMesh(); + const { isPlaying, setIsPlaying } = usePlayButtonStore(); + const { isReset } = useResetButtonStore(); + const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore(); + const [currentPhase, setCurrentPhase] = useState('stationed'); + const [path, setPath] = useState<[number, number, number][]>([]); - const computePath = useCallback( - (start: any, end: any) => { - try { - const navMeshQuery = new NavMeshQuery(navMesh); - const { path: segmentPath } = navMeshQuery.computePath(start, end); - return ( - segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || [] - ); - } catch { - return []; - } - }, - [navMesh] - ); + const computePath = useCallback( + (start: any, end: any) => { + try { + const navMeshQuery = new NavMeshQuery(navMesh); + const { path: segmentPath } = navMeshQuery.computePath(start, end); + return ( + segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || [] + ); + } catch { + return []; + } + }, + [navMesh] + ); - function vehicleStatus(modelid: string, status: string) { - // console.log(`AGV ${modelid}: ${status}`); - } - function reset() { - console.log("runs"); - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); - setPath([]); - setCurrentPhase('stationed') - } + function vehicleStatus(modelid: string, status: string) { + // console.log(`AGV ${modelid}: ${status}`); + } + function reset() { + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setPath([]); + setCurrentPhase('stationed') + } - useEffect(() => { - if (isPlaying) { - if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { - const toPickupPath = computePath( - new THREE.Vector3(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]), - agvDetail.point.action.pickUpPoint - ); - setPath(toPickupPath); - setVehicleActive(agvDetail.modelUuid, true); - setVehicleState(agvDetail.modelUuid, 'running'); - setCurrentPhase('stationed-pickup'); - vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup'); - return; - } else if ( - !agvDetail.isActive && - agvDetail.state === 'idle' && - currentPhase === 'picking' - ) { + useEffect(() => { + if (isPlaying) { + if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { + const toPickupPath = computePath( + new THREE.Vector3(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]), + agvDetail.point.action.pickUpPoint + ); + setPath(toPickupPath); + setVehicleActive(agvDetail.modelUuid, true); + setVehicleState(agvDetail.modelUuid, 'running'); + setCurrentPhase('stationed-pickup'); + vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup'); + return; + } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'picking') { - setTimeout(() => { - incrementVehicleLoad(agvDetail.modelUuid, 2); - }, 5000); + setTimeout(() => { + incrementVehicleLoad(agvDetail.modelUuid, 2); + }, 5000); - if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) { - const toDrop = computePath( - agvDetail.point.action.pickUpPoint, - agvDetail.point.action.unLoadPoint - ); - setPath(toDrop); - setVehicleActive(agvDetail.modelUuid, true); - setVehicleState(agvDetail.modelUuid, 'running'); - setCurrentPhase('pickup-drop'); - vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point'); + if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) { + const toDrop = computePath( + agvDetail.point.action.pickUpPoint, + agvDetail.point.action.unLoadPoint + ); + setPath(toDrop); + setVehicleActive(agvDetail.modelUuid, true); + setVehicleState(agvDetail.modelUuid, 'running'); + setCurrentPhase('pickup-drop'); + vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point'); + } + } else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'dropping' && agvDetail.currentLoad === 0) { + const dropToPickup = computePath( + agvDetail.point.action.unLoadPoint, + agvDetail.point.action.pickUpPoint + ); + setPath(dropToPickup); + setVehicleActive(agvDetail.modelUuid, true); + setVehicleState(agvDetail.modelUuid, 'running'); + setCurrentPhase('drop-pickup'); + vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); + } } - } else if ( - !agvDetail.isActive && - agvDetail.state === 'idle' && - currentPhase === 'dropping' && - agvDetail.currentLoad === 0 - ) { - const dropToPickup = computePath( - agvDetail.point.action.unLoadPoint, - agvDetail.point.action.pickUpPoint - ); - setPath(dropToPickup); - setVehicleActive(agvDetail.modelUuid, true); - setVehicleState(agvDetail.modelUuid, 'running'); - setCurrentPhase('drop-pickup'); - vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); - } - } - }, [vehicles, currentPhase, path, isPlaying, isReset]); + }, [vehicles, currentPhase, path, isPlaying, isReset]); - function handleCallBack() { - if (currentPhase === 'stationed-pickup') { - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); - setCurrentPhase('picking'); - vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material'); - setPath([]); - } else if (currentPhase === 'pickup-drop') { - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); - setCurrentPhase('dropping'); - vehicleStatus(agvDetail.modelUuid, 'Reached drop point'); - setPath([]); - } else if (currentPhase === 'drop-pickup') { - setVehicleActive(agvDetail.modelUuid, false); - setVehicleState(agvDetail.modelUuid, 'idle'); - setCurrentPhase('picking'); - setPath([]); - vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete'); + function handleCallBack() { + if (currentPhase === 'stationed-pickup') { + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setCurrentPhase('picking'); + vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material'); + setPath([]); + } else if (currentPhase === 'pickup-drop') { + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setCurrentPhase('dropping'); + vehicleStatus(agvDetail.modelUuid, 'Reached drop point'); + setPath([]); + } else if (currentPhase === 'drop-pickup') { + setVehicleActive(agvDetail.modelUuid, false); + setVehicleState(agvDetail.modelUuid, 'idle'); + setCurrentPhase('picking'); + setPath([]); + vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete'); + } } - } - return ( - <> - - - ); + return ( + <> + + + ); } export default VehicleInstance; \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 9aa89f4..eaf12a3 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -28,8 +28,8 @@ function Vehicles() { actionType: "travel", unLoadDuration: 10, loadCapacity: 2, - pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, - unLoadPoint: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, + pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, + unLoadPoint: { position: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, triggers: [ { triggerUuid: "trig-001", @@ -71,8 +71,8 @@ function Vehicles() { actionType: "travel", unLoadDuration: 10, loadCapacity: 2, - pickUpPoint: { x: 90, y: 0, z: 28 }, - unLoadPoint: { x: 20, y: 0, z: 10 }, + pickUpPoint: { position: { x: 90, y: 0, z: 28 }, rotation: { x: 0, y: 0, z: 0 } }, + unLoadPoint: { position: { x: 20, y: 0, z: 10 }, rotation: { x: 0, y: 0, z: 0 } }, triggers: [ { triggerUuid: "trig-001", @@ -95,7 +95,8 @@ function Vehicles() { ] } } - }, { + }, + { modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79", modelName: "forklift", position: [98.85729337188162, 0, 38.36616546567653], @@ -113,8 +114,8 @@ function Vehicles() { actionType: "travel", unLoadDuration: 15, loadCapacity: 5, - pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, - unLoadPoint: { x: 20, y: 0, z: 10 }, + pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, + unLoadPoint: { position: { x: 20, y: 0, z: 10 }, rotation: { x: 0, y: 0, z: 0 } }, triggers: [ { triggerUuid: "trig-001", diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 3293699..811812d 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -44,8 +44,8 @@ interface VehiclePointSchema { actionType: "travel"; unLoadDuration: number; loadCapacity: number; - pickUpPoint: { x: number; y: number, z: number } | null; - unLoadPoint: { x: number; y: number, z: number } | null; + pickUpPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null; + unLoadPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null; triggers: TriggerSchema[]; }; } @@ -134,7 +134,7 @@ interface ConveyorStatus extends ConveyorEventSchema { isActive: boolean; idleTime: number; activeTime: number; - + } interface MachineStatus extends MachineEventSchema { From cc44826f669be9dc0fb6c8c163c5278d3149b651 Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Tue, 29 Apr 2025 10:34:21 +0530 Subject: [PATCH 16/30] updating progressbar --- app/src/components/icons/analysis.tsx | 93 ++++++ .../ui/analysis/ProductionCapacity.tsx | 62 ++++ app/src/components/ui/analysis/ROISummary.tsx | 151 ++++++++++ .../ui/analysis/SemiCircleProgress.tsx | 25 ++ .../ui/analysis/ThroughputSummary.tsx | 146 ++++++++++ .../visualization/RealTimeVisulization.tsx | 2 +- app/src/pages/Project.tsx | 12 +- .../components/analysis/ROISummary.scss | 269 +++++++++++++++++ .../styles/components/analysis/analysis.scss | 270 ++++++++++++++++++ app/src/styles/main.scss | 2 + 10 files changed, 1029 insertions(+), 3 deletions(-) create mode 100644 app/src/components/icons/analysis.tsx create mode 100644 app/src/components/ui/analysis/ProductionCapacity.tsx create mode 100644 app/src/components/ui/analysis/ROISummary.tsx create mode 100644 app/src/components/ui/analysis/SemiCircleProgress.tsx create mode 100644 app/src/components/ui/analysis/ThroughputSummary.tsx create mode 100644 app/src/styles/components/analysis/ROISummary.scss create mode 100644 app/src/styles/components/analysis/analysis.scss diff --git a/app/src/components/icons/analysis.tsx b/app/src/components/icons/analysis.tsx new file mode 100644 index 0000000..3a5542b --- /dev/null +++ b/app/src/components/icons/analysis.tsx @@ -0,0 +1,93 @@ +export function ThroughputSummaryIcon() { + return ( + + + + + ); +} +export function ProductionCapacityIcon() { + return ( + + + + + ); +} +export function ROISummaryIcon() { + return ( + + + + + + ); +} +export function PowerIcon() { + return ( + + + + + + + + + + + + ); +} diff --git a/app/src/components/ui/analysis/ProductionCapacity.tsx b/app/src/components/ui/analysis/ProductionCapacity.tsx new file mode 100644 index 0000000..268ea81 --- /dev/null +++ b/app/src/components/ui/analysis/ProductionCapacity.tsx @@ -0,0 +1,62 @@ +import React from "react"; +import { ProductionCapacityIcon } from "../../icons/analysis"; + +const ProductionCapacity = () => { + const totalBars = 6; + const progressPercent = 50; + + const barsToFill = Math.floor((progressPercent / 100) * totalBars); + const partialFillPercent = + ((progressPercent / 100) * totalBars - barsToFill) * 100; + + return ( +
    +
    +
    +
    +
    Throughput Summary
    +
    08:00 - 09:00 AM
    +
    +
    + +
    +
    + +
    +
    + 128 Units/hour +
    + + {/* Progress Bar */} +
    + {[...Array(totalBars)].map((_, i) => ( +
    + {i < barsToFill ? ( +
    + ) : i === barsToFill ? ( +
    + ) : null} +
    + ))} +
    +
    + +
    +
    + Avg. Process Time + 28.4 Secs/unit +
    +
    + Machine Utilization + 78% +
    +
    +
    +
    + ); +}; + +export default ProductionCapacity; diff --git a/app/src/components/ui/analysis/ROISummary.tsx b/app/src/components/ui/analysis/ROISummary.tsx new file mode 100644 index 0000000..cacd2c7 --- /dev/null +++ b/app/src/components/ui/analysis/ROISummary.tsx @@ -0,0 +1,151 @@ +import React from "react"; +import { ROISummaryIcon } from "../../icons/analysis"; +import SemiCircleProgress from "./SemiCircleProgress"; + +const ROISummary = () => { + // Data for the cost breakdown as an array of objects + const costBreakdownData = [ + { + item: "Raw Material A", + unitCost: "₹ 10/unit", + laborCost: "₹ 0", + totalCost: "₹ 1000", + sellingPrice: "₹ 1500", + }, + { + item: "Labor", + unitCost: "₹ 10/unit", + laborCost: "₹ 500", + totalCost: "₹ 500", + sellingPrice: "N/A", + }, + { + item: "Product 1", + unitCost: "₹ 10/unit", + laborCost: "₹ 200", + totalCost: "₹ 200", + sellingPrice: "₹ 2000", + }, + { + item: "Machine", + unitCost: "-", + laborCost: "-", + totalCost: "₹ 20,000", + sellingPrice: "N/A", + }, + { + item: "Total", + unitCost: "-", + laborCost: "-", + totalCost: "₹ 1,20,000", + sellingPrice: "-", + }, + { + item: "Net Profit", + unitCost: "-", + laborCost: "-", + totalCost: "₹ 1,60,000", + sellingPrice: "-", + }, + ]; + const progressValue = 50; + return ( +
    +
    +
    +
    +
    ROI Summary
    +
    From 24 November, 2025
    +
    +
    + +
    +
    +
    +
    Product :
    +
    Product name
    +
    +
    +
    +
    + +133% ROI with payback in just 50.3 months +
    +
    +
    + + +
    +
    +
    + Total Cost Incurred + ₹ 1,20,000 +
    +
    + Revenue Generated + ₹ 2,80,000 +
    +
    +
    + Net Profit + ₹ 1,60,000 +
    +
    +
    +
    +
    + + Cost Breakdown + +
    + + + + + + + + + + + + {costBreakdownData.map((row, index) => ( + + + + + + + + ))} + +
    ItemUnit CostLabor CostTotal CostSelling Price
    {row.item}{row.unitCost}{row.laborCost}{row.totalCost}{row.sellingPrice}
    +
    +
    +
    + 💡 + How to improve ROI? +
    +
    + Increase CNC utilization by 10%{" "} + to shave 0.5 months of payback + period +
    + +
    +
    +
    + ); +}; + +export default ROISummary; diff --git a/app/src/components/ui/analysis/SemiCircleProgress.tsx b/app/src/components/ui/analysis/SemiCircleProgress.tsx new file mode 100644 index 0000000..bd11d28 --- /dev/null +++ b/app/src/components/ui/analysis/SemiCircleProgress.tsx @@ -0,0 +1,25 @@ +import React from "react"; + +const SemiCircleProgress = () => { + const progress = 10; + const clampedProgress = Math.min(Math.max(progress, 0), 100); // clamp 0-100 + return ( +
    +
    +
    +
    +
    {clampedProgress}%
    +
    + ); +}; + +export default SemiCircleProgress; diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx new file mode 100644 index 0000000..cb4fac5 --- /dev/null +++ b/app/src/components/ui/analysis/ThroughputSummary.tsx @@ -0,0 +1,146 @@ +import React from "react"; +import { Line } from "react-chartjs-2"; +import { + Chart as ChartJS, + LineElement, + CategoryScale, + LinearScale, + PointElement, +} from "chart.js"; +import { PowerIcon, ThroughputSummaryIcon } from "../../icons/analysis"; + +ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement); + +const ThroughputSummary = () => { + const data = { + labels: ["08:00", "08:10", "08:20", "08:30", "08:40", "08:50", "09:00"], + datasets: [ + { + label: "Units/hour", + data: [100, 120, 110, 130, 125, 128, 132], + borderColor: "#B392F0", + tension: 0.4, + pointRadius: 0, // hide points + }, + ], + }; + + const options = { + responsive: true, + scales: { + x: { + grid: { + display: false, + }, + ticks: { + display: false, + color: "#fff", + }, + }, + y: { + grid: { + display: false, + }, + ticks: { + display: false, + color: "#fff", + }, + }, + }, + plugins: { + legend: { + display: false, + }, + tooltip: { + enabled: true, + }, + }, + }; + + const shiftUtilization = { + "shift 1": 25, + "shift 2": 45, + "shift 3": 15, + }; + + return ( +
    +
    +
    +
    +
    Throughput Summary
    +
    08:00 - 09:00 AM
    +
    +
    + +
    +
    + +
    +
    + 1240 Units/hour +
    +
    +
    +
    Asset usage
    +
    85%
    +
    + +
    +
    + +
    +
    +
    Energy Consumption
    +
    +
    + +
    +
    +
    456
    +
    KWH
    +
    +
    +
    +
    +
    Shift Utilization
    +
    +
    85%
    + +
    +
    +
    +
    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    +
    +
    + ); +}; + +export default ThroughputSummary; diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index cd2c57c..50b72ba 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -343,7 +343,7 @@ const RealTimeVisulization: React.FC = () => { onDrop={(event) => handleDrop(event)} onDragOver={(event) => event.preventDefault()} > - + {/* */}
    {activeModule === "visualization" && selectedZone.zoneName !== "" && ( diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 2daa091..26d1d7d 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -23,6 +23,9 @@ import SimulationPlayer from "../components/ui/simulation/simulationPlayer"; import RenderOverlay from "../components/templates/Overlay"; import MenuBar from "../components/ui/menu/menu"; import KeyPressListener from "../utils/shortcutkeys/handleShortcutKeys"; +import ProductionCapacity from "../components/ui/analysis/ProductionCapacity"; +import ThroughputSummary from "../components/ui/analysis/ThroughputSummary"; +import ROISummary from "../components/ui/analysis/ROISummary"; const Project: React.FC = () => { let navigate = useNavigate(); @@ -38,7 +41,7 @@ const Project: React.FC = () => { setFloorItems([]); setWallItems([]); setZones([]); - setActiveModule('builder') + setActiveModule("builder"); const email = localStorage.getItem("email"); if (email) { const Organization = email!.split("@")[1].split(".")[0]; @@ -57,8 +60,13 @@ const Project: React.FC = () => { return (
    +
    + {/* + */} + +
    - {loadingProgress && } + {/* {loadingProgress && } */} {!isPlaying && ( <> {toggleThreeD && } diff --git a/app/src/styles/components/analysis/ROISummary.scss b/app/src/styles/components/analysis/ROISummary.scss new file mode 100644 index 0000000..f4ee414 --- /dev/null +++ b/app/src/styles/components/analysis/ROISummary.scss @@ -0,0 +1,269 @@ +.roiSummary-container { + + .roiSummary-wrapper { + background-color: #F2F2F7; + + .product-info { + display: flex; + } + + .playBack { + display: flex; + background-color: var(--background-color); + border-radius: 12px; + padding: 6px; + + .info { + span { + font-size: var(--font-size-xlarge); + + &:first-child { + color: #31C756; + } + + &:last-child { + color: #2B3344; + } + } + } + } + + .roi-details { + display: flex; + + .roi-progress { + width: 60%; + } + + .metrics { + display: flex; + flex-direction: column; + gap: 6px; + + .metric-item { + width: 100%; + border-radius: 6px; + border: 1px solid var(--axis-colors-green, #43C06D); + background: var(--axis-colors-green-lite, #BEEECF); + display: flex; + flex-direction: column; + padding: 4px 6px; + + &:last-child { + align-items: center; + } + + .metric-label { + font-size: 10px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + } + + .metric-value { + text-align: center; + line-height: 20px; + } + } + + .metric-wrapper { + display: flex; + gap: 6px; + + .metric-item { + background-color: var(--background-color); + border: 1px solid var(--Grays-Gray-6, #F2F2F7); + + } + } + } + } + + + .cost-breakdown { + background-color: var(--background-color); + border: 1px solid var(--text-disabled); + border-radius: 8px; + padding: 16px; + + .breakdown-header { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 16px; + + .section-number { + font-size: 20px; + color: #00aaff; + } + + .section-title { + font-size: var(--font-size-regular); + color: #333; + } + + .expand-icon { + font-size: 16px; + color: #666; + cursor: pointer; + } + } + + + + .breakdown-table { + width: 100%; + border-collapse: collapse; + border-radius: 8px; + + th, + td { + padding: 8px; + text-align: left; + border-top: 1px solid var(--text-disabled); + border-bottom: 1px solid var(--text-disabled); + } + + /* Apply left border to first child */ + th:first-child { + border-left: 1px solid var(--text-disabled); + } + + /* Apply right border to last child */ + th:last-child { + border-right: 1px solid var(--text-disabled); + } + + td:first-child { + border-left: 1px solid var(--text-disabled); + } + + /* Apply right border to last child */ + td:last-child { + border-right: 1px solid var(--text-disabled); + } + + th { + background-color: var(--background-color); + + color: #333; + } + + .total-row, + .net-profit-row { + font-weight: bold; + color: #333; + } + } + + + + } + + + .tips-section { + background-color: var(--background-color); + border-radius: 8px; + display: flex; + flex-direction: column; + gap: 6px; + padding: 12px; + + .tip-header { + display: flex; + align-items: center; + + .tip-title { + color: var(--text-color); + font-weight: 600; + } + } + + .tip-description { + span { + color: #34C759; + /* Default color for the first span */ + + &:first-child { + color: #34C759; + /* Color for the first span */ + } + + &:nth-child(2) { + color: #488EF6; + /* Color for the second span */ + } + } + } + } + + .get-tips-button { + border: none; + + border-radius: 5px; + cursor: pointer; + font-size: 14px; + margin-top: 8px; + + /* Make the button content-width dependent */ + display: inline-block; + display: flex; + justify-content: flex-end; + background: none; + + .btn { + background-color: var(--accent-color); + color: var(--background-color); + padding: 4px 6px; + /* Add padding to ensure it has space around the text */ + border-radius: 5px; + display: inline-block; + /* Ensure button width adjusts to its content */ + font-size: 14px; + text-align: center; + /* Ensure text is centered */ + } + } + + + + } +} + + +.semi-circle-wrapper { + width: 250px; + height: 125px; + overflow: hidden; + position: relative; + } + + .semi-circle { + width: 250px; + height: 250px; + border-radius: 50%; + position: relative; + transition: background 0.5s ease; + transform: rotate(180deg); /* rotate so 0% is at left */ + } + + .progress-cover { + position: absolute; + width: 75%; + height: 75%; + top: 12.5%; + left: 12.5%; + background-color: white; + border-radius: 50%; + } + + .label { + position: absolute; + top: 40%; + left: 50%; + transform: translate(-50%, -50%); + font-weight: bold; + font-size: 1.2rem; + } + \ No newline at end of file diff --git a/app/src/styles/components/analysis/analysis.scss b/app/src/styles/components/analysis/analysis.scss new file mode 100644 index 0000000..bc33556 --- /dev/null +++ b/app/src/styles/components/analysis/analysis.scss @@ -0,0 +1,270 @@ +.analysis { + position: absolute; + top: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100vh; + z-index: 100000000000000000000000000000; +} + +.analysis-card { + min-width: 333px; + // background: var(--primary-color); + border-radius: 20px; + + padding: 8px; + + .analysis-card-wrapper { + background: var(--background-color); + border-radius: 14px; + padding: 16px; + + display: flex; + flex-direction: column; + gap: 14px; + + .card-header { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + + .main-header { + line-height: 20px; + font-size: var(--font-size-regular); + } + } + + .process-container { + display: flex; + flex-direction: column; + + .throughput-value { + font-size: 1rem; + + .value { + font-weight: bold; + font-size: 1.5rem; + } + } + + .progress-bar-wrapper { + display: flex; + gap: 8px; + margin-top: 6px; + } + + .progress-bar { + position: relative; + width: 36px; + height: 4px; + border-radius: 13px; + overflow: hidden; + background-color: #FBEBD7; + + .bar-fill { + position: absolute; + height: 100%; + top: 0; + left: 0; + background-color: #FC9D2F; + border-radius: 13px; + } + + .bar-fill.full { + width: 100%; + } + + .bar-fill.partial { + width: 0; // inline style will override this + } + } + } + + .metrics-section { + padding-top: 16px; + border-top: 1px solid var(--background-color-gray); + + .metric { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 14px; + margin-bottom: 8px; + + .label { + color: var(--text-color); + } + + .value { + font-weight: bold; + } + } + } + } +} + + +.throughoutSummary { + .throughoutSummary-wrapper { + .process-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + gap: 16px; + width: 100%; + + .throughput-value { + font-size: var(--font-size-small); + flex: 1; + display: flex; + flex-direction: column; + + .value { + color: var(--accent-color); + } + + /* Let the text take available space */ + } + + .lineChart { + max-width: 200px; + height: 100px; + position: relative; + + .assetUsage { + text-align: right; + position: absolute; + right: 0; + top: 0; + } + + canvas { + background-color: transparent; + } + } + } + + .footer { + display: flex; + gap: 16px; // Space between cards + margin-top: 24px; + + .footer-card { + width: 100%; + background: var(--background-color-gray); + border-radius: 6px; + padding: 8px; + display: flex; + flex-direction: column; + gap: 6px; + + &:first-child { + width: 85%; + } + + .header { + font-size: var(--font-size-regular); + } + + .value-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: end; + gap: 6px; + } + } + + .shiftUtilization { + .value-container { + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + + .value { + font-size: var(--font-size-xlarge); + } + + .progress-wrapper { + width: 100%; + display: flex; + gap: 6px; + + .progress { + border-radius: 6px; + height: 5px; + + &:nth-child(1) { + background-color: #F3C64D; + } + + &:nth-child(2) { + background-color: #67B3F4; + } + + &:nth-child(3) { + background-color: #7981F5; + } + } + } + + .progress-indicator { + display: flex; + justify-content: space-between; + width: 100%; + gap: 6px; + + .shift-wrapper { + display: flex; + align-items: center; + gap: 5px; + + /* Align items vertically */ + &:nth-child(1) { + .indicator { + + background-color: #F3C64D; + } + } + + &:nth-child(2) { + .indicator { + + background-color: #67B3F4; + } + } + + &:nth-child(3) { + .indicator { + + background-color: #7981F5; + } + } + + label { + font-size: var(--font-size-small); + position: relative; + } + + .indicator { + display: inline-block; + width: 5px; + height: 5px; + border-radius: 50%; + + } + } + } + } + } + + } + + + } +} \ No newline at end of file diff --git a/app/src/styles/main.scss b/app/src/styles/main.scss index 5e46dd4..f0f7704 100644 --- a/app/src/styles/main.scss +++ b/app/src/styles/main.scss @@ -25,6 +25,8 @@ @use 'components/simulation/simulation'; @use 'components/menu/menu'; @use 'components/confirmationPopUp'; +@use 'components/analysis/analysis'; +@use 'components/analysis/ROISummary.scss'; // layout @use 'layout/loading'; From c1a7fe30156ef79a53adcdb78b5e093fb307657a Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 29 Apr 2025 12:50:14 +0530 Subject: [PATCH 17/30] feat: Implement collaboration features including user following and avatar management --- .../components/layout/sidebarRight/Header.tsx | 2 +- .../layout/sidebarRight/SideBarRight.tsx | 3 + .../properties/GlobalProperties.tsx | 5 +- app/src/components/templates/FollowPerson.tsx | 29 ++++++++++ app/src/functions/collabUserIcon.tsx | 31 ---------- .../collaboration/camera/collabCams.tsx | 19 +++++-- .../collaboration/camera/collabUserIcon.tsx | 56 +++++++++++++++++++ .../modules/collaboration/collaboration.tsx | 38 +++++++++---- .../functions/getAvatarColor.ts | 2 +- .../collaboration}/functions/getInitials.ts | 0 .../collaboration/functions/setCameraView.ts | 46 +++++++++++++++ .../collaboration}/users/Avatar.tsx | 7 +-- app/src/pages/Project.tsx | 15 +++-- app/src/store/useCollabStore.ts | 30 ++++++++++ app/src/styles/components/templates.scss | 22 ++++++++ app/src/styles/layout/popup.scss | 1 + 16 files changed, 243 insertions(+), 63 deletions(-) create mode 100644 app/src/components/templates/FollowPerson.tsx delete mode 100644 app/src/functions/collabUserIcon.tsx create mode 100644 app/src/modules/collaboration/camera/collabUserIcon.tsx rename app/src/{functions/users => modules/collaboration}/functions/getAvatarColor.ts (98%) rename app/src/{functions/users => modules/collaboration}/functions/getInitials.ts (100%) create mode 100644 app/src/modules/collaboration/functions/setCameraView.ts rename app/src/{functions => modules/collaboration}/users/Avatar.tsx (87%) create mode 100644 app/src/store/useCollabStore.ts diff --git a/app/src/components/layout/sidebarRight/Header.tsx b/app/src/components/layout/sidebarRight/Header.tsx index f9f48fb..a449500 100644 --- a/app/src/components/layout/sidebarRight/Header.tsx +++ b/app/src/components/layout/sidebarRight/Header.tsx @@ -2,9 +2,9 @@ import React, { useEffect, useState } from "react"; import { AppDockIcon } from "../../icons/HeaderIcons"; import orgImg from "../../../assets/orgTemp.png"; import { useActiveUsers } from "../../../store/store"; -import { getAvatarColor } from "../../../functions/users/functions/getAvatarColor"; import { ActiveUser } from "../../../types/users"; import CollaborationPopup from "../../templates/CollaborationPopup"; +import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor"; const Header: React.FC = () => { const { activeUsers } = useActiveUsers(); diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index cb9b5dc..b2f25eb 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -49,6 +49,9 @@ const SideBarRight: React.FC = () => { setSubModule("simulations"); } } + if (activeModule !== "simulation") { + setSubModule("properties"); + } }, [activeModule, selectedEventData, selectedEventSphere, setSubModule]); return ( diff --git a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx index 568783c..251ada3 100644 --- a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx @@ -282,8 +282,7 @@ const GlobalProperties: React.FC = () => { key={"6"} /> -
    - + {/*
    { max={5} onChange={(value: number) => updateGridDistance(value)} onPointerUp={updatedGrid} - /> + /> */}
    ); }; diff --git a/app/src/components/templates/FollowPerson.tsx b/app/src/components/templates/FollowPerson.tsx new file mode 100644 index 0000000..a85d0c9 --- /dev/null +++ b/app/src/components/templates/FollowPerson.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import RenderOverlay from "./Overlay"; +import { useSelectedUserStore } from "../../store/useCollabStore"; +import { useCamMode } from "../../store/store"; + +const FollowPerson: React.FC = () => { + // Get the selected user from the store + const { selectedUser, clearSelectedUser } = useSelectedUserStore(); + const { setCamMode } = useCamMode(); + return ( + + {selectedUser && ( + // eslint-disable-next-line +
    { + clearSelectedUser(); + setCamMode("FirstPerson"); + }} + style={{ "--user-color": selectedUser.color } as React.CSSProperties} + > +
    {selectedUser.name}
    +
    + )} +
    + ); +}; + +export default FollowPerson; diff --git a/app/src/functions/collabUserIcon.tsx b/app/src/functions/collabUserIcon.tsx deleted file mode 100644 index 9e6802b..0000000 --- a/app/src/functions/collabUserIcon.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from "react"; -import CustomAvatar from "./users/Avatar"; - -interface CollabUserIconProps { - userName: string; - userImage?: string; - color: string; -} - -const CollabUserIcon: React.FC = ({ - userImage, - userName, - color, -}) => { - return ( -
    -
    - {userImage ? ( - {userName} - ) : ( - - )} -
    -
    - {userName} -
    -
    - ); -}; - -export default CollabUserIcon; diff --git a/app/src/modules/collaboration/camera/collabCams.tsx b/app/src/modules/collaboration/camera/collabCams.tsx index 1347a2a..461cb7f 100644 --- a/app/src/modules/collaboration/camera/collabCams.tsx +++ b/app/src/modules/collaboration/camera/collabCams.tsx @@ -8,9 +8,9 @@ import { useActiveUsers, useSocketStore } from "../../../store/store"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import { useNavigate } from "react-router-dom"; import { Html } from "@react-three/drei"; -import CollabUserIcon from "../../../functions/collabUserIcon"; -import { getAvatarColor } from "../../../functions/users/functions/getAvatarColor"; +import CollabUserIcon from "./collabUserIcon"; import useModuleStore from "../../../store/useModuleStore"; +import { getAvatarColor } from "../functions/getAvatarColor"; const CamModelsGroup = () => { const navigate = useNavigate(); @@ -20,13 +20,14 @@ const CamModelsGroup = () => { const { socket } = useSocketStore(); const { activeModule } = useModuleStore(); + // eslint-disable-next-line react-hooks/exhaustive-deps const loader = new GLTFLoader(); const dracoLoader = new DRACOLoader(); dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/"); loader.setDRACOLoader(dracoLoader); const [cams, setCams] = useState([]); - const [models, setModels] = useState>({}); + const [models, setModels] = useState>({}); const dedupeCams = (cams: any[]) => { const seen = new Set(); @@ -102,6 +103,7 @@ const CamModelsGroup = () => { }); socket.on("cameraUpdateResponse", (data: any) => { + if ( !groupRef.current || socket.id === data.socketId || @@ -122,6 +124,11 @@ const CamModelsGroup = () => { data.data.rotation.y, data.data.rotation.z ), + target: new THREE.Vector3( + data.data.target.x, + data.data.target.y, + data.data.target.z + ), }, })); }); @@ -131,7 +138,7 @@ const CamModelsGroup = () => { socket.off("userDisConnectResponse"); socket.off("cameraUpdateResponse"); }; - }, [socket]); + }, [email, loader, navigate, setActiveUsers, socket]); useFrame(() => { if (!groupRef.current) return; @@ -217,9 +224,11 @@ const CamModelsGroup = () => { position={[-0.015, 0, 0.7]} > diff --git a/app/src/modules/collaboration/camera/collabUserIcon.tsx b/app/src/modules/collaboration/camera/collabUserIcon.tsx new file mode 100644 index 0000000..dcdb73b --- /dev/null +++ b/app/src/modules/collaboration/camera/collabUserIcon.tsx @@ -0,0 +1,56 @@ +import React from "react"; +import CustomAvatar from "../users/Avatar"; +import { useSelectedUserStore } from "../../../store/useCollabStore"; +import { useCamMode } from "../../../store/store"; + +interface CollabUserIconProps { + userName: string; + userImage?: string; + color: string; + position?: { + x: number; + y: number; + z: number; + }; + rotation?: { + x: number; + y: number; + z: number; + }; +} + +const CollabUserIcon: React.FC = ({ + userImage, + userName, + color, + position, + rotation, +}) => { + const { setSelectedUser } = useSelectedUserStore(); + const { setCamMode } = useCamMode(); + return ( +
    + +
    + {userName} +
    +
    + ); +}; + +export default CollabUserIcon; diff --git a/app/src/modules/collaboration/collaboration.tsx b/app/src/modules/collaboration/collaboration.tsx index 84d3ab1..8835185 100644 --- a/app/src/modules/collaboration/collaboration.tsx +++ b/app/src/modules/collaboration/collaboration.tsx @@ -1,14 +1,32 @@ -import React from 'react' -import CamModelsGroup from './camera/collabCams' +import React, { useEffect } from "react"; +import CamModelsGroup from "./camera/collabCams"; +import { useSelectedUserStore } from "../../store/useCollabStore"; +import { useThree } from "@react-three/fiber"; +import setCameraView from "./functions/setCameraView"; +import { useCamMode } from "../../store/store"; -const Collaboration = () => { - return ( - <> +const Collaboration: React.FC = () => { + const { selectedUser } = useSelectedUserStore(); + const { camMode } = useCamMode(); + const { camera, controls } = useThree(); // Access R3F camera and controls - + useEffect(() => { + if(camMode !== "FollowPerson") return; + // If a user is selected, set the camera view to their location + // and update the camera and controls accordingly + if (selectedUser?.location) { + const { position, rotation } = selectedUser.location; + setCameraView({ + controls, + camera, + position, + rotation, + username: selectedUser.name, + }); + } + }, [selectedUser, camera, controls, camMode]); - - ) -} + return ; +}; -export default Collaboration \ No newline at end of file +export default Collaboration; diff --git a/app/src/functions/users/functions/getAvatarColor.ts b/app/src/modules/collaboration/functions/getAvatarColor.ts similarity index 98% rename from app/src/functions/users/functions/getAvatarColor.ts rename to app/src/modules/collaboration/functions/getAvatarColor.ts index d9a5d37..6d34edc 100644 --- a/app/src/functions/users/functions/getAvatarColor.ts +++ b/app/src/modules/collaboration/functions/getAvatarColor.ts @@ -27,7 +27,7 @@ export function getAvatarColor(index: number, name?: string): string { const localStorageKey = "userAvatarColors"; // Check if local storage is available if (name) { - let userColors = JSON.parse(localStorage.getItem(localStorageKey) || "{}"); + let userColors = JSON.parse(localStorage.getItem(localStorageKey) ?? "{}"); // Check if the user already has an assigned color if (userColors[name]) { diff --git a/app/src/functions/users/functions/getInitials.ts b/app/src/modules/collaboration/functions/getInitials.ts similarity index 100% rename from app/src/functions/users/functions/getInitials.ts rename to app/src/modules/collaboration/functions/getInitials.ts diff --git a/app/src/modules/collaboration/functions/setCameraView.ts b/app/src/modules/collaboration/functions/setCameraView.ts new file mode 100644 index 0000000..af05181 --- /dev/null +++ b/app/src/modules/collaboration/functions/setCameraView.ts @@ -0,0 +1,46 @@ +import * as THREE from 'three'; + +interface SetCameraViewProps { + controls: any; + camera: THREE.Camera; + position: THREE.Vector3 | { x: number; y: number; z: number }; + rotation: THREE.Euler | { x: number; y: number; z: number }; + username?: string; +} + +export default async function setCameraView({ + controls, + camera, + position, + rotation, + username, +}: SetCameraViewProps) { + if (!controls || !camera) return; + + // Normalize position + const newPosition = position instanceof THREE.Vector3 + ? position + : new THREE.Vector3(position.x, position.y, position.z); + + // Normalize rotation + const newRotation = rotation instanceof THREE.Euler + ? rotation + : new THREE.Euler(rotation.x, rotation.y, rotation.z); + + // Update camera position and rotation + // camera.position.copy(newPosition); + // camera.rotation.copy(newRotation); + + // If your controls need to update the target, you can optionally adjust it too + if (controls.setTarget) { + // Setting a basic target slightly forward from new position based on rotation + const cameraDirection = new THREE.Vector3(0, 0, -1).applyEuler(newRotation); + const targetPosition = new THREE.Vector3().copy(newPosition).add(cameraDirection); + + // controls.setTarget(targetPosition.x, targetPosition.y, targetPosition.z); + controls?.setLookAt(...newPosition.toArray(), newPosition.x, 0, newPosition.z, true); + } + + // Optionally you can log + console.log(`Camera view updated by ${username ?? 'unknown user'}`); +} diff --git a/app/src/functions/users/Avatar.tsx b/app/src/modules/collaboration/users/Avatar.tsx similarity index 87% rename from app/src/functions/users/Avatar.tsx rename to app/src/modules/collaboration/users/Avatar.tsx index d3e5dca..899ecb4 100644 --- a/app/src/functions/users/Avatar.tsx +++ b/app/src/modules/collaboration/users/Avatar.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useState } from "react"; -import { getInitials } from "./functions/getInitials"; -import { getAvatarColor } from "./functions/getAvatarColor"; +import { getInitials } from "../functions/getInitials"; interface AvatarProps { name: string; // Name can be a full name or initials @@ -26,7 +25,7 @@ const CustomAvatar: React.FC = ({ const initials = getInitials(name); // Convert name to initials if needed // Draw background - ctx.fillStyle = color || "#323232"; // Use color prop or generate color based on index + ctx.fillStyle = color ?? "#323232"; // Use color prop or generate color based on index ctx.fillRect(0, 0, size, size); // Draw initials @@ -40,7 +39,7 @@ const CustomAvatar: React.FC = ({ const dataURL = canvas.toDataURL("image/png"); setImageSrc(dataURL); } - }, [name, size, textColor]); + }, [color, name, size, textColor]); if (!imageSrc) { return null; // Return null while the image is being generated diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 3f6b4cc..bae83cc 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -1,11 +1,10 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; import ModuleToggle from "../components/ui/ModuleToggle"; import SideBarLeft from "../components/layout/sidebarLeft/SideBarLeft"; import SideBarRight from "../components/layout/sidebarRight/SideBarRight"; import useModuleStore, { useThreeDStore } from "../store/useModuleStore"; import RealTimeVisulization from "../modules/visualization/RealTimeVisulization"; import Tools from "../components/ui/Tools"; -// import Scene from "../modules/scene/scene"; import { useSocketStore, useFloorItems, @@ -20,12 +19,9 @@ import { usePlayButtonStore } from "../store/usePlayButtonStore"; import MarketPlace from "../modules/market/MarketPlace"; import LoadingPage from "../components/templates/LoadingPage"; import SimulationPlayer from "../components/ui/simulation/simulationPlayer"; -import RenderOverlay from "../components/templates/Overlay"; -import MenuBar from "../components/ui/menu/menu"; import KeyPressListener from "../utils/shortcutkeys/handleShortcutKeys"; -import ProductionCapacity from "../components/ui/analysis/ProductionCapacity"; -import ThroughputSummary from "../components/ui/analysis/ThroughputSummary"; -import ROISummary from "../components/ui/analysis/ROISummary"; +import { useSelectedUserStore } from "../store/useCollabStore"; +import FollowPerson from "../components/templates/FollowPerson"; const Project: React.FC = () => { let navigate = useNavigate(); @@ -44,7 +40,7 @@ const Project: React.FC = () => { setActiveModule("builder"); const email = localStorage.getItem("email"); if (email) { - const Organization = email!.split("@")[1].split(".")[0]; + const Organization = email.split("@")[1].split(".")[0]; useSocketStore.getState().initializeSocket(email, Organization); const name = localStorage.getItem("userName"); if (Organization && name) { @@ -55,8 +51,10 @@ const Project: React.FC = () => { navigate("/"); } }, []); + const { isPlaying } = usePlayButtonStore(); const { toggleThreeD } = useThreeDStore(); + const { selectedUser } = useSelectedUserStore(); return (
    @@ -81,6 +79,7 @@ const Project: React.FC = () => { {activeModule !== "market" && } {isPlaying && activeModule === "simulation" && } + {selectedUser && }
    ); }; diff --git a/app/src/store/useCollabStore.ts b/app/src/store/useCollabStore.ts new file mode 100644 index 0000000..3fe1497 --- /dev/null +++ b/app/src/store/useCollabStore.ts @@ -0,0 +1,30 @@ +import { create } from 'zustand'; + +interface SelectedUser { + color: string; + name: string; + location?: { + position: { + x: number; + y: number; + z: number; + }; + rotation: { + x: number; + y: number; + z: number; + }; + } +} + +interface SelectedUserStore { + selectedUser: SelectedUser | null; + setSelectedUser: (user: SelectedUser) => void; + clearSelectedUser: () => void; +} + +export const useSelectedUserStore = create((set) => ({ + selectedUser: null, + setSelectedUser: (user) => set({ selectedUser: user }), + clearSelectedUser: () => set({ selectedUser: null }), +})); diff --git a/app/src/styles/components/templates.scss b/app/src/styles/components/templates.scss index e69de29..bd28d94 100644 --- a/app/src/styles/components/templates.scss +++ b/app/src/styles/components/templates.scss @@ -0,0 +1,22 @@ +.follow-person-container{ + height: 100vh; + width: 100vw; + position: fixed; + top: 0; + left: 0; + outline: 8px solid var(--user-color); + outline-offset: -3px; + border-radius: 16px; + .follower-name{ + background-color: var(--user-color); + color: #FFFFFF; + padding: 4px 8px; + padding-top: 16px; + text-align: center; + position: absolute; + top: -10px; + left: 50%; + transform: translate(-50%, 0); + border-radius: 8px; + } +} diff --git a/app/src/styles/layout/popup.scss b/app/src/styles/layout/popup.scss index a354c10..b92d8cc 100644 --- a/app/src/styles/layout/popup.scss +++ b/app/src/styles/layout/popup.scss @@ -137,6 +137,7 @@ width: 100%; object-fit: cover; vertical-align: top; + pointer-events: none; } } .user-name{ From 617d29f2e3b3e573764ade22ab000a2ab56aca02 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 29 Apr 2025 12:50:56 +0530 Subject: [PATCH 18/30] feat: Add target parameter to setCameraView function for improved camera control --- .../collaboration/functions/setCameraView.ts | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/app/src/modules/collaboration/functions/setCameraView.ts b/app/src/modules/collaboration/functions/setCameraView.ts index af05181..8bae59b 100644 --- a/app/src/modules/collaboration/functions/setCameraView.ts +++ b/app/src/modules/collaboration/functions/setCameraView.ts @@ -6,6 +6,7 @@ interface SetCameraViewProps { position: THREE.Vector3 | { x: number; y: number; z: number }; rotation: THREE.Euler | { x: number; y: number; z: number }; username?: string; + target?: THREE.Vector3 | { x: number; y: number; z: number }; } export default async function setCameraView({ @@ -14,6 +15,7 @@ export default async function setCameraView({ position, rotation, username, + target }: SetCameraViewProps) { if (!controls || !camera) return; @@ -22,22 +24,7 @@ export default async function setCameraView({ ? position : new THREE.Vector3(position.x, position.y, position.z); - // Normalize rotation - const newRotation = rotation instanceof THREE.Euler - ? rotation - : new THREE.Euler(rotation.x, rotation.y, rotation.z); - - // Update camera position and rotation - // camera.position.copy(newPosition); - // camera.rotation.copy(newRotation); - - // If your controls need to update the target, you can optionally adjust it too if (controls.setTarget) { - // Setting a basic target slightly forward from new position based on rotation - const cameraDirection = new THREE.Vector3(0, 0, -1).applyEuler(newRotation); - const targetPosition = new THREE.Vector3().copy(newPosition).add(cameraDirection); - - // controls.setTarget(targetPosition.x, targetPosition.y, targetPosition.z); controls?.setLookAt(...newPosition.toArray(), newPosition.x, 0, newPosition.z, true); } From fdf10589a7bac75fdf03f1b39aa71a54c7dacb8c Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Tue, 29 Apr 2025 12:56:20 +0530 Subject: [PATCH 19/30] Merged With AGV-UI --- .../simulation/ui/vehicle/vehicleUI.tsx | 99 +++--- .../instances/animator/vehicleAnimator.tsx | 25 +- .../instances/instance/vehicleInstance.tsx | 7 +- .../vehicle/instances/vehicleInstances.tsx | 22 +- .../modules/simulation/vehicle/vehicles.tsx | 317 +++++++++++------- 5 files changed, 287 insertions(+), 183 deletions(-) diff --git a/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx index f927c33..b26cfc9 100644 --- a/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx +++ b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx @@ -5,37 +5,40 @@ import { useGLTF } from "@react-three/drei"; import { useSelectedEventSphere } from "../../../../store/simulation/useSimulationStore"; import * as THREE from "three"; import { useThree } from "@react-three/fiber"; +import { useVehicleStore } from "../../../../store/simulation/useVehicleStore"; type VehicleUIProps = { vehicleStatusSample: VehicleEventSchema[]; setVehicleStatusSample: React.Dispatch< React.SetStateAction >; + vehicle: any }; const VehicleUI: React.FC = ({ vehicleStatusSample, setVehicleStatusSample, + vehicle }) => { const { scene: startScene } = useGLTF(startPoint) as any; const { scene: endScene } = useGLTF(startEnd) as any; const { camera, gl, controls } = useThree(); const { selectedEventSphere } = useSelectedEventSphere(); - + const { updateVehicle } = useVehicleStore(); const startMarker = useRef(null); const endMarker = useRef(null); - const hasInitialized = useRef(false); + const hasInitialized = useRef(false); + const raycaster = useRef(new THREE.Raycaster()); + const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Y = 0 plane + const mouse = useRef(new THREE.Vector2()); + const prevMousePos = useRef({ x: 0, y: 0 }); const [draggedMarker, setDraggedMarker] = useState<"start" | "end" | null>( null ); const [dragOffset, setDragOffset] = useState(null); - const [isRotating, setIsRotating] = useState(false); + const [isRotating, setIsRotating] = useState(false); - const raycaster = useRef(new THREE.Raycaster()); - const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Y = 0 plane - const mouse = useRef(new THREE.Vector2()); - const prevMousePos = useRef({ x: 0, y: 0 }); // Initialize start/end markers useEffect(() => { @@ -91,9 +94,8 @@ const VehicleUI: React.FC = ({ pickUpPoint.y, pickUpPoint.z ); - const worldPos = selectedEventSphere.localToWorld(localPos); - worldPos.y = 0; // Force y to 0 - startMarker.current.position.copy(worldPos); + localPos.y = 0; // Force y to 0 + startMarker.current.position.copy(localPos); } else { const defaultLocal = new THREE.Vector3(0, 0, 1.5); const defaultWorld = selectedEventSphere.localToWorld(defaultLocal); @@ -108,9 +110,10 @@ const VehicleUI: React.FC = ({ unLoadPoint.y, unLoadPoint.z ); - const worldPos = selectedEventSphere.localToWorld(localPos); - worldPos.y = 0; // Force y to 0 - endMarker.current.position.copy(worldPos); + + + localPos.y = 0; // Force y to 0 + endMarker.current.position.copy(localPos); } else { const defaultLocal = new THREE.Vector3(0, 0, -1.5); const defaultWorld = selectedEventSphere.localToWorld(defaultLocal); @@ -190,6 +193,7 @@ const VehicleUI: React.FC = ({ z: intersectPoint.z + dragOffset.z, }; + if (draggedMarker === "start" && startMarker.current) { startMarker.current.position.set(newPos.x, newPos.y, newPos.z); } else if (draggedMarker === "end" && endMarker.current) { @@ -215,36 +219,51 @@ const VehicleUI: React.FC = ({ draggedMarker === "start" ? startMarker.current : endMarker.current; if (!marker) return; - const worldPos = marker.position.clone(); - const localPos = selectedEventSphere.worldToLocal(worldPos); + const worldPos = marker.position; - // Direct update (no snapping, ground level forced at y = 0) - const updatedLocalPos = { x: localPos.x, y: 0, z: localPos.z }; + const updatedLocalPos = { x: worldPos.x, y: 0, z: worldPos.z }; + console.log('updatedLocalPos: ', updatedLocalPos); - setVehicleStatusSample((prev) => - prev.map((vehicle) => { - if ( - vehicle.modelUuid === selectedEventSphere.userData.modelUuid && - selectedEventSphere - ) { - const updatedVehicle = { - ...vehicle, - point: { - ...vehicle.point, - action: { - ...vehicle.point?.action, - ...(draggedMarker === "start" - ? { pickUpPoint: updatedLocalPos } - : { unLoadPoint: updatedLocalPos }), - }, - }, - }; - return updatedVehicle; - } - return vehicle; - }) - ); + console.log('draggedMarker: ', draggedMarker); + // setVehicleStatusSample((prev) => + // prev.map((vehicle) => { + // if ( + // vehicle.modelUuid === selectedEventSphere.userData.modelUuid && + // selectedEventSphere + // ) { + // const updatedVehicle = { + // ...vehicle, + // point: { + // ...vehicle.point, + // action: { + // ...vehicle.point?.action, + // ...(draggedMarker === "start" + // ? { pickUpPoint: updatedLocalPos } + // : { unLoadPoint: updatedLocalPos }), + // }, + // }, + // }; + // return updatedVehicle; + // } + // return vehicle; + // }) + // ); + + updateVehicle(selectedEventSphere.userData.modelUuid, { + point: { + ...vehicle?.point, + action: { + ...vehicle?.point?.action, + ...(draggedMarker === "start" + ? { pickUpPoint: updatedLocalPos } + : { unLoadPoint: updatedLocalPos }), + }, + }, + }); + + + setDraggedMarker(null); setDragOffset(null); }; diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index 6e2093e..e4b2ef5 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -1,11 +1,9 @@ import { useEffect, useRef, useState } from 'react' import { useFrame, useThree } from '@react-three/fiber'; -import { useActiveTool, useFloorItems } from '../../../../../store/store'; import * as THREE from 'three'; import { Line } from '@react-three/drei'; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; -import useModuleStore from '../../../../../store/useModuleStore'; interface VehicleAnimatorProps { path: [number, number, number][]; @@ -17,23 +15,24 @@ interface VehicleAnimatorProps { } function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) { + // console.log('path: ', path); const { decrementVehicleLoad } = useVehicleStore(); const { isPaused } = usePauseButtonStore(); const { isPlaying } = usePlayButtonStore(); const { speed } = useAnimationPlaySpeed(); const { isReset, setReset } = useResetButtonStore(); - const [restRotation, setRestingRotation] = useState(true); - const [progress, setProgress] = useState(0); - const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); - const { scene } = useThree(); const progressRef = useRef(0); const movingForward = useRef(true); const completedRef = useRef(false); + const isPausedRef = useRef(false); + const pauseTimeRef = useRef(null); + const [restRotation, setRestingRotation] = useState(true); + const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); + const [progress, setProgress] = useState(0); + const { scene } = useThree(); let startTime: number; let fixedInterval: number; let coveredDistance = progressRef.current; - const isPausedRef = useRef(false); - const pauseTimeRef = useRef(null); useEffect(() => { @@ -73,6 +72,9 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai } }, [isReset, isPlaying]) + useEffect(() => { + isPausedRef.current = isPaused; + }, [isPaused]); useFrame((_, delta) => { const object = scene.getObjectByProperty('uuid', agvUuid); @@ -152,10 +154,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai } }); - useEffect(() => { - isPausedRef.current = isPaused; - }, [isPaused]); - function firstFrame() { const droppedMaterial = agvDetail.currentLoad; startTime = performance.now(); @@ -182,11 +180,8 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai fixedInterval = ((unLoadDuration / agvDetail.currentLoad) * (1000 / speed)); if (elapsedTime >= fixedInterval) { - console.log('elapsedTime: ', elapsedTime); - let droppedMat = droppedMaterial - 1; decrementVehicleLoad(agvDetail.modelUuid, 1); - if (droppedMat > 0) { startTime = performance.now(); requestAnimationFrame(() => step(droppedMat)); diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 3f692d9..570c137 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -3,7 +3,7 @@ import VehicleAnimator from '../animator/vehicleAnimator'; import * as THREE from 'three'; import { NavMeshQuery } from '@recast-navigation/core'; import { useNavMesh } from '../../../../../store/store'; -import { usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; +import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore'; function VehicleInstance({ agvDetail }: any) { @@ -12,7 +12,7 @@ function VehicleInstance({ agvDetail }: any) { const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore(); const [currentPhase, setCurrentPhase] = useState('stationed'); const [path, setPath] = useState<[number, number, number][]>([]); - let isIncrememtable = useRef(true); + let isIncrememtable = useRef(true); const computePath = useCallback( (start: any, end: any) => { @@ -20,7 +20,7 @@ function VehicleInstance({ agvDetail }: any) { const navMeshQuery = new NavMeshQuery(navMesh); const { path: segmentPath } = navMeshQuery.computePath(start, end); return ( - segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || [] + segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [] ); } catch { return []; @@ -41,7 +41,6 @@ function VehicleInstance({ agvDetail }: any) { setPath([]); } - const increment = () => { if (isIncrememtable.current) { console.log('called'); diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx index 2a0070b..aa482c0 100644 --- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -1,14 +1,32 @@ import React from 'react' import VehicleInstance from './instance/vehicleInstance' import { useVehicleStore } from '../../../../store/simulation/useVehicleStore' +import VehicleUI from '../../ui/vehicle/vehicleUI'; +type VehicleUIProps = { + vehicleStatusSample: VehicleEventSchema[]; + setVehicleStatusSample: React.Dispatch< + React.SetStateAction + >; +}; +const VehicleInstances: React.FC = ({ + vehicleStatusSample, + setVehicleStatusSample, +}) => { -function VehicleInstances() { const { vehicles } = useVehicleStore(); + return ( <> {vehicles.map((val: any, i: any) => - + <> + + + )} diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index 65376f2..3b811b3 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -5,133 +5,206 @@ import { useFloorItems } from "../../../store/store"; import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; import VehicleUI from "../ui/vehicle/vehicleUI"; function Vehicles() { - const { vehicles, addVehicle } = useVehicleStore(); - const { selectedEventSphere } = useSelectedEventSphere(); - const { floorItems } = useFloorItems(); + const { vehicles, addVehicle } = useVehicleStore(); - const [vehicleStatusSample, setVehicleStatusSample] = useState< - VehicleEventSchema[] - >([ - - { - modelUuid: "68f8dc55-7802-47fe-aa1c-eade54b4320a", - modelName: "AGV", - position: [89.61609306554463, 0, 33.634136622267356], - rotation: [0, 0, 0], - state: "idle", - type: "vehicle", - speed: 2.5, - point: { - uuid: "point-789", - position: [0, 1, 0], - rotation: [0, 0, 0], - action: { - actionUuid: "action-456", - actionName: "Deliver to Zone A", - actionType: "travel", - unLoadDuration: 10, - loadCapacity: 2, - pickUpPoint: null, - unLoadPoint: null, - triggers: [ - { - triggerUuid: "trig-001", - triggerName: "Start Travel", - triggerType: "onStart", - delay: 0, - triggeredAsset: { - triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - triggeredPoint: { - pointName: "Pickup Arm Point", - pointUuid: "arm-point-01", - }, - triggeredAction: { - actionName: "Grab Widget", - actionUuid: "grab-001", - }, - }, - }, - { - triggerUuid: "trig-002", - triggerName: "Complete Travel", - triggerType: "onComplete", - delay: 2, - triggeredAsset: null, - }, - ], + const { floorItems } = useFloorItems() + + const [vehicleStatusSample, setVehicleStatusSample] = useState< + VehicleEventSchema[] + >([ + { + modelUuid: "9356f710-4727-4b50-bdb2-9c1e747ecc74", + modelName: "AGV", + position: [97.9252965204558, 0, 37.96138815638661], + rotation: [0, 0, 0], + state: "idle", + type: "vehicle", + speed: 2.5, + point: { + uuid: "point-789", + position: [0, 1, 0], + rotation: [0, 0, 0], + action: { + actionUuid: "action-456", + actionName: "Deliver to Zone A", + actionType: "travel", + unLoadDuration: 10, + loadCapacity: 2, + pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, + unLoadPoint: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, + triggers: [ + { + triggerUuid: "trig-001", + triggerName: "Start Travel", + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, + triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, + triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } + } + }, + { + triggerUuid: "trig-002", + triggerName: "Complete Travel", + triggerType: "onComplete", + delay: 2, + triggeredAsset: null + } + ] + } + } }, - }, - }, - { - modelUuid: "3a8f6da6-da57-4ef5-91e3-b8daf89e5753", - modelName: "forklift", - position: [98.85729337188162, 0, 38.36616546567653], - rotation: [0, 0, 0], - state: "idle", - type: "vehicle", - speed: 2.5, - point: { - uuid: "point-789", - position: [0, 1, 0], - rotation: [0, 0, 0], - action: { - actionUuid: "action-456", - actionName: "Deliver to Zone A", - actionType: "travel", - unLoadDuration: 15, - loadCapacity: 5, - pickUpPoint: null, - unLoadPoint: null, - triggers: [ - { - triggerUuid: "trig-001", - triggerName: "Start Travel", - triggerType: "onStart", - delay: 0, - triggeredAsset: { - triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, - triggeredPoint: { - pointName: "Pickup Arm Point", - pointUuid: "arm-point-01", - }, - triggeredAction: { - actionName: "Grab Widget", - actionUuid: "grab-001", - }, - }, - }, - { - triggerUuid: "trig-002", - triggerName: "Complete Travel", - triggerType: "onComplete", - delay: 2, - triggeredAsset: null, - }, - ], + { + modelUuid: "b06960bb-3d2e-41f7-a646-335f389c68b4", + modelName: "AGV", + position: [89.61609306554463, 0, 33.634136622267356], + rotation: [0, 0, 0], + state: "idle", + type: "vehicle", + speed: 2.5, + point: { + uuid: "point-789", + position: [0, 1, 0], + rotation: [0, 0, 0], + action: { + actionUuid: "action-456", + actionName: "Deliver to Zone A", + actionType: "travel", + unLoadDuration: 10, + loadCapacity: 2, + pickUpPoint: null, + unLoadPoint: null, + triggers: [ + { + triggerUuid: "trig-001", + triggerName: "Start Travel", + triggerType: "onStart", + delay: 0, + triggeredAsset: { + triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, + triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, + triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } + } + }, + { + triggerUuid: "trig-002", + triggerName: "Complete Travel", + triggerType: "onComplete", + delay: 2, + triggeredAsset: null + } + ] + } + } }, - }, - }, - ]); - // useEffect(()) - console.log("vehicleStatusSample", vehicleStatusSample); - useEffect(() => { - addVehicle("123", vehicleStatusSample[0]); - // addVehicle('123', vehicleStatusSample[1]); - // addVehicle('123', vehicleStatusSample[2]); - }, []); + { + modelUuid: "cd7d0584-0684-42b4-b051-9e882c1914aa", + modelName: "AGV", + position: [105.90938758014703, 0, 31.584209911095215], + rotation: [0, 0, 0], + state: "idle", + type: "vehicle", + speed: 2.5, + point: { + uuid: "point-789", + position: [0, 1, 0], + rotation: [0, 0, 0], + action: { + actionUuid: "action-456", + actionName: "Deliver to Zone A", + actionType: "travel", + unLoadDuration: 10, + loadCapacity: 2, + pickUpPoint: null, + unLoadPoint: null, + triggers: [ + { + triggerUuid: "trig-001", + triggerName: "Start Travel", + triggerType: "onStart", + delay: 0, + triggeredAsset: { + triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, + triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, + triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } + } + }, + { + triggerUuid: "trig-002", + triggerName: "Complete Travel", + triggerType: "onComplete", + delay: 2, + triggeredAsset: null + } + ] + } + } + }, + // { + // modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79", + // modelName: "forklift", + // position: [98.85729337188162, 0, 38.36616546567653], + // rotation: [0, 0, 0], + // state: "idle", + // type: "vehicle", + // speed: 2.5, + // point: { + // uuid: "point-789", + // position: [0, 1, 0], + // rotation: [0, 0, 0], + // action: { + // actionUuid: "action-456", + // actionName: "Deliver to Zone A", + // actionType: "travel", + // unLoadDuration: 15, + // loadCapacity: 5, + // pickUpPoint: null, + // unLoadPoint: null, + // triggers: [ + // { + // triggerUuid: "trig-001", + // triggerName: "Start Travel", + // triggerType: "onStart", + // delay: 0, + // triggeredAsset: { + // triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" }, + // triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" }, + // triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" } + // } + // }, + // { + // triggerUuid: "trig-002", + // triggerName: "Complete Travel", + // triggerType: "onComplete", + // delay: 2, + // triggeredAsset: null + // } + // ] + // } + // } + // } + ]); + useEffect(() => { + console.log("vehicles", vehicles); + }, [vehicles]) + useEffect(() => { + addVehicle("123", vehicleStatusSample[0]); + addVehicle('123', vehicleStatusSample[1]); + addVehicle('123', vehicleStatusSample[2]); + }, []); - useEffect(() => {}, [vehicles]); - - return ( - <> - - - - ); + return ( + <> + + {/* */} + + ); } export default Vehicles; From ab5ade7bee51db8338f533f366c11b59ac61ded8 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 29 Apr 2025 13:42:24 +0530 Subject: [PATCH 20/30] feat: Enhance camera control and user experience with improved key handling and speed adjustments --- .../components/layout/sidebarRight/Header.tsx | 8 +- app/src/modules/builder/groups/zoneGroup.tsx | 15 +- app/src/modules/scene/camera/camMode.tsx | 220 +++++++++++------- app/src/types/world/worldConstants.ts | 8 +- .../utils/shortcutkeys/handleShortcutKeys.ts | 2 +- 5 files changed, 160 insertions(+), 93 deletions(-) diff --git a/app/src/components/layout/sidebarRight/Header.tsx b/app/src/components/layout/sidebarRight/Header.tsx index a449500..a88baee 100644 --- a/app/src/components/layout/sidebarRight/Header.tsx +++ b/app/src/components/layout/sidebarRight/Header.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { AppDockIcon } from "../../icons/HeaderIcons"; import orgImg from "../../../assets/orgTemp.png"; import { useActiveUsers } from "../../../store/store"; @@ -8,7 +8,7 @@ import { getAvatarColor } from "../../../modules/collaboration/functions/getAvat const Header: React.FC = () => { const { activeUsers } = useActiveUsers(); - const userName = localStorage.getItem("userName") || "Anonymous"; + const userName = localStorage.getItem("userName") ?? "Anonymous"; const guestUsers: ActiveUser[] = activeUsers.filter( (user: ActiveUser) => user.userName !== userName @@ -23,14 +23,14 @@ const Header: React.FC = () => { )}
    -
    { setUserManagement(true); }} > Share -
    + {/*
    */} diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index d218534..f1818f3 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -69,7 +69,9 @@ const ZoneGroup: React.FC = () => { }, transparent: true, depthWrite: false, - }), []); + }), + [] + ); useEffect(() => { const fetchZones = async () => { @@ -148,6 +150,7 @@ const ZoneGroup: React.FC = () => { } }, [toolMode, toggleView]); + // eslint-disable-next-line react-hooks/exhaustive-deps const addZoneToBackend = async (zone: { zoneId: string; zoneName: string; @@ -503,6 +506,15 @@ const ZoneGroup: React.FC = () => { draggedSphere, movePoint, activeLayer, + raycaster, + pointer, + controls, + plane, + setZones, + setZonePoints, + addZoneToBackend, + handleDeleteZone, + updateZoneToBackend, ]); useFrame(() => { @@ -551,6 +563,7 @@ const ZoneGroup: React.FC = () => { key={index} position={midpoint} rotation={[0, -angle, 0]} + // visible={false} > { - const { camMode, setCamMode } = useCamMode(); - const [, get] = useKeyboardControls() - const [isTransitioning, setIsTransitioning] = useState(false); - const state: any = useThree(); - const { toggleView } = useToggleView(); + const { camMode, setCamMode } = useCamMode(); + const [, get] = useKeyboardControls(); + const [isTransitioning, setIsTransitioning] = useState(false); + const state: any = useThree(); + const { toggleView } = useToggleView(); + const [isShiftActive, setIsShiftActive] = useState(false); - useEffect(() => { - const handlePointerLockChange = async () => { - if (document.pointerLockElement && !toggleView) { - // console.log('Pointer is locked'); - } else { - // console.log('Pointer is unlocked'); - if (camMode === "FirstPerson" && !toggleView) { - setCamMode("ThirdPerson"); - await switchToThirdPerson(state.controls, state.camera); - } - } - }; - - document.addEventListener('pointerlockchange', handlePointerLockChange); - - return () => { - document.removeEventListener('pointerlockchange', handlePointerLockChange); - }; - }, [camMode, toggleView, setCamMode, state.controls, state.camera]); - - useEffect(() => { - const handleKeyPress = async (event: any) => { - if (!state.controls) return; - - const keyCombination = detectModifierKeys(event); - - if (keyCombination === "/" && !isTransitioning && !toggleView) { - setIsTransitioning(true); - state.controls.mouseButtons.left = CONSTANTS.controlsTransition.leftMouse; - state.controls.mouseButtons.right = CONSTANTS.controlsTransition.rightMouse; - state.controls.mouseButtons.wheel = CONSTANTS.controlsTransition.wheelMouse; - state.controls.mouseButtons.middle = CONSTANTS.controlsTransition.middleMouse; - - if (camMode === 'ThirdPerson') { - setCamMode("FirstPerson"); - await switchToFirstPerson(state.controls, state.camera); - } else if (camMode === "FirstPerson") { - setCamMode("ThirdPerson"); - await switchToThirdPerson(state.controls, state.camera); - } - - setIsTransitioning(false); - } - }; - - window.addEventListener("keydown", handleKeyPress); - return () => { - window.removeEventListener("keydown", handleKeyPress); - }; - }, [camMode, isTransitioning, toggleView, state.controls, state.camera, setCamMode]); - - useFrame(() => { - const { forward, backward, left, right } = get(); - if (!state.controls) return - if (!state.controls || camMode === "ThirdPerson" || !document.pointerLockElement) return; - - if (forward) { - state.controls.forward(CONSTANTS.firstPersonControls.forwardSpeed, true) + useEffect(() => { + const handlePointerLockChange = async () => { + if (document.pointerLockElement && !toggleView) { + // Pointer is locked + } else { + // Pointer is unlocked + if (camMode === "FirstPerson" && !toggleView) { + setCamMode("ThirdPerson"); + await switchToThirdPerson(state.controls, state.camera); } - if (backward) { - state.controls.forward(CONSTANTS.firstPersonControls.backwardSpeed, true) - } - if (left) { - state.controls.truck(CONSTANTS.firstPersonControls.leftSpeed, 0, true) - } - if (right) { - state.controls.truck(CONSTANTS.firstPersonControls.rightSpeed, 0, true) - } - }); + } + }; - return null; // This component does not render any UI + document.addEventListener("pointerlockchange", handlePointerLockChange); + + return () => { + document.removeEventListener( + "pointerlockchange", + handlePointerLockChange + ); + }; + }, [camMode, toggleView, setCamMode, state.controls, state.camera]); + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Shift") { + setIsShiftActive(true); + } + }; + + const handleKeyUp = (event: KeyboardEvent) => { + if (event.key === "Shift") { + setIsShiftActive(false); + } + }; + + window.addEventListener("keydown", handleKeyDown); + window.addEventListener("keyup", handleKeyUp); + + return () => { + window.removeEventListener("keydown", handleKeyDown); + window.removeEventListener("keyup", handleKeyUp); + }; + }, []); + + useEffect(() => { + const handleKeyPress = async (event: KeyboardEvent) => { + if (!state.controls) return; + + const keyCombination = detectModifierKeys(event); + + if (keyCombination === "/" && !isTransitioning && !toggleView) { + setIsTransitioning(true); + + state.controls.mouseButtons.left = + CONSTANTS.controlsTransition.leftMouse; + state.controls.mouseButtons.right = + CONSTANTS.controlsTransition.rightMouse; + state.controls.mouseButtons.wheel = + CONSTANTS.controlsTransition.wheelMouse; + state.controls.mouseButtons.middle = + CONSTANTS.controlsTransition.middleMouse; + + if (camMode === "ThirdPerson") { + setCamMode("FirstPerson"); + await switchToFirstPerson(state.controls, state.camera); + } else if (camMode === "FirstPerson") { + setCamMode("ThirdPerson"); + await switchToThirdPerson(state.controls, state.camera); + } + + setIsTransitioning(false); + } + }; + + window.addEventListener("keydown", handleKeyPress); + return () => { + window.removeEventListener("keydown", handleKeyPress); + }; + }, [ + camMode, + isTransitioning, + toggleView, + state.controls, + state.camera, + setCamMode, + ]); + + useFrame(() => { + const { forward, backward, left, right } = get(); + if (!state.controls) return; + if (camMode === "ThirdPerson" || !document.pointerLockElement) return; + + const speedMultiplier = isShiftActive ? 4 : 1; + + if (forward) { + state.controls.forward( + CONSTANTS.firstPersonControls.forwardSpeed * speedMultiplier, + true + ); + } + if (backward) { + state.controls.forward( + CONSTANTS.firstPersonControls.backwardSpeed * speedMultiplier, + true + ); + } + if (left) { + state.controls.truck( + CONSTANTS.firstPersonControls.leftSpeed * speedMultiplier, + 0, + true + ); + } + if (right) { + state.controls.truck( + CONSTANTS.firstPersonControls.rightSpeed * speedMultiplier, + 0, + true + ); + } + }); + + return null; // This component does not render any UI }; -export default CamMode; \ No newline at end of file +export default CamMode; diff --git a/app/src/types/world/worldConstants.ts b/app/src/types/world/worldConstants.ts index 924c12c..0374c8a 100644 --- a/app/src/types/world/worldConstants.ts +++ b/app/src/types/world/worldConstants.ts @@ -189,10 +189,10 @@ export const firstPersonControls: Controls = { maxDistance: 0, // Maximum distance from the target maxPolarAngle: Math.PI, // Maximum polar angle leftMouse: 1, // Mouse button for rotation (ROTATE) - forwardSpeed: 0.3, // Speed of forward movement - backwardSpeed: -0.3, // Speed of backward movement - leftSpeed: -0.3, // Speed of left movement - rightSpeed: 0.3, // Speed of right movement + forwardSpeed: 0.1, // Speed of forward movement + backwardSpeed: -0.1, // Speed of backward movement + leftSpeed: -0.1, // Speed of left movement + rightSpeed: 0.1, // Speed of right movement }; export const thirdPersonControls: ThirdPersonControls = { diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts index 43ca553..52877b9 100644 --- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts +++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts @@ -190,7 +190,7 @@ const KeyPressListener: React.FC = () => { return () => { window.removeEventListener("keydown", handleKeyPress); }; - }, [activeModule, toggleUI, toggleView]); // Dependencies to reapply effect if these values change + }, [activeModule, setActiveModule, setActiveSubTool, setActiveTool, setAddAction, setDeleteTool, setIsPlaying, setSelectedWallItem, setToggleThreeD, setToggleUI, setToggleView, setToolMode, toggleUI, toggleView]); // Dependencies to reapply effect if these values change return null; // This component does not render any UI }; From 77a6dda068ee2d70e0594b1d4145ca05bf2e42fa Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 29 Apr 2025 14:58:58 +0530 Subject: [PATCH 21/30] feat: Add icon color variables for light and dark themes --- app/src/styles/abstracts/variables.scss | 11 ++ app/src/styles/base/base.scss | 203 +++++++++++++----------- 2 files changed, 121 insertions(+), 93 deletions(-) diff --git a/app/src/styles/abstracts/variables.scss b/app/src/styles/abstracts/variables.scss index 6bb3d57..8400709 100644 --- a/app/src/styles/abstracts/variables.scss +++ b/app/src/styles/abstracts/variables.scss @@ -60,6 +60,17 @@ $highlight-secondary-color: #6F42C1; $highlight-accent-color-dark: #403E6A; $highlight-secondary-color-dark: #C4ABF1; +// icon colors +// ---------- light mode ---------- +$icon-default-color: #6F42C1; +$icon-default-color-hover: #7f4ddb; +$icon-default-color-active: #F2F2F7; + +// ---------- dark mode ---------- +$icon-default-color-dark: #6F42C1; +$icon-default-color-hover-dark: #7f4ddb; +$icon-default-color-active-dark: #F2F2F7; + // colors $color1: #A392CD; $color2: #7b4cd3; diff --git a/app/src/styles/base/base.scss b/app/src/styles/base/base.scss index e74c0ec..d812e9b 100644 --- a/app/src/styles/base/base.scss +++ b/app/src/styles/base/base.scss @@ -1,139 +1,156 @@ -@use "../abstracts/variables" as *; // abstracts/variables.scss +@use "../abstracts/variables" as *; -// Light theme styles [data-theme="light"] { - // Text and Input colors - --text-color: #{$text-color}; // Main text color for light theme - --text-disabled: #{$text-disabled}; // Disabled text color - --input-text-color: #{$input-text-color}; // Input field text color + // text colors + --text-color: #{$text-color}; + --text-disabled: #{$text-disabled}; + --input-text-color: #{$input-text-color}; + --highlight-text-color: #{$highlight-text-color}; - // Accent and Highlight colors - --primary-color: #{$background-color}; // Primary color for light theme - --accent-color: #{$accent-color}; // Primary accent color for light theme - --highlight-accent-color: #{$highlight-accent-color}; // Highlight color for light theme - --accent-gradient-color: #{$acent-gradient}; // Primary accent color for light theme + // background colors + --background-color: #{$background-color}; + --background-color-secondary: #{$background-color-secondary}; + --background-color-accent: #{$background-color-accent}; + --background-color-button: #{$background-color-button}; + --background-color-drop-down: #{$background-color-drop-down}; + --background-color-input: #{$background-color-input}; + --background-color-input-focus: #{$background-color-input-focus}; + --background-color-drop-down-gradient: #{$background-color-drop-down-gradient}; + --background-color-selected: #{$background-color-selected}; + --background-radial-gray-gradient: #{$background-radial-gray-gradient}; + + // border colors + --border-color: #{$border-color}; + --border-color-accent: #{$border-color-accent}; + + // highlight colors + --highlight-accent-color: #{$highlight-accent-color}; + --highlight-secondary-color: #{$highlight-secondary-color}; + + // icon colors + --icon-default-color: #{$icon-default-color}; + --icon-default-color-active: #{$icon-default-color-active}; + + // old colors + --accent-color: #{$accent-color}; + --highlight-accent-color: #{$highlight-accent-color}; + --accent-gradient-color: #{$acent-gradient}; --faint-gradient-color: #{$faint-gradient}; - - // Background colors - --background-color: #{$background-color}; // Main background color - --background-color-secondary: #{$background-color-secondary}; // Secondary background color - --background-color-gray: #{$background-color-gray}; // Secondary background color - - // Border colors - --border-color: #{$border-color}; // Border color for light theme - - // Shadow variables - --shadow-main-light: #{$shadow-color}; // Main shadow color - --box-shadow-light: 0px 2px 4px var(--shadow-main-light); // Light shadow - --box-shadow-medium: 0px 4px 8px var(--shadow-main-light); // Medium shadow - --box-shadow-heavy: 0px 8px 16px var(--shadow-main-light); // Heavy shadow - - // Font families - --font-inter: #{$font-inter}; // Inter font family - --font-josefin-sans: #{$font-josefin-sans}; // Josefin Sans font family - --font-poppins: #{$font-poppins}; // Poppins font family - --font-roboto: #{$font-roboto}; // Roboto font family + --background-color-gray: #{$background-color-gray}; + --border-color: #{$border-color}; + --shadow-main-light: #{$shadow-color}; + --box-shadow-light: 0px 2px 4px var(--shadow-main-light); + --box-shadow-medium: 0px 4px 8px var(--shadow-main-light); + --box-shadow-heavy: 0px 8px 16px var(--shadow-main-light); + --font-inter: #{$font-inter}; + --font-josefin-sans: #{$font-josefin-sans}; + --font-poppins: #{$font-poppins}; + --font-roboto: #{$font-roboto}; } -// Dark theme styles [data-theme="dark"] { - // Text and Input colors - --text-color: #{$text-color-dark}; // Main text color for dark theme - --text-disabled: #{$text-disabled-dark}; // Disabled text color - --input-text-color: #{$input-text-color-dark}; // Input field text color + // text colors + --text-color: #{$text-color-dark}; + --text-disabled: #{$text-disabled-dark}; + --input-text-color: #{$input-text-color-dark}; + --highlight-text-color: #{$highlight-text-color-dark}; - // Accent and Highlight colors - --primary-color: #{$highlight-accent-color-dark}; - --accent-color: #{$accent-color-dark}; // Primary accent color for dark theme - --highlight-accent-color: #{$highlight-accent-color-dark}; // Highlight color for dark theme - --accent-gradient-color: #{$acent-gradient-dark}; // Primary accent color for light theme + // background colors + --background-color: #{$background-color-dark}; + --background-color-secondary: #{$background-color-secondary-dark}; + --background-color-accent: #{$background-color-accent-dark}; + --background-color-button: #{$background-color-button-dark}; + --background-color-drop-down: #{$background-color-drop-down-dark}; + --background-color-input: #{$background-color-input-dark}; + --background-color-input-focus: #{$background-color-input-focus-dark}; + --background-color-drop-down-gradient: #{$background-color-drop-down-gradient-dark}; + --background-color-selected: #{$background-color-selected-dark}; + --background-radial-gray-gradient: #{$background-radial-gray-gradient-dark}; + + // border colors + --border-color: #{$border-color}; + --border-color-accent: #{$border-color-accent-dark}; + + // highlight colors + --highlight-accent-color: #{$highlight-accent-color-dark}; + --highlight-secondary-color: #{$highlight-secondary-color-dark}; + + // icon colors + --icon-default-color: #{$icon-default-color-dark}; + --icon-default-color-active: #{$icon-default-color-active-dark}; + + // old colors + --accent-color: #{$accent-color-dark}; + --highlight-accent-color: #{$highlight-accent-color-dark}; + --accent-gradient-color: #{$acent-gradient-dark}; --faint-gradient-color: #{$faint-gradient-dark}; - - // Background colors - --background-color: #{$background-color-dark}; // Main background color - --background-color-secondary: #{$background-color-secondary-dark}; // Secondary background color - --background-color-gray: #{$background-color-gray-dark}; // Secondary background color - - // Border colors - --border-color: #{$border-color-dark}; // Border color for dark theme - - // Shadow variables - --shadow-main-dark: #{$shadow-color}; // Main shadow color - --box-shadow-light: 0px 2px 4px var(--shadow-main-dark); // Light shadow - --box-shadow-medium: 0px 4px 8px var(--shadow-main-dark); // Medium shadow - --box-shadow-heavy: 0px 8px 16px var(--shadow-main-dark); // Heavy shadow - - // Font families - --font-inter: #{$font-inter}; // Inter font family - --font-josefin-sans: #{$font-josefin-sans}; // Josefin Sans font family - --font-poppins: #{$font-poppins}; // Poppins font family - --font-roboto: #{$font-roboto}; // Roboto font family + --background-color-gray: #{$background-color-gray-dark}; + --border-color: #{$border-color-dark}; + --shadow-main-dark: #{$shadow-color}; + --box-shadow-light: 0px 2px 4px var(--shadow-main-dark); + --box-shadow-medium: 0px 4px 8px var(--shadow-main-dark); + --box-shadow-heavy: 0px 8px 16px var(--shadow-main-dark); + --font-inter: #{$font-inter}; + --font-josefin-sans: #{$font-josefin-sans}; + --font-poppins: #{$font-poppins}; + --font-roboto: #{$font-roboto}; } -// Root container styles #root { - height: 100vh; // Full viewport height - width: 100vw; // Full viewport width - overflow: hidden; // Prevent scrollbars + height: 100vh; + width: 100vw; + overflow: hidden; background-color: var(--background-color-gray); } -// Root overlay styles #root-over { - position: fixed; // Fix overlay to the viewport - top: 0; // Align to the top - left: 0; // Align to the left - z-index: 99; // Ensure high stacking order + position: fixed; + top: 0; + left: 0; + z-index: 99; } body { background: var(--background-color); + --font-size-tiny: #{$tiny}; + --font-size-small: #{$small}; + --font-size-regular: #{$regular}; + --font-size-large: #{$large}; + --font-size-xlarge: #{$xlarge}; + --font-size-xxlarge: #{$xxlarge}; + --font-size-xxxlarge: #{$xxxlarge}; + --font-weight-regular: #{$regular-weight}; + --font-weight-medium: #{$medium-weight}; + --font-weight-bold: #{$bold-weight}; - /* Font Sizes */ - --font-size-tiny: #{$tiny}; // Extra small text - --font-size-small: #{$small}; // Small text - --font-size-regular: #{$regular}; // Default text size - --font-size-large: #{$large}; // Large text size - --font-size-xlarge: #{$xlarge}; // Extra large text size - --font-size-xxlarge: #{$xxlarge}; // Double extra large text size - --font-size-xxxlarge: #{$xxxlarge}; // Triple extra large text size - - /* Font Weights */ - --font-weight-regular: #{$regular-weight}; // Regular font weight - --font-weight-medium: #{$medium-weight}; // Medium font weight - --font-weight-bold: #{$bold-weight}; // Bold font weight + // colors + --color1: #{$color1}; + --color2: #{$color2}; + --color3: #{$color3}; + --color4: #{$color4}; + --color5: #{$color5}; } -/* Apply custom scrollbar styles globally */ ::-webkit-scrollbar { width: 8px; - /* Width of the scrollbar */ height: 8px; - /* Height for horizontal scrollbars */ } ::-webkit-scrollbar-track { background: transparent; - /* Background of the scrollbar track */ border-radius: 4px; - /* Rounded corners */ } ::-webkit-scrollbar-thumb { background: var(--accent-color); - /* Scrollbar handle color */ border-radius: 4px; - /* Rounded corners */ border: 2px solid var(--primary-color); - /* Padding around the scrollbar handle */ } ::-webkit-scrollbar-thumb:hover { background: var(--accent-color); - /* Handle color on hover */ } ::-webkit-scrollbar-corner { background: transparent; - /* Remove corner styling for scrollable containers */ } From 45fea9465ef7d07cf79123b6bdf5fe972cd93869 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 29 Apr 2025 16:27:03 +0530 Subject: [PATCH 22/30] Refactor styles to use 'background' shorthand property instead of 'background-color' for consistency across components. Updated various components including confirmation pop-up, input fields, lists, marketplace, menu, module toggle, simulation, and more. Enhanced visual effects with backdrop filters and adjusted padding/margins for improved layout. Removed unnecessary styles and optimized hover effects for better user experience. --- app/src/components/icons/ContextMenuIcons.tsx | 34 +++---- app/src/components/icons/DashboardIcon.tsx | 86 ++++++++--------- .../components/icons/ExportCommonIcons.tsx | 90 ++++++++--------- .../components/icons/ExportModuleIcons.tsx | 40 ++++---- app/src/components/icons/ExportToolsIcons.tsx | 84 ++++++++-------- app/src/components/icons/HeaderIcons.tsx | 18 ++-- app/src/components/icons/Logo.tsx | 68 ++++++------- .../icons/RealTimeVisulationIcons.tsx | 14 +-- app/src/components/icons/SimulationIcons.tsx | 30 +++--- app/src/components/icons/marketPlaceIcons.tsx | 10 +- app/src/modules/builder/groups/zoneGroup.tsx | 2 +- app/src/modules/market/CardsContainer.tsx | 50 +++++----- .../widgets/panel/AddButtons.tsx | 8 +- app/src/styles/abstracts/variables.scss | 17 ++-- app/src/styles/base/base.scss | 15 +-- app/src/styles/base/global.scss | 6 +- .../styles/components/analysis/analysis.scss | 18 ++-- .../styles/components/confirmationPopUp.scss | 4 +- app/src/styles/components/input.scss | 96 ++++++++----------- app/src/styles/components/lists.scss | 10 +- .../components/marketPlace/marketPlace.scss | 39 ++++---- app/src/styles/components/menu/menu.scss | 14 +-- app/src/styles/components/moduleToggle.scss | 11 ++- .../components/simulation/simulation.scss | 6 +- app/src/styles/components/templates.scss | 2 +- app/src/styles/components/tools.scss | 19 ++-- .../visualization/floating/common.scss | 20 ++-- .../visualization/ui/styledWidgets.scss | 2 +- app/src/styles/layout/loading.scss | 2 +- app/src/styles/layout/popup.scss | 12 +-- app/src/styles/layout/sidebar.scss | 73 +++++++------- app/src/styles/layout/toast.scss | 8 +- app/src/styles/pages/dashboard.scss | 8 +- app/src/styles/pages/home.scss | 35 ------- app/src/styles/pages/realTimeViz.scss | 58 +++++------ app/src/styles/pages/userAuth.scss | 2 +- app/src/styles/scene/scene.scss | 5 +- 37 files changed, 491 insertions(+), 525 deletions(-) diff --git a/app/src/components/icons/ContextMenuIcons.tsx b/app/src/components/icons/ContextMenuIcons.tsx index 217ad8f..f48cf3b 100644 --- a/app/src/components/icons/ContextMenuIcons.tsx +++ b/app/src/components/icons/ContextMenuIcons.tsx @@ -9,31 +9,31 @@ export function FlipXAxisIcon() { > @@ -52,31 +52,31 @@ export function FlipYAxisIcon() { > @@ -95,31 +95,31 @@ export function FlipZAxisIcon() { ); diff --git a/app/src/components/icons/DashboardIcon.tsx b/app/src/components/icons/DashboardIcon.tsx index f1f4d7d..314a3c8 100644 --- a/app/src/components/icons/DashboardIcon.tsx +++ b/app/src/components/icons/DashboardIcon.tsx @@ -9,13 +9,13 @@ export function NotificationIcon() { > @@ -34,7 +34,7 @@ export function HomeIcon() { > ); @@ -51,7 +51,7 @@ export function ProjectsIcon() { > ); @@ -70,103 +70,103 @@ export function TutorialsIcon() { cx="8.157" cy="8.35866" r="6.17928" - stroke="var(--text-color)" + stroke="var(--icon-default-color)" strokeWidth="0.562865" /> @@ -184,12 +184,12 @@ export function DocumentationIcon() { > @@ -208,7 +208,7 @@ export function HelpIcon() { @@ -236,17 +236,17 @@ export function LogoutIcon() { > diff --git a/app/src/components/icons/ExportCommonIcons.tsx b/app/src/components/icons/ExportCommonIcons.tsx index fcf7202..f6f0287 100644 --- a/app/src/components/icons/ExportCommonIcons.tsx +++ b/app/src/components/icons/ExportCommonIcons.tsx @@ -24,7 +24,7 @@ export function ArrowIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - + ); } @@ -40,14 +40,14 @@ export function FocusIcon() { > @@ -65,7 +65,7 @@ export function LockIcon({ isLocked }: { isLocked: boolean }) { > @@ -80,7 +80,7 @@ export function LockIcon({ isLocked }: { isLocked: boolean }) { > @@ -100,7 +100,7 @@ export function EyeIcon({ isClosed }: { isClosed: boolean }) { @@ -119,13 +119,13 @@ export function EyeIcon({ isClosed }: { isClosed: boolean }) { > @@ -142,9 +142,9 @@ export function KebebIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - - - + + + ); } @@ -160,7 +160,7 @@ export function AddIcon() { > @@ -179,12 +179,12 @@ export function CloseIcon() { > @@ -203,11 +203,11 @@ export function SettingsIcon() { @@ -231,7 +231,7 @@ export function HelpIcon() { @@ -255,7 +255,7 @@ export function TrashIcon() { @@ -280,32 +280,32 @@ export function FilterIcon() { > @@ -324,7 +324,7 @@ export function EyeDroperIcon({ isActive }: { isActive: boolean }) { @@ -387,7 +387,7 @@ export function UndoIcon() { fillRule="evenodd" clipRule="evenodd" d="M3.76516 1.73483C3.91161 1.88128 3.91161 2.11872 3.76516 2.26516L2.90533 3.125H7.5C9.0878 3.125 10.375 4.41218 10.375 6C10.375 7.5878 9.0878 8.875 7.5 8.875H4C3.79289 8.875 3.625 8.7071 3.625 8.5C3.625 8.2929 3.79289 8.125 4 8.125H7.5C8.6736 8.125 9.625 7.1736 9.625 6C9.625 4.82639 8.6736 3.875 7.5 3.875H2.90533L3.76516 4.73483C3.91161 4.88128 3.91161 5.1187 3.76516 5.26515C3.61872 5.4116 3.38128 5.4116 3.23483 5.26515L1.73483 3.76516C1.58839 3.61872 1.58839 3.38128 1.73483 3.23483L3.23483 1.73483C3.38128 1.58839 3.61872 1.58839 3.76516 1.73483Z" - fill="var(--text-color)" + fill="var(--icon-default-color)" /> ); @@ -406,7 +406,7 @@ export function RedoIcon() { fillRule="evenodd" clipRule="evenodd" d="M8.23484 1.73483C8.08839 1.88128 8.08839 2.11872 8.23484 2.26516L9.09467 3.125H4.5C2.9122 3.125 1.625 4.41218 1.625 6C1.625 7.5878 2.9122 8.875 4.5 8.875H8C8.20711 8.875 8.375 8.7071 8.375 8.5C8.375 8.2929 8.20711 8.125 8 8.125H4.5C3.3264 8.125 2.375 7.1736 2.375 6C2.375 4.82639 3.3264 3.875 4.5 3.875H9.09467L8.23484 4.73483C8.08839 4.88128 8.08839 5.1187 8.23484 5.26515C8.38128 5.4116 8.61872 5.4116 8.76517 5.26515L10.2652 3.76516C10.4116 3.61872 10.4116 3.38128 10.2652 3.23483L8.76517 1.73483C8.61872 1.58839 8.38128 1.58839 8.23484 1.73483Z" - fill="var(--text-color)" + fill="var(--icon-default-color)" /> ); @@ -442,7 +442,7 @@ export function RemoveIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - + ); } @@ -458,11 +458,11 @@ export function InfoIcon() { > ); @@ -512,21 +512,21 @@ export const KebabIcon = () => { cy="1.35112" rx="1.4993" ry="1.27477" - fill="var(--text-color)" + fill="var(--icon-default-color)" /> ); @@ -545,7 +545,7 @@ export const DublicateIcon = () => { fillRule="evenodd" clipRule="evenodd" d="M14.3125 11.375C14.3125 11.7545 14.0045 12.0625 13.625 12.0625H8.125C7.7455 12.0625 7.4375 11.7545 7.4375 11.375V5.875C7.4375 5.4955 7.7455 5.1875 8.125 5.1875H13.625C14.0045 5.1875 14.3125 5.4955 14.3125 5.875V11.375ZM13.625 4.5H8.125C7.36566 4.5 6.75 5.11566 6.75 5.875V11.375C6.75 12.1343 7.36566 12.75 8.125 12.75H13.625C14.3843 12.75 15 12.1343 15 11.375V5.875C15 5.11566 14.3843 4.5 13.625 4.5ZM11.5625 14.125C11.5625 14.5045 11.2545 14.8125 10.875 14.8125H5.375C4.9955 14.8125 4.6875 14.5045 4.6875 14.125V8.625C4.6875 8.2455 4.9955 7.9375 5.375 7.9375H6.0625V7.25H5.375C4.61566 7.25 4 7.86566 4 8.625V14.125C4 14.8843 4.61566 15.5 5.375 15.5H10.875C11.6343 15.5 12.25 14.8843 12.25 14.125V13.4375H11.5625V14.125Z" - fill="var(--text-color)" + fill="var(--icon-default-color)" /> ); @@ -562,31 +562,31 @@ export const DeleteIcon = () => { > diff --git a/app/src/components/icons/ExportModuleIcons.tsx b/app/src/components/icons/ExportModuleIcons.tsx index fb2f566..1dda323 100644 --- a/app/src/components/icons/ExportModuleIcons.tsx +++ b/app/src/components/icons/ExportModuleIcons.tsx @@ -10,8 +10,8 @@ export function BuilderIcon({ isActive }: { isActive: boolean }) { > @@ -29,41 +29,41 @@ export function SimulationIcon({ isActive }: { isActive: boolean }) { > @@ -81,19 +81,19 @@ export function VisualizationIcon({ isActive }: { isActive: boolean }) { > @@ -112,20 +112,20 @@ export function CartIcon({ isActive }: { isActive: boolean }) { > diff --git a/app/src/components/icons/ExportToolsIcons.tsx b/app/src/components/icons/ExportToolsIcons.tsx index 478113c..cfe56ba 100644 --- a/app/src/components/icons/ExportToolsIcons.tsx +++ b/app/src/components/icons/ExportToolsIcons.tsx @@ -11,13 +11,13 @@ export function ZoneIcon({ isActive }: { isActive: boolean }) { @@ -41,27 +41,27 @@ export function AsileIcon({ isActive }: { isActive: boolean }) { > ); @@ -87,36 +87,36 @@ export function FloorIcon({ isActive }: { isActive: boolean }) { ); @@ -212,56 +212,56 @@ export function WallIcon({ isActive }: { isActive: boolean }) { @@ -305,7 +305,7 @@ export function WindowIcon({ isActive }: { isActive: boolean }) { > @@ -349,7 +349,7 @@ export function DoorIcon({ isActive }: { isActive: boolean }) { > ); @@ -393,17 +393,17 @@ export function PillerIcon({ isActive }: { isActive: boolean }) { > @@ -444,16 +444,16 @@ export function CommentIcon({ isActive }: { isActive: boolean }) { > @@ -485,7 +485,7 @@ export function FreeMoveIcon({ isActive }: { isActive: boolean }) { > ); @@ -533,7 +533,7 @@ export function DeleteIcon({ isActive }: { isActive: boolean }) { > @@ -565,7 +565,7 @@ export function CursorIcon({ isActive }: { isActive: boolean }) { > @@ -584,7 +584,7 @@ export function PlayIcon({ isActive }: { isActive: boolean }) { > @@ -603,7 +603,7 @@ export function PenIcon({ isActive }: { isActive: boolean }) { @@ -623,13 +623,13 @@ export function SaveTemplateIcon({ isActive }: { isActive: boolean }) { @@ -648,19 +648,19 @@ export function MeasureToolIcon({ isActive }: { isActive: boolean }) { > ); diff --git a/app/src/components/icons/HeaderIcons.tsx b/app/src/components/icons/HeaderIcons.tsx index 81f3690..ef02f02 100644 --- a/app/src/components/icons/HeaderIcons.tsx +++ b/app/src/components/icons/HeaderIcons.tsx @@ -65,15 +65,15 @@ export function AppDockIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - - - - - - - - - + + + + + + + + + ); } diff --git a/app/src/components/icons/Logo.tsx b/app/src/components/icons/Logo.tsx index d15398c..822e83e 100644 --- a/app/src/components/icons/Logo.tsx +++ b/app/src/components/icons/Logo.tsx @@ -7,108 +7,108 @@ export function LogoIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - + diff --git a/app/src/components/icons/RealTimeVisulationIcons.tsx b/app/src/components/icons/RealTimeVisulationIcons.tsx index 84d8cca..d418247 100644 --- a/app/src/components/icons/RealTimeVisulationIcons.tsx +++ b/app/src/components/icons/RealTimeVisulationIcons.tsx @@ -10,43 +10,43 @@ export function CleanPannel() { diff --git a/app/src/components/icons/SimulationIcons.tsx b/app/src/components/icons/SimulationIcons.tsx index 4879ea4..67a1a51 100644 --- a/app/src/components/icons/SimulationIcons.tsx +++ b/app/src/components/icons/SimulationIcons.tsx @@ -9,13 +9,13 @@ export function AnalysisIcon({ isActive }: { isActive: boolean }) { > @@ -34,11 +34,11 @@ export function MechanicsIcon({ isActive }: { isActive: boolean }) { > ); @@ -55,15 +55,15 @@ export function PropertiesIcon({ isActive }: { isActive: boolean }) { > ); @@ -82,13 +82,13 @@ export function SimulationIcon({ isActive }: { isActive: boolean }) { fillRule="evenodd" clipRule="evenodd" d="M6.44104 7.04762C6.57815 6.98413 6.73614 6.98413 6.87325 7.04762L12.0161 9.42958C12.198 9.51377 12.3143 9.69589 12.3143 9.89624V15.8512C12.3143 16.0347 12.2165 16.2043 12.0577 16.2962L6.9148 19.2736C6.75547 19.3659 6.55881 19.3659 6.39949 19.2736L1.25661 16.2962C1.09779 16.2043 1 16.0347 1 15.8512V9.89624C1 9.69589 1.11635 9.51377 1.29815 9.42958L6.44104 7.04762ZM2.02857 10.7297L6.14286 12.794V17.9366L2.02857 15.5546V10.7297ZM7.17143 17.9366L11.2857 15.5546V10.7297L7.17143 12.794V17.9366ZM6.65714 11.9013L10.6163 9.91477L6.65714 8.08106L2.69798 9.91477L6.65714 11.9013Z" - fill={isActive ? "var(--primary-color)" : "var(--text-color)"} + fill={isActive ? "var(--icon-default-color-active)" : "var(--icon-default-color)"} /> ); @@ -107,21 +107,21 @@ export function ResetIcon() { > @@ -140,7 +140,7 @@ export function PlayStopIcon() { > @@ -159,7 +159,7 @@ export function ExitIcon() { > diff --git a/app/src/components/icons/marketPlaceIcons.tsx b/app/src/components/icons/marketPlaceIcons.tsx index e69303f..6952ae1 100644 --- a/app/src/components/icons/marketPlaceIcons.tsx +++ b/app/src/components/icons/marketPlaceIcons.tsx @@ -29,13 +29,13 @@ export function DownloadIcon() { fillRule="evenodd" clipRule="evenodd" d="M2.5 11.875C2.84518 11.875 3.125 12.1548 3.125 12.5C3.125 13.6962 3.12633 14.5304 3.21096 15.1599C3.29317 15.7714 3.44354 16.0952 3.67418 16.3258C3.90481 16.5565 4.22863 16.7068 4.8401 16.7891C5.46956 16.8737 6.30383 16.875 7.5 16.875H12.5C13.6962 16.875 14.5304 16.8737 15.1599 16.7891C15.7714 16.7068 16.0952 16.5565 16.3258 16.3258C16.5565 16.0952 16.7068 15.7714 16.7891 15.1599C16.8737 14.5304 16.875 13.6962 16.875 12.5C16.875 12.1548 17.1548 11.875 17.5 11.875C17.8452 11.875 18.125 12.1548 18.125 12.5V12.5458C18.125 13.6854 18.125 14.604 18.0279 15.3265C17.9271 16.0766 17.7113 16.7081 17.2097 17.2097C16.7081 17.7113 16.0766 17.9271 15.3265 18.0279C14.604 18.125 13.6854 18.125 12.5458 18.125H7.45428C6.31462 18.125 5.39602 18.125 4.67354 18.0279C3.92345 17.9271 3.29189 17.7113 2.79029 17.2097C2.28869 16.7081 2.07295 16.0766 1.9721 15.3265C1.87497 14.604 1.87498 13.6854 1.875 12.5458C1.875 12.5305 1.875 12.5152 1.875 12.5C1.875 12.1548 2.15483 11.875 2.5 11.875Z" - fill="var(--primary-color)" + fill="var(--icon-default-color-active)" /> ); @@ -52,13 +52,13 @@ export function EyeIconBig() { > @@ -80,7 +80,7 @@ export function CommentsIcon() { fillRule="evenodd" clipRule="evenodd" d="M8 13C7.416 13 6.852 12.932 6.31 12.8165L3.956 14.2315L3.9875 11.912C2.183 10.827 1 9.033 1 7C1 3.6865 4.134 1 8 1C11.866 1 15 3.6865 15 7C15 10.314 11.866 13 8 13ZM8 0C3.582 0 0 3.1345 0 7C0 9.2095 1.1725 11.177 3 12.4595V16L6.5045 13.8735C6.9895 13.9535 7.4885 14 8 14C12.418 14 16 10.866 16 7C16 3.1345 12.418 0 8 0ZM11.5 5.5H4.5C4.224 5.5 4 5.724 4 6C4 6.2765 4.224 6.5 4.5 6.5H11.5C11.776 6.5 12 6.2765 12 6C12 5.724 11.776 5.5 11.5 5.5ZM10.5 8.5H5.5C5.224 8.5 5 8.7235 5 9C5 9.2765 5.224 9.5 5.5 9.5H10.5C10.776 9.5 11 9.2765 11 9C11 8.7235 10.776 8.5 10.5 8.5Z" - fill="var(--text-color)" + fill="var(--icon-default-color)" /> diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index f1818f3..1eadd24 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -563,7 +563,7 @@ const ZoneGroup: React.FC = () => { key={index} position={midpoint} rotation={[0, -angle, 0]} - // visible={false} + visible={false} > = ({ models }) => { }; return ( -
    -
    Products You May Like
    -
    - {models.length > 0 && - models.map((assetDetail) => ( - +
    +
    Products You May Like
    +
    + {models.length > 0 && + models.map((assetDetail) => ( + + ))} + {/* */} + {selectedCard && ( + - ))} - {/* */} - {selectedCard && ( - - )} - {/* */} + )} + {/* */} +
    ); diff --git a/app/src/modules/visualization/widgets/panel/AddButtons.tsx b/app/src/modules/visualization/widgets/panel/AddButtons.tsx index d066cd4..4877824 100644 --- a/app/src/modules/visualization/widgets/panel/AddButtons.tsx +++ b/app/src/modules/visualization/widgets/panel/AddButtons.tsx @@ -304,8 +304,8 @@ const AddButtons: React.FC = ({
    @@ -341,8 +341,8 @@ const AddButtons: React.FC = ({
    diff --git a/app/src/styles/abstracts/variables.scss b/app/src/styles/abstracts/variables.scss index 8400709..d1a6a5e 100644 --- a/app/src/styles/abstracts/variables.scss +++ b/app/src/styles/abstracts/variables.scss @@ -10,16 +10,19 @@ $text-color: #2b3344; $text-disabled: #b7b7c6; $input-text-color: #595965; $highlight-text-color: #6f42c1; +$text-button-color: #f3f3fd; // ---------- dark mode ---------- $text-color-dark: #f3f3fd; $text-disabled-dark: #6f6f7a; $input-text-color-dark: #b5b5c8; $highlight-text-color-dark: #B392F0; +$text-button-color-dark: #f3f3fd; // background colors // ---------- light mode ---------- $background-color: linear-gradient(-45deg, #FCFDFDCC 0%, #FCFDFD99 100%); +$background-color-solid: #fcfdfd; $background-color-secondary: #FCFDFD4D; $background-color-accent: #6f42c1; $background-color-button: #6f42c1; @@ -32,6 +35,7 @@ $background-radial-gray-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46 // ---------- dark mode ---------- $background-color-dark: linear-gradient(-45deg, #333333B3 0%, #2D2437B3 100%); +$background-color-solid-dark: #19191d; $background-color-secondary-dark: #19191D99; $background-color-accent-dark: #6f42c1; $background-color-button-dark: #6f42c1; @@ -85,15 +89,15 @@ $accent-color-dark: #c4abf1; $highlight-accent-color: #e0dfff; $highlight-accent-color-dark: #403e6a; -$background-color: #fcfdfd; -$background-color-dark: #19191d; -$background-color-secondary: #e1e0ff80; -$background-color-secondary-dark: #39394f99; +// $background-color: #fcfdfd; +// $background-color-dark: #19191d; +// $background-color-secondary: #e1e0ff80; +// $background-color-secondary-dark: #39394f99; $background-color-gray: #f3f3f3; $background-color-gray-dark: #232323; -$border-color: #e0dfff; -$border-color-dark: #403e6a; +// $border-color: #e0dfff; +// $border-color-dark: #403e6a; $shadow-color: #3c3c431a; $shadow-color-dark: #8f8f8f1a; @@ -141,3 +145,4 @@ $border-radius-medium: 6px; $border-radius-large: 12px; $border-radius-circle: 50%; $border-radius-extra-large: 20px; +$border-radius-xxx: 30px; diff --git a/app/src/styles/base/base.scss b/app/src/styles/base/base.scss index d812e9b..bd1403e 100644 --- a/app/src/styles/base/base.scss +++ b/app/src/styles/base/base.scss @@ -4,11 +4,13 @@ // text colors --text-color: #{$text-color}; --text-disabled: #{$text-disabled}; + --text-button-color: #{$text-button-color}; --input-text-color: #{$input-text-color}; --highlight-text-color: #{$highlight-text-color}; // background colors --background-color: #{$background-color}; + --background-color-solid: #{$background-color-solid}; --background-color-secondary: #{$background-color-secondary}; --background-color-accent: #{$background-color-accent}; --background-color-button: #{$background-color-button}; @@ -52,11 +54,13 @@ // text colors --text-color: #{$text-color-dark}; --text-disabled: #{$text-disabled-dark}; + --text-button-color: #{$text-button-color-dark}; --input-text-color: #{$input-text-color-dark}; --highlight-text-color: #{$highlight-text-color-dark}; // background colors --background-color: #{$background-color-dark}; + --background-color-solid: #{$background-color-solid-dark}; --background-color-secondary: #{$background-color-secondary-dark}; --background-color-accent: #{$background-color-accent-dark}; --background-color-button: #{$background-color-button-dark}; @@ -100,7 +104,7 @@ height: 100vh; width: 100vw; overflow: hidden; - background-color: var(--background-color-gray); + background: var(--background-color-gray); } #root-over { @@ -132,8 +136,8 @@ body { } ::-webkit-scrollbar { - width: 8px; - height: 8px; + width: 4px; + height: 4px; } ::-webkit-scrollbar-track { @@ -142,13 +146,12 @@ body { } ::-webkit-scrollbar-thumb { - background: var(--accent-color); + background: var(--background-color-button); border-radius: 4px; - border: 2px solid var(--primary-color); } ::-webkit-scrollbar-thumb:hover { - background: var(--accent-color); + background: var(--background-color-button); } ::-webkit-scrollbar-corner { diff --git a/app/src/styles/base/global.scss b/app/src/styles/base/global.scss index 3ba017e..d1bf505 100644 --- a/app/src/styles/base/global.scss +++ b/app/src/styles/base/global.scss @@ -1,5 +1,9 @@ +@use "../abstracts/variables" as *; +@use "../abstracts/mixins" as *; + section, .section{ padding: 12px; outline: 1px solid var(--border-color); - border-radius: 16px; + border-radius: #{$border-radius-large}; + background: var(--background-color); } diff --git a/app/src/styles/components/analysis/analysis.scss b/app/src/styles/components/analysis/analysis.scss index bc33556..9c4b0e6 100644 --- a/app/src/styles/components/analysis/analysis.scss +++ b/app/src/styles/components/analysis/analysis.scss @@ -63,14 +63,14 @@ height: 4px; border-radius: 13px; overflow: hidden; - background-color: #FBEBD7; + background: #FBEBD7; .bar-fill { position: absolute; height: 100%; top: 0; left: 0; - background-color: #FC9D2F; + background: #FC9D2F; border-radius: 13px; } @@ -144,7 +144,7 @@ } canvas { - background-color: transparent; + background: transparent; } } } @@ -200,15 +200,15 @@ height: 5px; &:nth-child(1) { - background-color: #F3C64D; + background: #F3C64D; } &:nth-child(2) { - background-color: #67B3F4; + background: #67B3F4; } &:nth-child(3) { - background-color: #7981F5; + background: #7981F5; } } } @@ -228,21 +228,21 @@ &:nth-child(1) { .indicator { - background-color: #F3C64D; + background: #F3C64D; } } &:nth-child(2) { .indicator { - background-color: #67B3F4; + background: #67B3F4; } } &:nth-child(3) { .indicator { - background-color: #7981F5; + background: #7981F5; } } diff --git a/app/src/styles/components/confirmationPopUp.scss b/app/src/styles/components/confirmationPopUp.scss index 4bef0ae..e955a79 100644 --- a/app/src/styles/components/confirmationPopUp.scss +++ b/app/src/styles/components/confirmationPopUp.scss @@ -11,7 +11,7 @@ left: 50%; transform: translate(-50%, -50%); z-index: 5; - background-color: var(--background-color); + background: var(--background-color); padding: 14px 12px; border-radius: 6px; @@ -32,7 +32,7 @@ } &:last-child { - background-color: #ffe3e0; + background: #ffe3e0; color: #f65648; } diff --git a/app/src/styles/components/input.scss b/app/src/styles/components/input.scss index 21554e8..48d6ee8 100644 --- a/app/src/styles/components/input.scss +++ b/app/src/styles/components/input.scss @@ -15,7 +15,8 @@ input { &:focus, &:active { - outline: 1px solid var(--accent-color); + outline: 1px solid var(--border-color-accent); + background: var(--background-color-input-focus); } &:-webkit-autofill, @@ -27,26 +28,19 @@ input { caret-color: var(--input-text-color); // Background styles - background-color: var(--background-color) !important; - -webkit-box-shadow: 0 0 0px 1000px var(--background-color) inset !important; + background: var(--background-color-solid) !important; + -webkit-box-shadow: 0 0 0px 1000px var(--background-color-solid) inset !important; } // File input specific style adjustments &::file-selector-button { font-size: 14px; - color: var(--accent-color); - background-color: var(--background-color-secondary); + background: var(--background-color-secondary); border: none; outline: none; border-radius: #{$border-radius-small}; padding: 2px; cursor: pointer; - - // Hover effect for the file button - &:hover { - color: var(--primary-color); - background-color: var(--accent-color); - } } } @@ -93,8 +87,8 @@ input { } .active { - background-color: var(--accent-color); - color: var(--primary-color); + background: var(--background-color-button); + color: var(--text-button-color); } } @@ -102,14 +96,13 @@ input { position: sticky; top: 0; padding: 8px 10px; - background: var(--background-color); + width: 100%; z-index: 1; .search-container { @include flex-center; width: 100%; border-radius: #{$border-radius-small}; - background-color: var(--background-color); padding: 6px 2px; position: relative; border: 1px solid var(--border-color); @@ -129,7 +122,7 @@ input { font-weight: var(--font-weight-regular); border: none; outline: none; - background-color: transparent; + background: transparent; padding-left: 36px; } @@ -141,16 +134,17 @@ input { height: 24px; border: none; cursor: pointer; - background-color: transparent; + background: transparent; &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); } } } .active { border: 1px solid var(--accent-color); + background: var(--background-color-input-focus); } } @@ -166,7 +160,7 @@ input { position: absolute; left: 10px; top: 12px; - background-color: var(--background-color); + background: var(--background-color); border-radius: #{$border-radius-small}; box-shadow: var(--box-shadow-medium); z-index: 1; @@ -182,7 +176,7 @@ input { gap: 2px; &:hover { - background-color: var(--background-color-secondary); + background: var(--background-color-secondary); } .icon-container { @@ -197,11 +191,11 @@ input { } .selected { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); color: var(--accent-color); &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); } } @@ -226,13 +220,13 @@ input { justify-content: space-between; cursor: pointer; border-radius: 6px; - background-color: var(--background-color); + background: var(--background-color); } .dropdown-options { position: absolute; width: 100%; - background-color: var(--primary-color); + background: var(--background-color); border: 1px solid var(--border-color); border-radius: #{$border-radius-small}; z-index: 10; @@ -241,6 +235,7 @@ input { left: 0; top: 110%; padding: 4px; + backdrop-filter: blur(8px); .dropdown-search { margin-bottom: 4px; @@ -253,8 +248,8 @@ input { border-radius: #{$border-radius-small}; &:hover { - color: var(--accent-color); - background-color: var(--highlight-accent-color); + color: var(--highlight-text-color); + background: var(--highlight-accent-color); } } } @@ -318,7 +313,7 @@ input { .dropdown-button { width: 100%; - background-color: var(--background-color) !important; + background: var(--background-color) !important; border: 1px solid var(--border-color) !important; padding: 5px 10px; @@ -335,11 +330,11 @@ input { transition: background-color 0.3s ease; &:hover { - background-color: #333333; + background: #333333; } &.open { - background-color: #333333; + background: #333333; } } @@ -347,7 +342,7 @@ input { position: absolute; top: 110%; right: -16px; - background-color: var(--background-color); + background: var(--background-color); border: 1px solid var(--border-color); border-radius: 5px; box-shadow: #{$box-shadow-medium}; @@ -412,7 +407,7 @@ input { transition: background-color 0.3s ease; &:hover { - background-color: var(--background-color); + background: var(--background-color); } } @@ -435,12 +430,12 @@ input { } &:hover { - background-color: var(--background-color); + background: var(--background-color); } &.open { color: var(--accent-color); - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); } .icon { @@ -472,8 +467,8 @@ input { } .check-box { - height: 22px; - width: 44px; + height: 24px; + width: 38px; background: var(--background-color-secondary); border-radius: #{$border-radius-large}; position: relative; @@ -481,8 +476,8 @@ input { .check-box-style { position: absolute; - height: 18px; - width: 18px; + height: 20px; + width: 20px; top: 2px; left: 2px; background: var(--accent-color); @@ -523,7 +518,7 @@ input { -webkit-appearance: none; width: 16px; height: 16px; - background: var(--primary-color); + background: var(--background-color-accent); border-radius: #{$border-radius-circle}; box-shadow: 0 0 2px rgba(0, 0, 0, 0.2); cursor: pointer; @@ -597,19 +592,19 @@ input { cursor: not-allowed; &::-webkit-slider-thumb { - background: var(--primary-color); + background: var(--background-color-accent); box-shadow: none; outline: 4px solid var(--text-disabled); outline: -4px; } &::-moz-range-thumb { - background: var(--primary-color); + background: var(--background-color-accent); box-shadow: none; } &::-ms-thumb { - background: var(--primary-color); + background: var(--background-color-accent); box-shadow: none; } @@ -644,14 +639,10 @@ input { padding: 2px 32px; border: none; border-radius: #{$border-radius-large}; - color: var(--text-disabled); - background: var(--accent-color); + color: var(--text-color); + background: var(--background-color-button); transition: all 0.2s; cursor: pointer; - - &:hover { - color: var(--primary-color); - } } } @@ -710,11 +701,6 @@ input { line-height: 12px; text-align: center; border-radius: #{$border-radius-small}; - - &:hover { - background: var(--accent-color); - color: var(--primary-color); - } } } } @@ -722,8 +708,8 @@ input { .invite-button { padding: 4px 12px; border-radius: #{$border-radius-large}; - background: var(--accent-color); - color: var(--primary-color); + background: var(--background-color-accent); + color: var(--text-button-color); } .multi-email-invite-input.active { @@ -770,7 +756,7 @@ input { width: 100%; height: 100%; border-radius: #{$border-radius-small}; - background-color: var(--background-color-gray); + background: var(--background-color-gray); } } } diff --git a/app/src/styles/components/lists.scss b/app/src/styles/components/lists.scss index cf66d2b..3b52e69 100644 --- a/app/src/styles/components/lists.scss +++ b/app/src/styles/components/lists.scss @@ -30,8 +30,6 @@ } .list-wrapper { - - .no-item { padding: 12px; } @@ -41,7 +39,6 @@ // margin-left: 10px; overflow: hidden; - .list-item { @include flex-space-between; width: 100%; @@ -67,7 +64,7 @@ } .active { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); color: var(--primary-color); } } @@ -75,7 +72,6 @@ .asset-list { border-left: 2px solid var(--border-color); - margin-left: 20px + margin-left: 20px; } - -} \ 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 c93b344..b84a252 100644 --- a/app/src/styles/components/marketPlace/marketPlace.scss +++ b/app/src/styles/components/marketPlace/marketPlace.scss @@ -5,28 +5,28 @@ height: 100vh; width: 100vw; z-index: #{$z-index-marketplace}; - background-color: var(--background-color-secondary); + background: var(--background-color-secondary); position: absolute; left: 0; top: 0; padding: 100px 50px; padding-bottom: 32px; - backdrop-filter: blur(6px); - + .marketplace-container { position: relative; padding: 20px 2px; height: 100%; - background-color: var(--background-color); + background: var(--background-color); box-shadow: #{$box-shadow-medium}; - border-radius: #{$border-radius-extra-large}; + border-radius: #{$border-radius-xxx}; + outline: 1px solid var(--border-color); + backdrop-filter: blur(16px); } .marketPlace { width: 100%; height: 100%; overflow: auto; - padding-bottom: 60px; display: flex; flex-direction: column; gap: 24px; @@ -83,12 +83,18 @@ } } } - + .cards-container-wrapper{ + position: relative; + height: calc(100% - 60px); + padding: 0px 10px; + } .cards-container-container { - padding: 0px 20px; display: flex; + padding: 0 10px; flex-direction: column; gap: 6px; + height: 100%; + overflow: auto; .header { color: var(--text-color); @@ -107,7 +113,8 @@ border-radius: 18px; padding: 12px; box-shadow: 0px 2px 10.5px 0px #0000000d; - border: 1px solid var(--background-accent-transparent, #e0dfff80); + background: var(--background-color); + border: 1px solid var(--border-color); position: relative; display: flex; flex-direction: column; @@ -124,7 +131,7 @@ height: 30px; border-radius: 10px; padding: 5px; - background-color: var(--accent-color); + background: var(--accent-color); } .image-container { @@ -193,11 +200,11 @@ .buy-now-button { width: 100%; - background-color: var(--background-color-secondary); + background: var(--background-color-button); border-radius: $border-radius-extra-large; padding: 8px 0; @include flex-center; - color: var(--accent-color); + color: var(--text-button-color); &:hover { cursor: pointer; @@ -220,7 +227,7 @@ .assetPreview { width: 100%; height: 100%; - background-color: var(--background-color); + background: var(--background-color); display: flex; gap: 12px; overflow: hidden; @@ -262,7 +269,7 @@ border-radius: 50%; font-weight: var(--font-weight-bold); color: var(--background-color); - background-color: var(--accent-color); + background: var(--accent-color); } .organization-details { @@ -327,7 +334,7 @@ display: block; width: 2px; height: 12px; - background-color: #ccc; + background: #ccc; } } @@ -363,7 +370,7 @@ } &:last-child { - background-color: var(--accent-color); + background: var(--accent-color); color: var(--background-color); } } diff --git a/app/src/styles/components/menu/menu.scss b/app/src/styles/components/menu/menu.scss index 55b16f9..34c56d1 100644 --- a/app/src/styles/components/menu/menu.scss +++ b/app/src/styles/components/menu/menu.scss @@ -36,7 +36,7 @@ top: 32px; left: 0; z-index: 5; - background-color: var(--background-color); + background: var(--background-color); color: var(--text-color); box-shadow: var(--box-shadow-light); border-radius: 8px; @@ -73,7 +73,7 @@ position: absolute; top: 0; left: 100%; - background-color: var(--background-color); + background: var(--background-color); min-width: 220px; border-radius: 4px; box-shadow: var(--box-shadow-light); @@ -95,7 +95,7 @@ rotate: -90deg; } &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); span, .menu-item-right span { color: var(--accent-color); @@ -123,7 +123,7 @@ position: absolute; left: 100%; top: 0; - background-color: var(--background-color); + background: var(--background-color); min-width: 200px; border-radius: 0 4px 4px 4px; box-shadow: var(--box-shadow-light); @@ -140,7 +140,7 @@ white-space: nowrap; color: var(--text-color); &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); span { color: var(--accent-color); } @@ -154,7 +154,7 @@ } &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); .menu-button { color: var(--accent-color); } @@ -164,7 +164,7 @@ .split { width: 100%; height: 1px; - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); margin: 2px 0; } } diff --git a/app/src/styles/components/moduleToggle.scss b/app/src/styles/components/moduleToggle.scss index a6a77c8..c864cbf 100644 --- a/app/src/styles/components/moduleToggle.scss +++ b/app/src/styles/components/moduleToggle.scss @@ -18,7 +18,8 @@ padding: 4px 12px; border-radius: #{$border-radius-extra-large}; box-shadow: var(--box-shadow-medium); - background-color: var(--background-color); + background: var(--background-color); + backdrop-filter: blur(8px); cursor: pointer; overflow: hidden; position: relative; @@ -37,7 +38,7 @@ left: 0; width: 0%; height: 100%; - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); transition: width 0.2s; border-radius: #{$border-radius-extra-large}; } @@ -49,15 +50,15 @@ } .active { cursor: default; - background-color: var(--accent-color); + background: var(--background-color-button); &::after{ display: none; } &:hover { - background-color: var(--accent-color); + background: var(--background-color-button); } .module { - color: var(--highlight-accent-color); + color: var(--icon-default-color-active); } } } diff --git a/app/src/styles/components/simulation/simulation.scss b/app/src/styles/components/simulation/simulation.scss index eb109c2..9f89d0a 100644 --- a/app/src/styles/components/simulation/simulation.scss +++ b/app/src/styles/components/simulation/simulation.scss @@ -17,11 +17,11 @@ gap: 2px; padding: 6px 8px; min-width: 64px; - background-color: var(--background-color); + background: var(--background-color); border-radius: #{$border-radius-small}; cursor: pointer; &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); color: var(--accent-color); path { stroke: var(--accent-color); @@ -75,7 +75,7 @@ } .marker{ position: absolute; - background-color: var(--text-disabled); + background: var(--text-disabled); width: 2px; height: 12px; border-radius: 1px; diff --git a/app/src/styles/components/templates.scss b/app/src/styles/components/templates.scss index bd28d94..a2a3da5 100644 --- a/app/src/styles/components/templates.scss +++ b/app/src/styles/components/templates.scss @@ -8,7 +8,7 @@ outline-offset: -3px; border-radius: 16px; .follower-name{ - background-color: var(--user-color); + background: var(--user-color); color: #FFFFFF; padding: 4px 8px; padding-top: 16px; diff --git a/app/src/styles/components/tools.scss b/app/src/styles/components/tools.scss index 5a10518..c80caf5 100644 --- a/app/src/styles/components/tools.scss +++ b/app/src/styles/components/tools.scss @@ -13,14 +13,15 @@ border-radius: #{$border-radius-large}; width: fit-content; transition: width 0.2s; - background-color: var(--background-color); + background: var(--background-color); + backdrop-filter: blur(8px); z-index: #{$z-index-default}; .split { height: 20px; width: 2px; border-radius: 2px; - background: var(--highlight-accent-color); + background: var(--text-disabled); } .draw-tools, @@ -48,10 +49,10 @@ } .active { - background-color: var(--accent-color); + background: var(--accent-color); &:hover { - background-color: var(--accent-color); + background: var(--accent-color); } } } @@ -91,7 +92,7 @@ padding: 4px; &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); color: var(--accent-color); path { @@ -117,7 +118,7 @@ @include flex-center; padding: 3px; border-radius: #{$border-radius-small}; - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); gap: 2px; position: relative; @@ -131,7 +132,7 @@ &::after { content: ""; position: absolute; - background-color: var(--accent-color); + background: var(--accent-color); left: 3px; top: 3px; height: 18px; @@ -161,7 +162,7 @@ width: 30px; height: 30px; border-radius: 50%; - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); cursor: pointer; @include flex-center; position: fixed; @@ -174,7 +175,7 @@ font-weight: 700; &:hover { font-weight: 500; - background-color: var(--accent-color); + background: var(--accent-color); color: var(--highlight-accent-color); &::after{ animation: pulse 1s ease-out infinite; diff --git a/app/src/styles/components/visualization/floating/common.scss b/app/src/styles/components/visualization/floating/common.scss index d138959..0084e7a 100644 --- a/app/src/styles/components/visualization/floating/common.scss +++ b/app/src/styles/components/visualization/floating/common.scss @@ -3,7 +3,7 @@ .throughput-wrapper, .card { - background-color: var(--background-color); + background: var(--background-color); box-shadow: var(--box-shadow-heavy); @include flex-center; flex-direction: column; @@ -105,7 +105,7 @@ } .productionCapacity-wrapper { - background-color: var(--background-color); + background: var(--background-color); display: flex; flex-direction: column; gap: 6px; @@ -116,7 +116,7 @@ .headeproductionCapacityr-wrapper, .bar-chart { padding: 14px; - background-color: var(--background-color); + background: var(--background-color); display: flex; flex-direction: column; gap: 6px; @@ -276,7 +276,7 @@ .icon { width: 45px; height: 45px; - background-color: var(--accent-color); + background: var(--accent-color); display: flex; justify-content: center; align-items: center; @@ -289,7 +289,7 @@ display: flex; flex-direction: column; gap: 6px; - background-color: var(--background-color); + background: var(--background-color); padding: 14px; .header { @@ -307,7 +307,7 @@ .productivity-dashboard { width: 100%; - background-color: var(--background-color); + background: var(--background-color); color: white; padding: 20px; border-radius: 8px; @@ -324,7 +324,7 @@ } .options { - background-color: #343b47; + background: #343b47; width: 30px; height: 30px; display: flex; @@ -334,7 +334,7 @@ cursor: pointer; &:hover { - background-color: #49505a; + background: #49505a; } } } @@ -350,7 +350,7 @@ gap: 10px; .metric { - background-color: #2c3e50; + background: #2c3e50; padding: 15px; border-radius: 4px; @@ -445,7 +445,7 @@ } .scaleLabels { - background-color: var(--background-color); + background: var(--background-color); box-shadow: var(--box-shadow-heavy); display: flex; justify-content: space-between; diff --git a/app/src/styles/components/visualization/ui/styledWidgets.scss b/app/src/styles/components/visualization/ui/styledWidgets.scss index 794b756..8262bb3 100644 --- a/app/src/styles/components/visualization/ui/styledWidgets.scss +++ b/app/src/styles/components/visualization/ui/styledWidgets.scss @@ -43,7 +43,7 @@ .icon { width: 16.95305824279785px; height: 16.95305824279785px; - background-color: var(--accent-color); + background: var(--accent-color); border-radius: 50%; display: flex; justify-content: center; diff --git a/app/src/styles/layout/loading.scss b/app/src/styles/layout/loading.scss index 0a13753..59354ff 100644 --- a/app/src/styles/layout/loading.scss +++ b/app/src/styles/layout/loading.scss @@ -4,7 +4,7 @@ .loading-wrapper { height: 100vh; width: 100vw; - background: var(--background-color); + background: var(--background-color-solid); .loading-container { position: relative; height: 100%; diff --git a/app/src/styles/layout/popup.scss b/app/src/styles/layout/popup.scss index b92d8cc..3b31442 100644 --- a/app/src/styles/layout/popup.scss +++ b/app/src/styles/layout/popup.scss @@ -5,13 +5,13 @@ height: 100vh; width: 100vw; background: var(--background-color-secondary); - backdrop-filter: blur(2px); @include flex-center; .collaboration-popup-container { max-width: 50vw; - width: 460px; - background-color: var(--background-color); + width: 520px; + background: var(--background-color); border-radius: #{$border-radius-large}; + backdrop-filter: blur(8px); .split { width: 100%; height: 1px; @@ -88,14 +88,14 @@ .your-name { @include flex-center; gap: 6px; - color: var(--accent-color); + color: var(--text-color); .user-profile{ height: 24px; width: 24px; text-align: center; line-height: 25px; - background-color: var(--accent-color); - color: var(--primary-color); + background: var(--background-color-accent); + color: var(--text-color); border-radius: #{$border-radius-circle}; } } diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index a102feb..403b27a 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -6,9 +6,10 @@ position: fixed; top: 32px; left: 8px; - background-color: var(--background-color); + background: var(--background-color); backdrop-filter: blur(150px); - border-radius: #{$border-radius-extra-large}; + border-radius: #{$border-radius-xxx}; + outline: 1px solid var(--border-color); box-shadow: #{$box-shadow-medium}; z-index: #{$z-index-tools}; @@ -46,12 +47,12 @@ border-radius: #{$border-radius-small}; &:hover { - background-color: var(--background-color-secondary); + background: var(--background-color-secondary); } } .active { - background-color: var(--background-color-secondary); + background: var(--background-color-secondary); outline: 1px solid var(--accent-color); outline-offset: -1px; } @@ -174,7 +175,7 @@ .stock { padding: 13px 5px; - background-color: var(--background-color-secondary); + background: var(--background-color-secondary); border-radius: 6.33px; display: flex; justify-content: space-between; @@ -243,15 +244,17 @@ position: fixed; top: 32px; right: 8px; - background-color: var(--background-color); + background: var(--background-color); backdrop-filter: blur(150px); - border-radius: #{$border-radius-extra-large}; + border-radius: #{$border-radius-xxx}; + outline: 1px solid var(--border-color); box-shadow: #{$box-shadow-medium}; z-index: #{$z-index-tools}; .header-container { @include flex-space-between; padding: 10px; + padding-left: 16px; width: 100%; gap: 12px; height: 52px; @@ -262,8 +265,8 @@ .share-button { padding: 4px 12px; - color: var(--primary-color); - background-color: var(--accent-color); + color: var(--text-color); + background: var(--background-color-button); font-weight: var(--font-weight-regular); border-radius: #{$border-radius-large}; cursor: pointer; @@ -277,7 +280,7 @@ .split { height: 20px; width: 2px; - background: var(--background-color-secondary); + background: var(--text-disabled); } .users-container { @@ -353,26 +356,28 @@ height: 34px; width: 34px; border-radius: #{$border-radius-circle}; - background: var(--primary-color); + background: var(--background-color-secondary); + backdrop-filter: blur(8px); box-shadow: #{$box-shadow-medium}; } .active { - background: var(--accent-color); + background: var(--background-color-accent); } } .sidebar-right-container { min-height: 50vh; - padding-bottom: 12px; + padding: 8px; position: relative; overflow: auto; .sidebar-right-content-container { - border-bottom: 1px solid var(--border-color); height: calc(100% - 36px); position: relative; - width: 320px; + width: 304px; + padding-bottom: 10px; + .no-event-selected { color: #666; padding: 1.8rem 1rem; @@ -532,7 +537,7 @@ } button { - background-color: transparent; + background: transparent; box-shadow: none; color: #5273eb; padding: 6px; @@ -732,7 +737,7 @@ stroke: var(--primary-color); } &:disabled { - background-color: var(--text-disabled); + background: var(--text-disabled); } } } @@ -841,7 +846,7 @@ transform: translateX(4px); &:hover { - background-color: var(--accent-color); + background: var(--accent-color); path { stroke: var(--primary-color); @@ -983,11 +988,9 @@ .zone-properties-container { .header { @include flex-space-between; - padding: 8px 12px; - border-top: 1px solid var(--highlight-accent-color); - border-bottom: 1px solid var(--highlight-accent-color); - color: var(--accent-color); - + padding: 10px 12px; + color: var(--text-color); + margin-bottom: 4px; .input-value { color: inherit; } @@ -1004,7 +1007,7 @@ border-radius: 8px 0 0 8px; &:hover { - background-color: var(--accent-color); + background: var(--accent-color); path { stroke: var(--primary-color); @@ -1017,8 +1020,8 @@ .generate-report-button, .button-save { @include flex-center; - background-color: var(--accent-color); - color: var(--primary-color); + background: var(--background-color-button); + color: var(--text-button-color); border-radius: #{$border-radius-large}; padding: 2px; gap: 4px; @@ -1028,12 +1031,6 @@ margin-bottom: 8px; } - .split { - height: 1px; - background: var(--highlight-accent-color); - margin: 8px; - } - .custom-input-container { .header { @include flex-space-between; @@ -1162,14 +1159,14 @@ flex-direction: row; flex-wrap: wrap; height: 100%; - gap: 3px; + gap: 8px; padding: 10px 0; .category { - width: 117px; + width: 121px; height: 95px; border-radius: 3.59px; - background-color: var(--background-color-gray); + background: var(--background-color-gray); padding: 8px; padding-top: 12px; font-weight: $bold-weight; @@ -1189,7 +1186,7 @@ width: 60px; height: 60px; border-radius: 50%; - background-color: var(--circle-color, #000); + background: var(--circle-color, #000); position: absolute; top: 60%; right: -10px; @@ -1270,7 +1267,7 @@ width: 117px; height: 95px; border-radius: #{$border-radius-small}; - background-color: var(--background-color-gray); + background: var(--background-color-gray); font-weight: $medium-weight; position: relative; overflow: hidden; @@ -1337,7 +1334,7 @@ width: 117px; height: 95px; border-radius: 3.59px; - background-color: var(--background-color-gray); + background: var(--background-color-gray); padding: 8px; padding-top: 12px; font-weight: $medium-weight; diff --git a/app/src/styles/layout/toast.scss b/app/src/styles/layout/toast.scss index 951a213..eb51c5a 100644 --- a/app/src/styles/layout/toast.scss +++ b/app/src/styles/layout/toast.scss @@ -51,19 +51,19 @@ } .toast.success { - background-color: #4caf50; + background: #4caf50; } .toast.error { - background-color: #f44336; + background: #f44336; } .toast.info { - background-color: #2196f3; + background: #2196f3; } .toast.warning { - background-color: #ff9800; + background: #ff9800; } @keyframes fadeIn { diff --git a/app/src/styles/pages/dashboard.scss b/app/src/styles/pages/dashboard.scss index 3fc9a05..a41dc50 100644 --- a/app/src/styles/pages/dashboard.scss +++ b/app/src/styles/pages/dashboard.scss @@ -43,7 +43,7 @@ padding: 12px 16px; cursor: not-allowed; color: var(--accent-color); - background-color: var(--background-color-secondary); + background: var(--background-color-secondary); border-radius: #{$border-radius-large}; } .side-bar-content-container { @@ -66,9 +66,9 @@ .active { color: var(--accent-color); font-weight: var(--font-weight-medium); - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); } } } @@ -161,7 +161,7 @@ width: 26px; line-height: 26px; text-align: center; - background-color: var(--accent-color); + background: var(--accent-color); color: var(--primary-color); border-radius: #{$border-radius-circle}; } diff --git a/app/src/styles/pages/home.scss b/app/src/styles/pages/home.scss index 4139cc1..a2db6f7 100644 --- a/app/src/styles/pages/home.scss +++ b/app/src/styles/pages/home.scss @@ -1,38 +1,3 @@ -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: var(--primary-color); - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: 282c34; -} - -.App-link { - color: var(--button-action-color); -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - .navbar{ position: absolute; top: 0; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index 1efa2d4..617e39f 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -3,7 +3,7 @@ // Main Container .realTime-viz { - background-color: #131313; + background: #131313; border-radius: 20px; box-shadow: $box-shadow-medium; width: calc(100% - (320px + 270px + 90px)); @@ -66,7 +66,7 @@ .zone-wrapper { display: flex; - background-color: var(--background-color); + background: var(--background-color); position: absolute; bottom: 0px; left: 50%; @@ -84,7 +84,7 @@ } .arrow { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); color: var(--background-color); } @@ -109,7 +109,7 @@ .zone { width: auto; - background-color: var(--background-color); + background: var(--background-color); border-radius: 6px; padding: 4px 8px; white-space: nowrap; @@ -117,7 +117,7 @@ } .active { - background-color: var(--accent-color); + background: var(--accent-color); color: var(--background-color); // color: #FCFDFD !important; } @@ -138,13 +138,13 @@ position: relative; flex: 1; height: 600px; - background-color: rgb(235, 235, 235); + background: rgb(235, 235, 235); margin: 0 30px; transition: height 0.3s ease, margin 0.3s ease; .zone-wrapper { display: flex; - background-color: rgba(224, 223, 255, 0.5); + background: rgba(224, 223, 255, 0.5); position: absolute; // bottom: 10px; left: 50%; @@ -162,7 +162,7 @@ .zone { width: auto; - background-color: $background-color; + background: $background-color; border-radius: 6px; padding: 4px 8px; white-space: nowrap; @@ -170,7 +170,7 @@ transition: background-color 0.3s ease; &.active { - background-color: var(--primary-color); + background: var(--primary-color); color: var(--accent-color); } } @@ -203,7 +203,7 @@ display: flex; flex-direction: column; gap: 6px; - background-color: var(--background-color); + background: var(--background-color); &::-webkit-scrollbar { display: none; @@ -217,7 +217,7 @@ border-radius: 8px; box-shadow: var(--box-shadow-medium); padding: 6px 0; - background-color: var(--background-color); + background: var(--background-color); position: relative; padding: 0 10px; @@ -237,7 +237,7 @@ top: 18px; right: 5px; transform: translate(0px, 0); - background-color: var(--background-color); + background: var(--background-color); z-index: 10; display: flex; @@ -261,7 +261,7 @@ } &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); width: 100%; svg { @@ -353,7 +353,7 @@ border-radius: 8px; box-shadow: var(--box-shadow-medium); padding: 6px 0; - background-color: var(--background-color); + background: var(--background-color); position: relative; } } @@ -377,7 +377,7 @@ .side-button-container { position: absolute; display: flex; - background-color: var(--background-color); + background: var(--background-color); padding: 2px; border-radius: 2px; transition: transform 0.3s ease; @@ -398,7 +398,7 @@ } .active { - background-color: var(--accent-color); + background: var(--accent-color); } &:hover { @@ -414,7 +414,7 @@ display: flex; justify-content: center; // align-items: center; - background-color: var(--accent-color); + background: var(--accent-color); border: none; color: var(--background-color); border-radius: 4px; @@ -494,7 +494,7 @@ padding: 12px; box-shadow: 1px -3px 4px 0px rgba(0, 0, 0, 0.11); border-radius: 8px; - background-color: white; + background: white; position: absolute; top: 20px; right: -100%; @@ -530,7 +530,7 @@ left: 1px; width: 10px; height: 10px; - background-color: var(--primary-color); + background: var(--primary-color); border-radius: 50%; } } @@ -584,7 +584,7 @@ } .zone.active { - background-color: #007bff; + background: #007bff; color: white; } @@ -592,7 +592,7 @@ .icon { // width: 25px !important; // height: 25px !important; - // background-color: transparent; + // background: transparent; } .kebab { @@ -604,7 +604,7 @@ z-index: 10; cursor: pointer; @include flex-center; - background-color: transparent !important; + background: transparent !important; } .kebab-options { @@ -612,7 +612,7 @@ top: 18px; right: 5px; transform: translate(0px, 0); - background-color: var(--background-color); + background: var(--background-color); z-index: 10; display: flex; @@ -625,7 +625,7 @@ .icon { width: 25px !important; height: 25px !important; - background-color: transparent; + background: transparent; } .btn { @@ -643,7 +643,7 @@ } &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); width: 100%; svg { @@ -675,7 +675,7 @@ /* Label styles for displaying distance values */ .distance-label { position: absolute; - background-color: var(--accent-color); + background: var(--accent-color); color: white; font-size: 12px; padding: 2px 6px; @@ -769,7 +769,7 @@ .editWidgetOptions { position: absolute; - background-color: var(--background-color); + background: var(--background-color); z-index: 3; display: flex; flex-direction: column; @@ -786,7 +786,7 @@ cursor: pointer; &:hover { - background-color: var(--highlight-accent-color); + background: var(--highlight-accent-color); color: var(--accent-color); } @@ -794,7 +794,7 @@ color: #f65648; &:hover { - background-color: #f657484d; + background: #f657484d; color: #f65648; } } diff --git a/app/src/styles/pages/userAuth.scss b/app/src/styles/pages/userAuth.scss index 6e86ac1..9d07dcf 100644 --- a/app/src/styles/pages/userAuth.scss +++ b/app/src/styles/pages/userAuth.scss @@ -9,7 +9,7 @@ padding: 20px; color: var(--text-color); height: 100vh; - background-color: var(--background-color); + background: var(--background-color); position: relative; z-index: 1; .logo-icon { diff --git a/app/src/styles/scene/scene.scss b/app/src/styles/scene/scene.scss index fc3b824..ab8f787 100644 --- a/app/src/styles/scene/scene.scss +++ b/app/src/styles/scene/scene.scss @@ -14,9 +14,8 @@ // style font-size: var(--font-size-large); padding: 2px 8px; - background: var(--primary-color); - color: var(--accent-color); - outline: 1px solid var(--accent-color); + background: var(--background-color-accent); + color: var(--text-color); border-radius: #{$border-radius-medium}; box-shadow: var(--box-shadow-light); } From 0b0e1e3d8b03ba6d186939456df5aaa0d3b4a9c1 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 29 Apr 2025 18:19:03 +0530 Subject: [PATCH 23/30] Refactor event properties components to use section elements for better semantics and styling consistency; update mechanics components to enhance layout and improve user experience; modify simulation component to manage open/close state for event lists; enhance file menu with project icon; improve input toggle styles; standardize color variables in SCSS; adjust sidebar styles for better visual hierarchy; implement backdrop filters for improved UI aesthetics; and refine overall component styling for consistency across the application. --- .../components/icons/ExportCommonIcons.tsx | 4 +- app/src/components/icons/ExportToolsIcons.tsx | 126 ++++---- app/src/components/icons/SimulationIcons.tsx | 30 +- .../components/layout/sidebarLeft/Outline.tsx | 36 ++- .../layout/sidebarRight/analysis/Analysis.tsx | 2 +- .../customInput/PositionInputs.tsx | 3 +- .../properties/AssetProperties.tsx | 80 ++--- .../properties/GlobalProperties.tsx | 116 +++---- .../properties/ZoneProperties.tsx | 84 ++--- .../eventProperties/EventProperties.tsx | 4 +- .../mechanics/conveyorMechanics.tsx | 123 +++---- .../mechanics/machineMechanics.tsx | 4 +- .../mechanics/roboticArmMechanics.tsx | 67 ++-- .../mechanics/storageMechanics.tsx | 4 +- .../mechanics/vehicleMechanics.tsx | 302 +++++++++--------- .../sidebarRight/simulation/Simulations.tsx | 20 +- app/src/components/ui/FileMenu.tsx | 4 + app/src/components/ui/inputs/InputToggle.tsx | 9 +- app/src/styles/abstracts/variables.scss | 90 ++++-- app/src/styles/base/base.scss | 6 +- app/src/styles/base/global.scss | 4 +- app/src/styles/components/input.scss | 40 ++- app/src/styles/components/menu/menu.scss | 23 +- app/src/styles/components/tools.scss | 4 +- app/src/styles/layout/sidebar.scss | 64 ++-- app/src/styles/pages/realTimeViz.scss | 1 + 26 files changed, 680 insertions(+), 570 deletions(-) diff --git a/app/src/components/icons/ExportCommonIcons.tsx b/app/src/components/icons/ExportCommonIcons.tsx index f6f0287..0377e23 100644 --- a/app/src/components/icons/ExportCommonIcons.tsx +++ b/app/src/components/icons/ExportCommonIcons.tsx @@ -9,7 +9,7 @@ export function SearchIcon() { > ); @@ -24,7 +24,7 @@ export function ArrowIcon() { fill="none" xmlns="http://www.w3.org/2000/svg" > - + ); } diff --git a/app/src/components/icons/ExportToolsIcons.tsx b/app/src/components/icons/ExportToolsIcons.tsx index cfe56ba..4dc7a5b 100644 --- a/app/src/components/icons/ExportToolsIcons.tsx +++ b/app/src/components/icons/ExportToolsIcons.tsx @@ -11,13 +11,13 @@ export function ZoneIcon({ isActive }: { isActive: boolean }) { @@ -41,27 +41,27 @@ export function AsileIcon({ isActive }: { isActive: boolean }) { > ); @@ -87,36 +87,36 @@ export function FloorIcon({ isActive }: { isActive: boolean }) { ); @@ -134,7 +134,7 @@ export function WallIcon({ isActive }: { isActive: boolean }) { @@ -212,56 +212,56 @@ export function WallIcon({ isActive }: { isActive: boolean }) { @@ -286,7 +286,7 @@ export function WindowIcon({ isActive }: { isActive: boolean }) { > @@ -324,11 +324,11 @@ export function DoorIcon({ isActive }: { isActive: boolean }) { > ); @@ -374,11 +374,11 @@ export function PillerIcon({ isActive }: { isActive: boolean }) { > @@ -393,17 +393,17 @@ export function PillerIcon({ isActive }: { isActive: boolean }) { > @@ -421,7 +421,7 @@ export function CommentIcon({ isActive }: { isActive: boolean }) { > @@ -471,8 +471,8 @@ export function FreeMoveIcon({ isActive }: { isActive: boolean }) { > ) : ( @@ -485,7 +485,7 @@ export function FreeMoveIcon({ isActive }: { isActive: boolean }) { > ); @@ -502,17 +502,17 @@ export function DeleteIcon({ isActive }: { isActive: boolean }) { > @@ -533,7 +533,7 @@ export function DeleteIcon({ isActive }: { isActive: boolean }) { > @@ -552,7 +552,7 @@ export function CursorIcon({ isActive }: { isActive: boolean }) { > ) : ( @@ -565,7 +565,7 @@ export function CursorIcon({ isActive }: { isActive: boolean }) { > @@ -584,8 +584,8 @@ export function PlayIcon({ isActive }: { isActive: boolean }) { > ); @@ -603,7 +603,7 @@ export function PenIcon({ isActive }: { isActive: boolean }) { @@ -623,13 +623,13 @@ export function SaveTemplateIcon({ isActive }: { isActive: boolean }) { @@ -648,19 +648,19 @@ export function MeasureToolIcon({ isActive }: { isActive: boolean }) { > ); diff --git a/app/src/components/icons/SimulationIcons.tsx b/app/src/components/icons/SimulationIcons.tsx index 67a1a51..b4aa881 100644 --- a/app/src/components/icons/SimulationIcons.tsx +++ b/app/src/components/icons/SimulationIcons.tsx @@ -9,13 +9,13 @@ export function AnalysisIcon({ isActive }: { isActive: boolean }) { > @@ -34,11 +34,11 @@ export function MechanicsIcon({ isActive }: { isActive: boolean }) { > ); @@ -55,15 +55,15 @@ export function PropertiesIcon({ isActive }: { isActive: boolean }) { > ); @@ -82,13 +82,13 @@ export function SimulationIcon({ isActive }: { isActive: boolean }) { fillRule="evenodd" clipRule="evenodd" d="M6.44104 7.04762C6.57815 6.98413 6.73614 6.98413 6.87325 7.04762L12.0161 9.42958C12.198 9.51377 12.3143 9.69589 12.3143 9.89624V15.8512C12.3143 16.0347 12.2165 16.2043 12.0577 16.2962L6.9148 19.2736C6.75547 19.3659 6.55881 19.3659 6.39949 19.2736L1.25661 16.2962C1.09779 16.2043 1 16.0347 1 15.8512V9.89624C1 9.69589 1.11635 9.51377 1.29815 9.42958L6.44104 7.04762ZM2.02857 10.7297L6.14286 12.794V17.9366L2.02857 15.5546V10.7297ZM7.17143 17.9366L11.2857 15.5546V10.7297L7.17143 12.794V17.9366ZM6.65714 11.9013L10.6163 9.91477L6.65714 8.08106L2.69798 9.91477L6.65714 11.9013Z" - fill={isActive ? "var(--icon-default-color-active)" : "var(--icon-default-color)"} + fill={"var(--icon-default-color-active)"} /> ); @@ -107,21 +107,21 @@ export function ResetIcon() { > @@ -140,7 +140,7 @@ export function PlayStopIcon() { > @@ -159,7 +159,7 @@ export function ExitIcon() { > diff --git a/app/src/components/layout/sidebarLeft/Outline.tsx b/app/src/components/layout/sidebarLeft/Outline.tsx index b7d5803..417f069 100644 --- a/app/src/components/layout/sidebarLeft/Outline.tsx +++ b/app/src/components/layout/sidebarLeft/Outline.tsx @@ -24,22 +24,26 @@ const Outline: React.FC = () => {
    ) : (
    - - +
    + +
    +
    + +
    )}
    diff --git a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx index d806740..9d2889f 100644 --- a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx +++ b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx @@ -100,7 +100,7 @@ const Analysis: React.FC = () => {
    Generate Report
    -
    +
    Create Analysis
    diff --git a/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx b/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx index 01b4ab3..8cc47d7 100644 --- a/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx +++ b/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx @@ -22,7 +22,7 @@ const PositionInput: React.FC = ({ value2 = "number", disabled = false, // Default disabled value isEyedrop = false, // Default isEyedrop value - handleEyeDropClick = () => { }, // Default function for eye drop click + handleEyeDropClick = () => {}, // Default function for eye drop click }) => { return (
    @@ -39,6 +39,7 @@ const PositionInput: React.FC = ({ disabled={disabled} // Apply disabled prop />
    +
    Y :
    {
    {/* Name */}
    {selectedFloorItem.userData.name}
    +
    + {}} + value1={selectedFloorItem.position.x.toFixed(5)} + value2={selectedFloorItem.position.z.toFixed(5)} + /> + {}} + value={parseFloat( + THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y).toFixed(5) + )} + /> +
    - {}} - value1={selectedFloorItem.position.x.toFixed(5)} - value2={selectedFloorItem.position.z.toFixed(5)} - /> - {}} - value={parseFloat( - THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y).toFixed(5) - )} - /> +
    +
    Render settings
    + + +
    -
    - - - - -
    User Data
    - - {/* Map through userData and render InputWithDropDown for each entry */} - {userData.map((data) => ( -
    - handleUserDataChange(data.id, newValue)} // Pass the change handler - /> -
    handleRemoveUserData(data.id)} - > - +
    +
    User Data
    + {userData.map((data) => ( +
    + handleUserDataChange(data.id, newValue)} // Pass the change handler + /> +
    handleRemoveUserData(data.id)} + > + +
    -
    - ))} + ))} - {/* Add new user data */} -
    - + Add -
    + {/* Add new user data */} +
    + + Add +
    +
    ); }; diff --git a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx index 251ada3..8b91afc 100644 --- a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx @@ -32,9 +32,7 @@ const GlobalProperties: React.FC = () => { const { renderDistance, setRenderDistance } = useRenderDistance(); const { setPlaneValue, setGridValue, planeValue, gridValue } = useTileDistance(); - useEffect(() => { - - }, [gridValue, planeValue]); + useEffect(() => {}, [gridValue, planeValue]); const { socket } = useSocketStore(); const { limitDistance, setLimitDistance } = useLimitDistance(); const [distance, setDistance] = useState(40); @@ -224,65 +222,66 @@ const GlobalProperties: React.FC = () => { // } return (
    -
    Environment
    -
    - - Optimize -
    +
    +
    Environment
    +
    + + Optimize +
    -
    +
    - - - - + + + + -
    - {/* //visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor} */} - { - // setLimitDistance(!limitDistance); - // // setDistance(75); - // // setRenderDistance(75); - // }} - onClick={async () => { - await limitRenderDistance(); // Call the function here - }} - /> - updateDistance(value)} - onPointerUp={updatedDist} - key={"6"} - /> +
    + {/* //visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor} */} + { + // setLimitDistance(!limitDistance); + // // setDistance(75); + // // setRenderDistance(75); + // }} + onClick={async () => { + await limitRenderDistance(); // Call the function here + }} + /> + updateDistance(value)} + onPointerUp={updatedDist} + key={"6"} + /> - {/*
    + {/*
    { onChange={(value: number) => updateGridDistance(value)} onPointerUp={updatedGrid} /> */} +
    ); }; diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx index a9f8cc0..1bb9400 100644 --- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx @@ -2,7 +2,12 @@ import React, { useEffect, useState } from "react"; import RenameInput from "../../../ui/inputs/RenameInput"; import Vector3Input from "../customInput/Vector3Input"; import { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore"; -import { useEditPosition, usezonePosition, useZones, usezoneTarget } from "../../../../store/store"; +import { + useEditPosition, + usezonePosition, + useZones, + usezoneTarget, +} from "../../../../store/store"; import { zoneCameraUpdate } from "../../../../services/visulization/zone/zoneCameraUpdation"; const ZoneProperties: React.FC = () => { @@ -13,9 +18,9 @@ const ZoneProperties: React.FC = () => { const { zones, setZones } = useZones(); useEffect(() => { - setZonePosition(selectedZone.zoneViewPortPosition) - setZoneTarget(selectedZone.zoneViewPortTarget) - }, [selectedZone?.zoneViewPortPosition, selectedZone?.zoneViewPortTarget]) + setZonePosition(selectedZone.zoneViewPortPosition); + setZoneTarget(selectedZone.zoneViewPortTarget); + }, [selectedZone?.zoneViewPortPosition, selectedZone?.zoneViewPortTarget]); async function handleSetView() { try { @@ -25,7 +30,7 @@ const ZoneProperties: React.FC = () => { let zonesdata = { zoneId: selectedZone.zoneId, viewPortposition: zonePosition, - viewPortCenter: zoneTarget + viewPortCenter: zoneTarget, }; let response = await zoneCameraUpdate(zonesdata, organization); @@ -34,14 +39,11 @@ const ZoneProperties: React.FC = () => { } else { // console.log(response); } - - } catch (error) { - - } + } catch (error) {} } function handleEditView() { - setEdit(!Edit); // This will toggle the `Edit` state correctly + setEdit(!Edit); // This will toggle the `Edit` state correctly } async function handleZoneNameChange(newName: string) { @@ -49,11 +51,11 @@ const ZoneProperties: React.FC = () => { const organization = email?.split("@")[1]?.split(".")[0]; const zonesdata = { zoneId: selectedZone.zoneId, - zoneName: newName + zoneName: newName, }; // Call your API to update the zone let response = await zoneCameraUpdate(zonesdata, organization); - console.log('response: ', response); + console.log("response: ", response); if (response.message === "updated successfully") { setZones((prevZones: any[]) => prevZones.map((zone) => @@ -66,7 +68,10 @@ const ZoneProperties: React.FC = () => { // console.log(response?.message); } } - function handleVectorChange(key: "zoneViewPortTarget" | "zoneViewPortPosition", newValue: [number, number, number]) { + function handleVectorChange( + key: "zoneViewPortTarget" | "zoneViewPortPosition", + newValue: [number, number, number] + ) { setSelectedZone((prev) => ({ ...prev, [key]: newValue })); } const checkZoneNameDuplicate = (name: string) => { @@ -79,33 +84,40 @@ const ZoneProperties: React.FC = () => { return (
    -
    - -
    - {Edit ? "Cancel" : "Edit"} +
    +
    + +
    + {Edit ? "Cancel" : "Edit"} +
    -
    - 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} - /> + 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 -
    - )} + {Edit && ( +
    + Set View +
    + )} +
    ); }; export default ZoneProperties; - diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 87d3bf6..88ae240 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -81,7 +81,7 @@ const EventProperties: React.FC = () => { )} {!currentEventData && selectedEventSphere && ( -
    +

    Oops! It looks like this object doesn't have an event assigned yet. To continue, please link it to one of the @@ -118,7 +118,7 @@ const EventProperties: React.FC = () => {

    )} {!selectedEventSphere && ( -
    +

    Oops! It looks like you haven't selected an event point yet. Please select an event to view its properties. diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx index b370b3e..7a0bc07 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -135,7 +135,7 @@ function ConveyorMechanics() { <> {selectedEventData && ( <> -

    +
    +
    + - - -
    -
    - +
    +
    + +
    +
    + + {activeOption === "default" && } + {activeOption === "spawn" && ( + + )} + {activeOption === "swap" && ( + + )} + {activeOption === "despawn" && } + {activeOption === "delay" && ( + + )} +
    -
    - - {activeOption === "default" && } - {activeOption === "spawn" && ( - - )} - {activeOption === "swap" && ( - - )} - {activeOption === "despawn" && } - {activeOption === "delay" && ( - - )} +
    +
    -
    -
    - -
    +
    )} diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx index fa2cfdf..db785da 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -85,7 +85,7 @@ function MachineMechanics() { return ( <> {selectedEventData && ( - <> +
    - +
    )} ); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx index 7c20ce5..acf65ae 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -134,7 +134,7 @@ function RoboticArmMechanics() { <> {selectedEventData && selectedPointData && ( <> -
    +
    +
    + - - - {selectedAction.actionId && currentAction && ( -
    -
    - + {selectedAction.actionId && currentAction && ( +
    +
    + +
    +
    + {}} + disabled={true} + /> + +
    +
    + +
    -
    - {}} - disabled={true} - /> - -
    -
    - -
    -
    - )} + )} +
    )} diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index d92ed80..ae7a498 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -74,7 +74,7 @@ function StorageMechanics() { return ( <> {selectedEventData && ( - <> +
    - + )} ); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index 93fa3c7..d8456e5 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -4,182 +4,186 @@ import RenameInput from "../../../../../ui/inputs/RenameInput"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import Trigger from "../trigger/Trigger"; import { - useSelectedEventData, - useSelectedProduct, + useSelectedEventData, + useSelectedProduct, } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import TravelAction from "../actions/TravelAction"; import ActionsList from "../components/ActionsList"; function VehicleMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "travel">( - "default" - ); - const [selectedPointData, setSelectedPointData] = useState(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateEvent, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState<"default" | "travel">( + "default" + ); + const [selectedPointData, setSelectedPointData] = useState< + VehiclePointSchema | undefined + >(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateEvent, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData.data.modelUuid, - selectedEventData.selectedPoint - ) as VehiclePointSchema | undefined; + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint + ) as VehiclePointSchema | undefined; - if (point) { - setSelectedPointData(point); - setActiveOption(point.action.actionType as "travel"); - } - } - }, [selectedProduct, selectedEventData, getPointByUuid]); + if (point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "travel"); + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleSpeedChange = (value: string) => { - if (!selectedEventData) return; - updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { - speed: parseFloat(value), - }); - }; + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { + speed: parseFloat(value), + }); + }; - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as "travel"; - setActiveOption(validOption); + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "travel"; + setActiveOption(validOption); - updateAction(selectedPointData.action.actionUuid, { - actionType: validOption, - }); - }; + updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); + }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { actionName: newName }); - }; + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + }; - const handleLoadCapacityChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - loadCapacity: parseFloat(value), - }); - }; + const handleLoadCapacityChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + loadCapacity: parseFloat(value), + }); + }; - const handleUnloadDurationChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - unLoadDuration: parseFloat(value), - }); - }; + const handleUnloadDurationChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + unLoadDuration: parseFloat(value), + }); + }; - const handlePickPointChange = (value: string) => { - if (!selectedPointData) return; - }; + const handlePickPointChange = (value: string) => { + if (!selectedPointData) return; + }; - const handleUnloadPointChange = (value: string) => { - if (!selectedPointData) return; - }; + const handleUnloadPointChange = (value: string) => { + if (!selectedPointData) return; + }; - // Get current values from store - const currentSpeed = - selectedEventData?.data.type === "vehicle" - ? selectedEventData.data.speed.toString() - : "0.5"; + // Get current values from store + const currentSpeed = + selectedEventData?.data.type === "vehicle" + ? selectedEventData.data.speed.toString() + : "0.5"; - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; - const currentLoadCapacity = selectedPointData - ? selectedPointData.action.loadCapacity.toString() - : "1"; + const currentLoadCapacity = selectedPointData + ? selectedPointData.action.loadCapacity.toString() + : "1"; - const currentUnloadDuration = selectedPointData - ? selectedPointData.action.unLoadDuration.toString() - : "1"; + const currentUnloadDuration = selectedPointData + ? selectedPointData.action.unLoadDuration.toString() + : "1"; - const currentPickPoint = selectedPointData?.action.pickUpPoint; + const currentPickPoint = selectedPointData?.action.pickUpPoint; - const currentUnloadPoint = selectedPointData?.action.unLoadPoint; + const currentUnloadPoint = selectedPointData?.action.unLoadPoint; - const availableActions = { - defaultOption: "travel", - options: ["travel"], - }; + const availableActions = { + defaultOption: "travel", + options: ["travel"], + }; - return ( + return ( + <> + {selectedEventData && ( <> - {selectedEventData && ( - <> -
    -
    -
    - { }} - onChange={handleSpeedChange} - /> -
    -
    -
    - -
    -
    - -
    -
    - +
    +
    +
    + {}} + onChange={handleSpeedChange} + /> +
    +
    +
    +
    + +
    +
    + +
    +
    + - {activeOption === "travel" && ( - - )} -
    -
    -
    - -
    - - )} + {activeOption === "travel" && ( + + )} +
    +
    +
    + +
    + - ); + )} + + ); } export default VehicleMechanics; diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index b037098..a8957d1 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { AddIcon, ArrowIcon, @@ -47,6 +47,8 @@ const Simulations: React.FC = () => { const { selectedProduct, setSelectedProduct } = useSelectedProduct(); const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); + const [openObjects, setOpenObjects] = useState(true); + const handleAddProduct = () => { addProduct(`Product ${products.length + 1}`, generateUUID()); }; @@ -102,7 +104,7 @@ const Simulations: React.FC = () => {
    Simulations
    -
    +
    Products
    @@ -164,16 +166,18 @@ const Simulations: React.FC = () => {
    -
    -
    +
    +
    - {events.map((event, index) => ( - - ))} + + {openObjects && + events.map((event, index) => )}
    diff --git a/app/src/components/ui/FileMenu.tsx b/app/src/components/ui/FileMenu.tsx index a7c876d..798cc62 100644 --- a/app/src/components/ui/FileMenu.tsx +++ b/app/src/components/ui/FileMenu.tsx @@ -2,12 +2,16 @@ import React, { useState } from "react"; import RenameInput from "./inputs/RenameInput"; import { ArrowIcon } from "../icons/ExportCommonIcons"; import MenuBar from "./menu/menu"; +import { ProjectIcon } from "../icons/HeaderIcons"; const FileMenu: React.FC = () => { const [openMenu, setOpenMenu] = useState(false); return (
    +
    + +
    = ({ -
    +
    diff --git a/app/src/styles/abstracts/variables.scss b/app/src/styles/abstracts/variables.scss index d1a6a5e..2913425 100644 --- a/app/src/styles/abstracts/variables.scss +++ b/app/src/styles/abstracts/variables.scss @@ -16,72 +16,91 @@ $text-button-color: #f3f3fd; $text-color-dark: #f3f3fd; $text-disabled-dark: #6f6f7a; $input-text-color-dark: #b5b5c8; -$highlight-text-color-dark: #B392F0; +$highlight-text-color-dark: #b392f0; $text-button-color-dark: #f3f3fd; // background colors // ---------- light mode ---------- -$background-color: linear-gradient(-45deg, #FCFDFDCC 0%, #FCFDFD99 100%); +$background-color: linear-gradient(-45deg, #fcfdfdcc 0%, #fcfdfd99 100%); $background-color-solid: #fcfdfd; -$background-color-secondary: #FCFDFD4D; +$background-color-secondary: #fcfdfd4d; $background-color-accent: #6f42c1; $background-color-button: #6f42c1; -$background-color-drop-down: #6F42C14D; -$background-color-input: #FFFFFF4D; -$background-color-input-focus: #F2F2F7; -$background-color-drop-down-gradient: linear-gradient(-45deg, #75649366 0%, #40257266 100%); -$background-color-selected: #E0DFFF; -$background-radial-gray-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%); +$background-color-drop-down: #6f42c14d; +$background-color-input: #ffffff4d; +$background-color-input-focus: #f2f2f7; +$background-color-drop-down-gradient: linear-gradient( + -45deg, + #75649366 0%, + #40257266 100% +); +$background-color-selected: #e0dfff; +$background-radial-gray-gradient: radial-gradient( + circle, + #bfe0f8 0%, + #e9ebff 46%, + #e2acff 100% +); // ---------- dark mode ---------- -$background-color-dark: linear-gradient(-45deg, #333333B3 0%, #2D2437B3 100%); +$background-color-dark: linear-gradient(-45deg, #333333b3 0%, #2d2437b3 100%); $background-color-solid-dark: #19191d; -$background-color-secondary-dark: #19191D99; +$background-color-secondary-dark: #19191d99; $background-color-accent-dark: #6f42c1; $background-color-button-dark: #6f42c1; $background-color-drop-down-dark: #50505080; -$background-color-input-dark: #FFFFFF33; +$background-color-input-dark: #ffffff33; $background-color-input-focus-dark: #333333; -$background-color-drop-down-gradient-dark: linear-gradient(-45deg, #8973B166 0%, #53427366 100%); -$background-color-selected-dark: #403E66; -$background-radial-gray-gradient-dark: radial-gradient(circle, #31373b 0%, #48494b 46%, #52415c 100%); +$background-color-drop-down-gradient-dark: linear-gradient( + -45deg, + #8973b166 0%, + #53427366 100% +); +$background-color-selected-dark: #403e66; +$background-radial-gray-gradient-dark: radial-gradient( + circle, + #31373b 0%, + #48494b 46%, + #52415c 100% +); // border colors // ---------- light mode ---------- -$border-color: #E0DFFF; -$border-color-accent: #6F42C1; +$border-color: #e0dfff; +$input-border-color: #d5dddd80; +$border-color-accent: #6f42c1; // ---------- dark mode ---------- -$border-color-dark: #564B69; -$border-color-accent-dark: #6F42C1; +$border-color-dark: #564b69; +$input-border-color-dark: #d5dddd80; +$border-color-accent-dark: #6f42c1; // highlight colors // ---------- light mode ---------- -$highlight-accent-color: #E0DFFF; -$highlight-secondary-color: #6F42C1; +$highlight-accent-color: #e0dfff; +$highlight-secondary-color: #6f42c1; // ---------- dark mode ---------- -$highlight-accent-color-dark: #403E6A; -$highlight-secondary-color-dark: #C4ABF1; +$highlight-accent-color-dark: #403e6a; +$highlight-secondary-color-dark: #c4abf1; // icon colors // ---------- light mode ---------- -$icon-default-color: #6F42C1; +$icon-default-color: #6f42c1; $icon-default-color-hover: #7f4ddb; -$icon-default-color-active: #F2F2F7; +$icon-default-color-active: #f2f2f7; // ---------- dark mode ---------- -$icon-default-color-dark: #6F42C1; +$icon-default-color-dark: #6f42c1; $icon-default-color-hover-dark: #7f4ddb; -$icon-default-color-active-dark: #F2F2F7; +$icon-default-color-active-dark: #f2f2f7; // colors -$color1: #A392CD; +$color1: #a392cd; $color2: #7b4cd3; -$color3: #B186FF; -$color4: #8752E8; -$color5: #C7A8FF; - +$color3: #b186ff; +$color4: #8752e8; +$color5: #c7a8ff; // old variables $accent-color: #6f42c1; @@ -106,7 +125,12 @@ $acent-gradient-dark: linear-gradient(90deg, #b392f0 0%, #a676ff 100%); $acent-gradient: linear-gradient(90deg, #6f42c1 0%, #925df3 100%); $faint-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%); -$faint-gradient-dark: radial-gradient(circle, #31373b 0%, #48494b 46%, #52415c 100%); +$faint-gradient-dark: radial-gradient( + circle, + #31373b 0%, + #48494b 46%, + #52415c 100% +); $font-inter: "Inter", sans-serif; $font-josefin-sans: "Josefin Sans", sans-serif; diff --git a/app/src/styles/base/base.scss b/app/src/styles/base/base.scss index bd1403e..10fb87c 100644 --- a/app/src/styles/base/base.scss +++ b/app/src/styles/base/base.scss @@ -23,6 +23,7 @@ // border colors --border-color: #{$border-color}; + --input-border-color: #{$input-border-color}; --border-color-accent: #{$border-color-accent}; // highlight colors @@ -73,6 +74,7 @@ // border colors --border-color: #{$border-color}; + --input-border-color: #{$input-border-color-dark}; --border-color-accent: #{$border-color-accent-dark}; // highlight colors @@ -136,8 +138,8 @@ body { } ::-webkit-scrollbar { - width: 4px; - height: 4px; + width: 0px; + height: 0px; } ::-webkit-scrollbar-track { diff --git a/app/src/styles/base/global.scss b/app/src/styles/base/global.scss index d1bf505..d90e6fb 100644 --- a/app/src/styles/base/global.scss +++ b/app/src/styles/base/global.scss @@ -2,8 +2,10 @@ @use "../abstracts/mixins" as *; section, .section{ - padding: 12px; + padding: 4px; outline: 1px solid var(--border-color); + outline-offset: -1px; border-radius: #{$border-radius-large}; background: var(--background-color); + margin: 4px 0; } diff --git a/app/src/styles/components/input.scss b/app/src/styles/components/input.scss index 48d6ee8..b4e7651 100644 --- a/app/src/styles/components/input.scss +++ b/app/src/styles/components/input.scss @@ -5,12 +5,12 @@ input { width: 100%; - padding: 2px 4px; - border-radius: #{$border-radius-small}; - outline: 1px solid var(--border-color); + padding: 4px 8px; + border-radius: #{$border-radius-large}; + outline: 1px solid var(--input-border-color); outline-offset: -1px; border: none; - background: transparent; + background: var(--background-color-input); color: var(--input-text-color); &:focus, @@ -44,6 +44,18 @@ input { } } +input[type="number"] { + // Chrome, Safari, Edge, Opera + &::-webkit-outer-spin-button, + &::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + + // Firefox + -moz-appearance: textfield; +} + .input-value { color: var(--input-text-color); font-size: var(--font-size-regular); @@ -61,9 +73,7 @@ input { color: var(--input-text-color); font-size: var(--font-size-regular); font-weight: var(--font-weight-regular); - border: 1px solid var(--accent-color); outline: none; - border-radius: #{$border-radius-small}; line-height: 26px; padding: 0 8px; } @@ -102,10 +112,11 @@ input { .search-container { @include flex-center; width: 100%; - border-radius: #{$border-radius-small}; - padding: 6px 2px; + border-radius: #{$border-radius-extra-large}; + padding: 3px 2px; position: relative; border: 1px solid var(--border-color); + background: var(--background-color-input-focus); .icon-container { @include flex-center; @@ -220,7 +231,6 @@ input { justify-content: space-between; cursor: pointer; border-radius: 6px; - background: var(--background-color); } .dropdown-options { @@ -469,7 +479,7 @@ input { .check-box { height: 24px; width: 38px; - background: var(--background-color-secondary); + background: var(--background-color); border-radius: #{$border-radius-large}; position: relative; cursor: pointer; @@ -480,7 +490,7 @@ input { width: 20px; top: 2px; left: 2px; - background: var(--accent-color); + background: var(--text-button-color); border-radius: #{$border-radius-circle}; transition: left 0.3s ease; } @@ -726,17 +736,17 @@ input { @include flex-center; } } - .upload-custom-asset-button{ + .upload-custom-asset-button { padding: 6px 12px; @include flex-space-between; - .title{ + .title { white-space: nowrap; width: 40%; } - input{ + input { display: none; } - .upload-button{ + .upload-button { width: 60%; background: var(--highlight-accent-color); color: var(--accent-color); diff --git a/app/src/styles/components/menu/menu.scss b/app/src/styles/components/menu/menu.scss index 34c56d1..be9e17f 100644 --- a/app/src/styles/components/menu/menu.scss +++ b/app/src/styles/components/menu/menu.scss @@ -6,15 +6,31 @@ align-items: center; gap: 2px; position: relative; - height: 32px; + border-radius: #{$border-radius-extra-large}; + background: var(--background-color-drop-down); + padding: 3px 8px; + width: fit-content; + max-width: 100%; .project-name { - line-height: 32px; + @include flex-center; height: 100%; + line-height: 26px; + .icon{ + @include flex-center; + height: 20px; + width: 20px; + } + .input-value{ + max-width: 120px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } .more-options-button { @include flex-center; border-radius: #{$border-radius-small}; - height: 28px; + height: 22px; position: relative; &:hover { background: var(--highlight-accent-color); @@ -41,6 +57,7 @@ box-shadow: var(--box-shadow-light); border-radius: 8px; border: 1px solid var(--border-color); + backdrop-filter: blur(10px); .menu-buttons { display: flex; flex-direction: column; diff --git a/app/src/styles/components/tools.scss b/app/src/styles/components/tools.scss index c80caf5..abea736 100644 --- a/app/src/styles/components/tools.scss +++ b/app/src/styles/components/tools.scss @@ -49,10 +49,10 @@ } .active { - background: var(--accent-color); + background: var(--background-color-accent); &:hover { - background: var(--accent-color); + background: var(--background-color-accent); } } } diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 403b27a..8e84d78 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -44,33 +44,40 @@ width: 32px; min-height: 32px; min-width: 32px; - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-large}; &:hover { - background: var(--background-color-secondary); + outline: 1px solid var(--border-color); + outline-offset: -1px; + background: var(--background-color-drop-down); } } .active { - background: var(--background-color-secondary); - outline: 1px solid var(--accent-color); + background: var(--background-color-accent); + outline: 1px solid var(--border-color); outline-offset: -1px; + rect { + stroke: var(--icon-default-color-active); + } + circle { + fill: var(--icon-default-color-active); + } + &:hover { + background: var(--background-color-secondary); + } } } .sidebar-left-container { min-height: 50vh; - padding-bottom: 12px; + padding-bottom: 4px; position: relative; display: flex; flex-direction: column; .sidebar-left-content-container { - border-bottom: 1px solid var(--border-color); - // flex: 1; - // height: calc(100% - 36px); position: relative; - // overflow: auto; .template-list { display: flex; @@ -232,8 +239,12 @@ .outline-content-container { position: relative; height: 100%; - overflow: auto; - max-height: 60vh; + padding: 8px; + .overflow { + height: calc(100% - 16px); + max-height: 46vh; + overflow: auto; + } } } } @@ -323,8 +334,8 @@ display: flex; .user-profile { - background: var(--accent-color); - color: var(--primary-color); + background: var(--background-color-accent); + color: var(--text-button-color); } .user-organization { @@ -349,6 +360,8 @@ .sidebar-actions-container { position: absolute; left: -40px; + background: transparent; + overflow: visible; .sidebar-action-list { margin-bottom: 12px; @@ -359,6 +372,8 @@ background: var(--background-color-secondary); backdrop-filter: blur(8px); box-shadow: #{$box-shadow-medium}; + outline: 1px solid var(--border-color); + outline-offset: -1px; } .active { @@ -715,10 +730,10 @@ .machine-mechanics-content-container, .simulations-container, .event-proprties-wrapper { + position: relative; max-height: calc(60vh - (47px - 35px)); - overflow: auto; - overflow-y: scroll; - + width: calc(100% - 4px); + overflow-x: hidden; .header { @include flex-space-between; padding: 6px 12px; @@ -904,9 +919,8 @@ .collapse-header-container { @include flex-space-between; padding-right: 12px; - margin-top: 8px; - border-top: 1px solid var(--border-color); - border-bottom: 1px solid var(--border-color); + margin: 8px 0; + width: 100%; .header { color: var(--accent-color); @@ -990,7 +1004,6 @@ @include flex-space-between; padding: 10px 12px; color: var(--text-color); - margin-bottom: 4px; .input-value { color: inherit; } @@ -998,7 +1011,6 @@ .input-container { @include flex-center; - .remove-button { @include flex-center; height: 18px; @@ -1032,6 +1044,13 @@ } .custom-input-container { + @include flex-space-between; + .split { + height: 20px; + width: 2px; + border-radius: 2px; + background: var(--text-disabled); + } .header { @include flex-space-between; border: none; @@ -1043,11 +1062,9 @@ .inputs-container { @include flex-space-between; - padding-bottom: 8px; .input-container { padding: 0 12px; - margin-top: 6px; gap: 6px; } } @@ -1065,7 +1082,6 @@ .dropdown-header-container, .dropdown-content-container { padding: 6px 12px; - border-top: 1px solid var(--highlight-accent-color); } .input-range-container { diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index 617e39f..64b0f0c 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -770,6 +770,7 @@ .editWidgetOptions { position: absolute; background: var(--background-color); + backdrop-filter: blur(10px); z-index: 3; display: flex; flex-direction: column; From 949dbbca8d4e73aba920dd599b9510c7bf5de76a Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 29 Apr 2025 18:32:25 +0530 Subject: [PATCH 24/30] refactor: Enhance FileMenu component with click handling and outside click detection --- app/src/components/ui/FileMenu.tsx | 42 +++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/app/src/components/ui/FileMenu.tsx b/app/src/components/ui/FileMenu.tsx index 798cc62..da85e54 100644 --- a/app/src/components/ui/FileMenu.tsx +++ b/app/src/components/ui/FileMenu.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useEffect, useRef } from "react"; import RenameInput from "./inputs/RenameInput"; import { ArrowIcon } from "../icons/ExportCommonIcons"; import MenuBar from "./menu/menu"; @@ -6,24 +6,48 @@ import { ProjectIcon } from "../icons/HeaderIcons"; const FileMenu: React.FC = () => { const [openMenu, setOpenMenu] = useState(false); + const containerRef = useRef(null); + let clickTimeout: NodeJS.Timeout | null = null; + + const handleClick = () => { + if (clickTimeout) return; + setOpenMenu((prev) => !prev); + clickTimeout = setTimeout(() => { + clickTimeout = null; + }, 800); + }; + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + containerRef.current && + !containerRef.current.contains(event.target as Node) + ) { + setOpenMenu(false); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + return ( -
    + ); }; From 529771712353bc2a64c47f0f3986c77c6e5d55ec Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 29 Apr 2025 18:41:31 +0530 Subject: [PATCH 25/30] fix: Update loading progress condition in Project component and correct border-radius in sidebar styles --- app/src/modules/visualization/RealTimeVisulization.tsx | 2 +- app/src/pages/Project.tsx | 2 +- app/src/styles/layout/sidebar.scss | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index 71faefb..05f7371 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -335,7 +335,7 @@ const RealTimeVisulization: React.FC = () => { onDrop={(event) => handleDrop(event)} onDragOver={(event) => event.preventDefault()} > - {/* */} +
    {activeModule === "visualization" && selectedZone.zoneName !== "" && ( diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index d88e425..c491583 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -64,7 +64,7 @@ const Project: React.FC = () => {
    */} - {/* {loadingProgress && } */} + {loadingProgress > 0 && } {!isPlaying && ( <> {toggleThreeD && } diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index eb4e2c0..01715ec 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -8,7 +8,7 @@ left: 8px; background: var(--background-color); backdrop-filter: blur(150px); - border-radius: #{$border-radius-xxx}; + border-radius: #{$border-radius-extra-large}; outline: 1px solid var(--border-color); box-shadow: #{$box-shadow-medium}; z-index: #{$z-index-tools}; @@ -257,7 +257,7 @@ right: 8px; background: var(--background-color); backdrop-filter: blur(150px); - border-radius: #{$border-radius-xxx}; + border-radius: #{$border-radius-extra-large}; outline: 1px solid var(--border-color); box-shadow: #{$box-shadow-medium}; z-index: #{$z-index-tools}; From 882c81a385928bc4c137ff535fa878d020a61196 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 29 Apr 2025 19:15:17 +0530 Subject: [PATCH 26/30] Refactor asset model handling and event data management - Removed redundant data structure in handleModelLoad function. - Introduced eventData object to encapsulate event-related information for different asset types (Conveyor, Vehicle, ArmBot, StaticMachine). - Updated socket emission to include complete data with eventData. - Enhanced copy-paste and duplication controls to maintain eventData integrity during object duplication. - Integrated event data updates in move and rotate controls to reflect changes in the simulation state. - Improved PointsCreator component to handle rotation for event groups. - Updated handleAddEventToProduct function to support event data management. - Enhanced product management to fetch existing products from the server and handle new product creation. - Added new types for eventData in worldTypes and simulationTypes for better type safety. - Refactored IndexedDB utility functions for cleaner code. --- .../eventProperties/EventProperties.tsx | 218 +++++----- .../mechanics/conveyorMechanics.tsx | 348 ++++++++-------- .../mechanics/machineMechanics.tsx | 201 +++++----- .../mechanics/roboticArmMechanics.tsx | 300 +++++++------- .../mechanics/storageMechanics.tsx | 187 +++++---- .../sidebarRight/simulation/Simulations.tsx | 346 ++++++++-------- .../IntialLoad/loadInitialFloorItems.ts | 375 ++++++------------ .../geomentries/assets/addAssetModel.ts | 105 +++-- .../builder/groups/floorItemsGroup.tsx | 1 + .../selectionControls/copyPasteControls.tsx | 46 ++- .../selectionControls/duplicationControls.tsx | 46 ++- .../selectionControls/moveControls.tsx | 25 +- .../selectionControls/rotateControls.tsx | 26 +- .../events/points/creator/pointsCreator.tsx | 12 +- .../functions/handleAddEventToProduct.ts | 42 +- .../modules/simulation/products/products.tsx | 33 +- app/src/modules/simulation/simulation.tsx | 4 +- .../triggers/connector/triggerConnector.tsx | 197 +++++++-- app/src/store/simulation/useProductStore.ts | 7 + app/src/types/simulationTypes.d.ts | 2 +- app/src/types/world/worldTypes.d.ts | 13 + app/src/utils/indexDB/idbUtils.ts | 54 +-- 22 files changed, 1379 insertions(+), 1209 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 87d3bf6..4fa9105 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -1,9 +1,8 @@ import React, { useEffect, useState } from "react"; import { - useSelectedAsset, - useSelectedEventData, - useSelectedEventSphere, - useSelectedProduct, + useSelectedEventData, + useSelectedEventSphere, + useSelectedProduct, } from "../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import ConveyorMechanics from "./mechanics/conveyorMechanics"; @@ -13,120 +12,117 @@ import MachineMechanics from "./mechanics/machineMechanics"; import StorageMechanics from "./mechanics/storageMechanics"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import { handleAddEventToProduct } from "../../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; +import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; const EventProperties: React.FC = () => { - const { selectedEventData } = useSelectedEventData(); - const { getEventByModelUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); - const [currentEventData, setCurrentEventData] = useState( - null - ); - const [assetType, setAssetType] = useState(null); - const { products, addEvent } = useProductStore(); - const { selectedEventSphere } = useSelectedEventSphere(); + const { selectedEventData } = useSelectedEventData(); + const { getEventByModelUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + const [currentEventData, setCurrentEventData] = useState(null); + const [assetType, setAssetType] = useState(null); + const { products, addEvent } = useProductStore(); + const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); - useEffect(() => { - const event = getCurrentEventData(); - setCurrentEventData(event); + useEffect(() => { + const event = getCurrentEventData(); + setCurrentEventData(event); - const type = determineAssetType(event); - setAssetType(type); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedEventData, selectedProduct]); + const type = determineAssetType(event); + setAssetType(type); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedEventData, selectedProduct]); + + const getCurrentEventData = () => { + if (!selectedEventData?.data || !selectedProduct) return null; + return ( + getEventByModelUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid + ) ?? null + ); + }; + + const determineAssetType = (event: EventsSchema | null) => { + if (!event) return null; + + switch (event.type) { + case "transfer": + return "conveyor"; + case "vehicle": + return "vehicle"; + case "roboticArm": + return "roboticArm"; + case "machine": + return "machine"; + case "storageUnit": + return "storageUnit"; + default: + return null; + } + }; - const getCurrentEventData = () => { - if (!selectedEventData?.data || !selectedProduct) return null; return ( - getEventByModelUuid( - selectedProduct.productId, - selectedEventData.data.modelUuid - ) ?? null +
    + {currentEventData && ( + <> +
    +
    + {selectedEventData?.data.modelName} +
    +
    + {assetType === "conveyor" && } + {assetType === "vehicle" && } + {assetType === "roboticArm" && } + {assetType === "machine" && } + {assetType === "storageUnit" && } + + )} + {!currentEventData && selectedEventSphere && ( +
    +

    + Oops! It looks like this object doesn't have an + event assigned yet. To continue, please link it to one of the + products below. +

    + +
    +

    + Here are some products you can add it to: +

    +
      + {products.map((product) => ( +
    • + +
    • + ))} +
    +
    +
    + ) + } + {!selectedEventSphere && ( +
    +

    + Oops! It looks like you haven't selected an event + point yet. Please select an event to view its properties. +

    +
    + )} +
    ); - }; - - const determineAssetType = (event: EventsSchema | null) => { - if (!event) return null; - - switch (event.type) { - case "transfer": - return "conveyor"; - case "vehicle": - return "vehicle"; - case "roboticArm": - return "roboticArm"; - case "machine": - return "machine"; - case "storageUnit": - return "storageUnit"; - default: - return null; - } - }; - - return ( -
    - {currentEventData && ( - <> -
    -
    - {selectedEventData?.data.modelName} -
    -
    - {assetType === "conveyor" && } - {assetType === "vehicle" && } - {assetType === "roboticArm" && } - {assetType === "machine" && } - {assetType === "storageUnit" && } - - )} - {!currentEventData && selectedEventSphere && ( -
    -

    - Oops! It looks like this object doesn't have an - event assigned yet. To continue, please link it to one of the - products below. -

    - -
    -

    - Here are some products you can add it to: -

    -
      - {products.map((product) => ( -
    • - -
    • - ))} -
    -
    -
    - )} - {!selectedEventSphere && ( -
    -

    - Oops! It looks like you haven't selected an event - point yet. Please select an event to view its properties. -

    -
    - )} -
    - ); }; export default EventProperties; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx index b370b3e..61c9c6c 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -8,217 +8,193 @@ import SwapAction from "../actions/SwapAction"; import SpawnAction from "../actions/SpawnAction"; import DefaultAction from "../actions/DefaultAction"; import Trigger from "../trigger/Trigger"; -import { - useSelectedEventData, - useSelectedProduct, -} from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import ActionsList from "../components/ActionsList"; function ConveyorMechanics() { - const [activeOption, setActiveOption] = useState< - "default" | "spawn" | "swap" | "delay" | "despawn" - >("default"); - const [selectedPointData, setSelectedPointData] = useState< - ConveyorPointSchema | undefined - >(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateEvent, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateEvent, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint - ) as ConveyorPointSchema | undefined; - if (point && "action" in point) { - setSelectedPointData(point); - setActiveOption( - point.action.actionType as - | "default" - | "spawn" - | "swap" - | "delay" - | "despawn" - ); - } - } - }, [selectedProduct, selectedEventData, getPointByUuid]); + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as ConveyorPointSchema | undefined; + if (point && "action" in point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as | "default" | "spawn" | "swap" | "delay" | "despawn"); + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleSpeedChange = (value: string) => { - if (!selectedEventData) return; - updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { - speed: parseFloat(value), - }); - }; + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { + speed: parseFloat(value), + }); + }; - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as - | "default" - | "spawn" - | "swap" - | "delay" - | "despawn"; - setActiveOption(validOption); + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as | "default" | "spawn" | "swap" | "delay" | "despawn"; + setActiveOption(validOption); - updateAction(selectedPointData.action.actionUuid, { - actionType: validOption, - }); - }; + updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); + }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { actionName: newName }); - }; + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + }; - const handleSpawnCountChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - spawnCount: value === "inherit" ? "inherit" : parseFloat(value), - }); - }; + const handleSpawnCountChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + spawnCount: value === "inherit" ? "inherit" : parseFloat(value), + }); + }; - const handleSpawnIntervalChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - spawnInterval: value === "inherit" ? "inherit" : parseFloat(value), - }); - }; + const handleSpawnIntervalChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + spawnInterval: value === "inherit" ? "inherit" : parseFloat(value), + }); + }; - const handleMaterialSelect = (material: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { material }); - }; + const handleMaterialSelect = (material: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { material }); + }; - const handleDelayChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - delay: value === "inherit" ? "inherit" : parseFloat(value), - }); - }; + const handleDelayChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + delay: value === "inherit" ? "inherit" : parseFloat(value), + }); + }; - const availableActions = { - defaultOption: "default", - options: ["default", "spawn", "swap", "delay", "despawn"], - }; + const availableActions = { + defaultOption: "default", + options: ["default", "spawn", "swap", "delay", "despawn"], + }; - // Get current values from store - const currentSpeed = - selectedEventData?.data.type === "transfer" - ? selectedEventData.data.speed.toString() - : "0.5"; + // Get current values from store + const currentSpeed = selectedEventData?.data.type === "transfer" + ? selectedEventData.data.speed.toString() + : "0.5"; - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; - const currentMaterial = selectedPointData - ? selectedPointData.action.material - : "Default material"; + const currentMaterial = selectedPointData + ? selectedPointData.action.material + : "Default material"; - const currentSpawnCount = selectedPointData - ? selectedPointData.action.spawnCount?.toString() || "1" - : "1"; + const currentSpawnCount = selectedPointData + ? selectedPointData.action.spawnCount?.toString() || "1" + : "1"; - const currentSpawnInterval = selectedPointData - ? selectedPointData.action.spawnInterval?.toString() || "1" - : "1"; + const currentSpawnInterval = selectedPointData + ? selectedPointData.action.spawnInterval?.toString() || "1" + : "1"; - const currentDelay = selectedPointData - ? selectedPointData.action.delay?.toString() || "0" - : "0"; + const currentDelay = selectedPointData + ? selectedPointData.action.delay?.toString() || "0" + : "0"; - return ( - <> - {selectedEventData && ( + return ( <> -
    -
    -
    - {}} - onChange={handleSpeedChange} - /> -
    -
    -
    + {selectedEventData && ( + <> +
    +
    +
    + { }} + onChange={handleSpeedChange} + /> +
    +
    +
    - + -
    -
    - -
    -
    - - {activeOption === "default" && } - {activeOption === "spawn" && ( - - )} - {activeOption === "swap" && ( - - )} - {activeOption === "despawn" && } - {activeOption === "delay" && ( - - )} -
    -
    -
    - -
    +
    +
    + +
    +
    + + {activeOption === "default" && } + {activeOption === "spawn" && ( + + )} + {activeOption === "swap" && ( + + )} + {activeOption === "despawn" && } + {activeOption === "delay" && ( + + )} +
    +
    +
    + +
    + + )} - )} - - ); + ); } export default ConveyorMechanics; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx index fa2cfdf..8d128af 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -2,128 +2,121 @@ import { useEffect, useState } from "react"; import RenameInput from "../../../../../ui/inputs/RenameInput"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import Trigger from "../trigger/Trigger"; -import { - useSelectedEventData, - useSelectedProduct, -} from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import ProcessAction from "../actions/ProcessAction"; import ActionsList from "../components/ActionsList"; function MachineMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "process">( - "default" - ); - const [selectedPointData, setSelectedPointData] = useState< - MachinePointSchema | undefined - >(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState<"default" | "process">("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint - ) as MachinePointSchema | undefined; - if (point && "action" in point) { - setSelectedPointData(point); - setActiveOption(point.action.actionType as "process"); - } - } - }, [selectedProduct, selectedEventData, getPointByUuid]); + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as MachinePointSchema | undefined; + if (point && "action" in point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "process"); + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as "process"; - setActiveOption(validOption); + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "process"; + setActiveOption(validOption); - updateAction(selectedPointData.action.actionUuid, { - actionType: validOption, - }); - }; + updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); + }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { actionName: newName }); - }; + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + }; - const handleProcessTimeChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - processTime: parseFloat(value), - }); - }; + const handleProcessTimeChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + processTime: parseFloat(value), + }); + }; - const handleMaterialSelect = (material: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - swapMaterial: material, - }); - }; + const handleMaterialSelect = (material: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + swapMaterial: material, + }); + }; - // Get current values from store - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + // Get current values from store + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; - const currentProcessTime = selectedPointData - ? selectedPointData.action.processTime.toString() - : "1"; + const currentProcessTime = selectedPointData + ? selectedPointData.action.processTime.toString() + : "1"; - const currentMaterial = selectedPointData - ? selectedPointData.action.swapMaterial - : "Default material"; + const currentMaterial = selectedPointData + ? selectedPointData.action.swapMaterial + : "Default material"; - const availableActions = { - defaultOption: "process", - options: ["process"], - }; + const availableActions = { + defaultOption: "process", + options: ["process"], + }; - return ( - <> - {selectedEventData && ( + return ( <> -
    -
    - -
    - -
    - - {activeOption === "process" && ( - - )} -
    -
    -
    - -
    + {selectedEventData && ( + <> +
    +
    + +
    + +
    + + {activeOption === "process" && ( + + )} +
    +
    +
    + +
    + + )} - )} - - ); + ); } export default MachineMechanics; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx index 7c20ce5..811a676 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -3,192 +3,164 @@ import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; import RenameInput from "../../../../../ui/inputs/RenameInput"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import Trigger from "../trigger/Trigger"; -import { - useSelectedEventData, - useSelectedProduct, - useSelectedAction, -} from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedEventData, useSelectedProduct, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import PickAndPlaceAction from "../actions/PickAndPlaceAction"; import ActionsList from "../components/ActionsList"; function RoboticArmMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">( - "default" - ); - const [selectedPointData, setSelectedPointData] = useState< - RoboticArmPointSchema | undefined - >(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateEvent, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); - const { selectedAction, setSelectedAction, clearSelectedAction } = - useSelectedAction(); + const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateEvent, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData.data.modelUuid, - selectedEventData.selectedPoint - ) as RoboticArmPointSchema | undefined; - if (point?.actions) { - setSelectedPointData(point); - setActiveOption( - point.actions[0].actionType as "default" | "pickAndPlace" - ); - if (point.actions.length > 0 && !selectedAction.actionId) { - setSelectedAction( - point.actions[0].actionUuid, - point.actions[0].actionName - ); + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint + ) as RoboticArmPointSchema | undefined; + if (point?.actions) { + setSelectedPointData(point); + setActiveOption(point.actions[0].actionType as "default" | "pickAndPlace"); + if (point.actions.length > 0 && !selectedAction.actionId) { + setSelectedAction( + point.actions[0].actionUuid, + point.actions[0].actionName + ); + } + } + } else { + clearSelectedAction(); } - } - } else { - clearSelectedAction(); - } - }, [ - clearSelectedAction, - getPointByUuid, - selectedAction.actionId, - selectedEventData, - selectedProduct, - setSelectedAction, - ]); + }, [clearSelectedAction, getPointByUuid, selectedAction.actionId, selectedEventData, selectedProduct, setSelectedAction,]); - const handleRenameAction = (newName: string) => { - if (!selectedAction.actionId) return; - updateAction(selectedAction.actionId, { actionName: newName }); + const handleRenameAction = (newName: string) => { + if (!selectedAction.actionId) return; + updateAction(selectedAction.actionId, { actionName: newName }); - if (selectedPointData) { - const updatedActions = selectedPointData.actions.map((action) => - action.actionUuid === selectedAction.actionId - ? { ...action, actionName: newName } - : action - ); - setSelectedPointData({ - ...selectedPointData, - actions: updatedActions, - }); - } - }; + if (selectedPointData) { + const updatedActions = selectedPointData.actions.map((action) => + action.actionUuid === selectedAction.actionId ? { ...action, actionName: newName } : action + ); + setSelectedPointData({ + ...selectedPointData, + actions: updatedActions, + }); + } + }; - const handleSpeedChange = (value: string) => { - if (!selectedEventData) return; - updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { - speed: parseFloat(value), - }); - }; + const handleSpeedChange = (value: string) => { + if (!selectedEventData) return; + updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, { + speed: parseFloat(value), + }); + }; - const handlePickPointChange = (value: string) => { - if (!selectedAction.actionId || !selectedPointData) return; - const [x, y, z] = value.split(",").map(Number); + const handlePickPointChange = (value: string) => { + if (!selectedAction.actionId || !selectedPointData) return; + const [x, y, z] = value.split(",").map(Number); - updateAction(selectedAction.actionId, { - process: { - startPoint: [x, y, z] as [number, number, number], - endPoint: - selectedPointData.actions.find( - (a) => a.actionUuid === selectedAction.actionId - )?.process.endPoint || null, - }, - }); - }; + updateAction(selectedAction.actionId, { + process: { + startPoint: [x, y, z] as [number, number, number], + endPoint: selectedPointData.actions.find((a) => a.actionUuid === selectedAction.actionId)?.process.endPoint || null, + }, + }); + }; - const handlePlacePointChange = (value: string) => { - if (!selectedAction.actionId || !selectedPointData) return; - const [x, y, z] = value.split(",").map(Number); + const handlePlacePointChange = (value: string) => { + if (!selectedAction.actionId || !selectedPointData) return; + const [x, y, z] = value.split(",").map(Number); - updateAction(selectedAction.actionId, { - process: { - startPoint: - selectedPointData.actions.find( - (a) => a.actionUuid === selectedAction.actionId - )?.process.startPoint || null, - endPoint: [x, y, z] as [number, number, number], - }, - }); - }; + updateAction(selectedAction.actionId, { + process: { + startPoint: selectedPointData.actions.find((a) => a.actionUuid === selectedAction.actionId)?.process.startPoint || null, + endPoint: [x, y, z] as [number, number, number], + }, + }); + }; - const availableActions = { - defaultOption: "pickAndPlace", - options: ["pickAndPlace"], - }; + const availableActions = { + defaultOption: "pickAndPlace", + options: ["pickAndPlace"], + }; - const currentSpeed = - selectedEventData?.data.type === "roboticArm" - ? selectedEventData.data.speed.toString() - : "0.5"; + const currentSpeed = selectedEventData?.data.type === "roboticArm" + ? selectedEventData.data.speed.toString() + : "0.5"; - const currentAction = selectedPointData?.actions.find( - (a) => a.actionUuid === selectedAction.actionId - ); - const currentPickPoint = currentAction?.process.startPoint - ? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}` - : ""; - const currentPlacePoint = currentAction?.process.endPoint - ? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}` - : ""; + const currentAction = selectedPointData?.actions.find((a) => a.actionUuid === selectedAction.actionId); - return ( - <> - {selectedEventData && selectedPointData && ( + const currentPickPoint = currentAction?.process.startPoint + ? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}` + : ""; + const currentPlacePoint = currentAction?.process.endPoint + ? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}` + : ""; + + return ( <> -
    -
    -
    - {}} - onChange={handleSpeedChange} - /> -
    -
    -
    + {selectedEventData && selectedPointData && ( + <> +
    +
    +
    + { }} + onChange={handleSpeedChange} + /> +
    +
    +
    - + - {selectedAction.actionId && currentAction && ( -
    -
    - -
    -
    - {}} - disabled={true} - /> - -
    -
    - -
    -
    - )} + {selectedAction.actionId && currentAction && ( +
    +
    + +
    +
    + { }} + disabled={true} + /> + +
    +
    + +
    +
    + )} + + )} - )} - - ); + ); } export default RoboticArmMechanics; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index d92ed80..b295519 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -2,119 +2,112 @@ import { useEffect, useState } from "react"; import RenameInput from "../../../../../ui/inputs/RenameInput"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import Trigger from "../trigger/Trigger"; -import { - useSelectedEventData, - useSelectedProduct, -} from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import StorageAction from "../actions/StorageAction"; import ActionsList from "../components/ActionsList"; function StorageMechanics() { - const [activeOption, setActiveOption] = useState< - "default" | "store" | "spawn" - >("default"); - const [selectedPointData, setSelectedPointData] = useState< - StoragePointSchema | undefined - >(); - const { selectedEventData } = useSelectedEventData(); - const { getPointByUuid, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default"); + const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); + const { getPointByUuid, updateAction } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); - useEffect(() => { - if (selectedEventData) { - const point = getPointByUuid( - selectedProduct.productId, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint - ) as StoragePointSchema | undefined; - if (point && "action" in point) { - setSelectedPointData(point); - setActiveOption(point.action.actionType as "store" | "spawn"); - } - } - }, [selectedProduct, selectedEventData, getPointByUuid]); + useEffect(() => { + if (selectedEventData) { + const point = getPointByUuid( + selectedProduct.productId, + selectedEventData?.data.modelUuid, + selectedEventData?.selectedPoint + ) as StoragePointSchema | undefined; + if (point && "action" in point) { + setSelectedPointData(point); + setActiveOption(point.action.actionType as "store" | "spawn"); + } + } + }, [selectedProduct, selectedEventData, getPointByUuid]); - const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as "store" | "spawn"; - setActiveOption(validOption); + const handleActionTypeChange = (option: string) => { + if (!selectedEventData || !selectedPointData) return; + const validOption = option as "store" | "spawn"; + setActiveOption(validOption); - updateAction(selectedPointData.action.actionUuid, { - actionType: validOption, - }); - }; + updateAction(selectedPointData.action.actionUuid, { + actionType: validOption, + }); + }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { actionName: newName }); - }; + const handleRenameAction = (newName: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { actionName: newName }); + }; - const handleCapacityChange = (value: string) => { - if (!selectedPointData) return; - updateAction(selectedPointData.action.actionUuid, { - storageCapacity: parseInt(value), - }); - }; + const handleCapacityChange = (value: string) => { + if (!selectedPointData) return; + updateAction(selectedPointData.action.actionUuid, { + storageCapacity: parseInt(value), + }); + }; - // Get current values from store - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; + // Get current values from store + const currentActionName = selectedPointData + ? selectedPointData.action.actionName + : "Action Name"; - const currentCapacity = selectedPointData - ? selectedPointData.action.storageCapacity.toString() - : "0"; + const currentCapacity = selectedPointData + ? selectedPointData.action.storageCapacity.toString() + : "0"; - const availableActions = { - defaultOption: "store", - options: ["store", "spawn"], - }; + const availableActions = { + defaultOption: "store", + options: ["store", "spawn"], + }; - return ( - <> - {selectedEventData && ( + return ( <> - -
    -
    - -
    -
    - - {activeOption === "store" && ( - - )} - {activeOption === "spawn" && ( -
    -

    Spawn configuration options would go here

    -
    - )} -
    -
    -
    - -
    + {selectedEventData && ( + <> + +
    +
    + +
    +
    + + {activeOption === "store" && ( + + )} + {activeOption === "spawn" && ( +
    +

    Spawn configuration options would go here

    +
    + )} +
    +
    +
    + +
    + + )} - )} - - ); + ); } export default StorageMechanics; diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index b037098..ca29087 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -1,216 +1,216 @@ -import React, { useEffect, useRef } from "react"; +import React, { useRef } from "react"; import { - AddIcon, - ArrowIcon, - RemoveIcon, - ResizeHeightIcon, + AddIcon, + ArrowIcon, + RemoveIcon, + ResizeHeightIcon, } from "../../../icons/ExportCommonIcons"; import RenameInput from "../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../functions/handleResizePannel"; import { - useSelectedAsset, - useSelectedProduct, + useSelectedAsset, + useSelectedProduct, } from "../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { generateUUID } from "three/src/math/MathUtils"; import RenderOverlay from "../../../templates/Overlay"; import EditWidgetOption from "../../../ui/menu/EditWidgetOption"; -import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi"; import { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { deleteEventDataApi } from "../../../../services/simulation/deleteEventDataApi"; interface Event { - pathName: string; + pathName: string; } interface ListProps { - val: Event; + val: Event; } const List: React.FC = ({ val }) => { - return ( -
    -
    {val.pathName}
    -
    - ); + return ( +
    +
    {val.pathName}
    +
    + ); }; const Simulations: React.FC = () => { - const productsContainerRef = useRef(null); - const { - products, - addProduct, - removeProduct, - renameProduct, - addEvent, - removeEvent, - } = useProductStore(); - const { selectedProduct, setSelectedProduct } = useSelectedProduct(); - const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); + const productsContainerRef = useRef(null); + const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent, } = useProductStore(); + const { selectedProduct, setSelectedProduct } = useSelectedProduct(); + const { getEventByModelUuid } = useEventsStore(); + const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); - const handleAddProduct = () => { - addProduct(`Product ${products.length + 1}`, generateUUID()); - }; + const handleAddProduct = () => { + addProduct(`Product ${products.length + 1}`, generateUUID()); + }; - const handleRemoveProduct = (productId: string) => { - const currentIndex = products.findIndex((p) => p.productId === productId); - const isSelected = selectedProduct.productId === productId; + const handleRemoveProduct = (productId: string) => { + const currentIndex = products.findIndex((p) => p.productId === productId); + const isSelected = selectedProduct.productId === productId; - const updatedProducts = products.filter((p) => p.productId !== productId); + const updatedProducts = products.filter((p) => p.productId !== productId); - if (isSelected) { - if (updatedProducts.length > 0) { - let newSelectedIndex = currentIndex; - if (currentIndex >= updatedProducts.length) { - newSelectedIndex = updatedProducts.length - 1; + if (isSelected) { + if (updatedProducts.length > 0) { + let newSelectedIndex = currentIndex; + if (currentIndex >= updatedProducts.length) { + newSelectedIndex = updatedProducts.length - 1; + } + setSelectedProduct( + updatedProducts[newSelectedIndex].productId, + updatedProducts[newSelectedIndex].productName + ); + } else { + setSelectedProduct("", ""); + } } - setSelectedProduct( - updatedProducts[newSelectedIndex].productId, - updatedProducts[newSelectedIndex].productName - ); - } else { - setSelectedProduct("", ""); - } - } - removeProduct(productId); - }; + removeProduct(productId); + }; - const handleRenameProduct = (productId: string, newName: string) => { - renameProduct(productId, newName); - if (selectedProduct.productId === productId) { - setSelectedProduct(productId, newName); - } - }; + const handleRenameProduct = (productId: string, newName: string) => { + renameProduct(productId, newName); + if (selectedProduct.productId === productId) { + setSelectedProduct(productId, newName); + } + }; - const handleRemoveEventFromProduct = () => { - if (selectedAsset) { - removeEvent(selectedProduct.productId, selectedAsset.modelUuid); - clearSelectedAsset(); - } - }; + const handleRemoveEventFromProduct = () => { + if (selectedAsset) { + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + deleteEventDataApi({ + productId: selectedProduct.productId, + modelUuid: selectedAsset.modelUuid, + organization: organization + }); + removeEvent(selectedProduct.productId, selectedAsset.modelUuid); + clearSelectedAsset(); + } + }; - const selectedProductData = products.find( - (product) => product.productId === selectedProduct.productId - ); + const selectedProductData = products.find( + (product) => product.productId === selectedProduct.productId + ); - const events: Event[] = - selectedProductData?.eventDatas.map((event) => ({ - pathName: event.modelName, + const events: Event[] = selectedProductData?.eventDatas.map((event) => ({ + pathName: event.modelName, })) || []; - return ( -
    -
    Simulations
    -
    -
    -
    -
    Products
    -
    - Add -
    -
    -
    -
    - {products.map((product, index) => ( -
    -
    - setSelectedProduct(product.productId, product.productName) - } - > - - - handleRenameProduct(product.productId, newName) - } - /> -
    - {products.length > 1 && ( -
    handleRemoveProduct(product.productId)} - > - + return ( +
    +
    Simulations
    +
    +
    +
    +
    Products
    +
    + Add +
    +
    +
    +
    + {products.map((product, index) => ( +
    +
    + setSelectedProduct(product.productId, product.productName) + } + > + + + handleRenameProduct(product.productId, newName) + } + /> +
    + {products.length > 1 && ( +
    handleRemoveProduct(product.productId)} + > + +
    + )} +
    + ))} +
    +
    handleResize(e, productsContainerRef)} + > + +
    - )}
    - ))} -
    -
    handleResize(e, productsContainerRef)} - > - -
    -
    -
    -
    -
    -
    Events
    -
    - +
    +
    +
    Events
    +
    + +
    +
    + {events.map((event, index) => ( + + ))} +
    + +
    +
    + Need to Compare Layout? +
    +
    + Click 'Compare' to review and analyze the layout + differences between them. +
    +
    + +
    +
    -
    - {events.map((event, index) => ( - - ))} -
    -
    -
    - Need to Compare Layout? -
    -
    - Click 'Compare' to review and analyze the layout - differences between them. -
    -
    - -
    + {selectedAsset && ( + + { + if (option === "Add to Product") { + handleAddEventToProduct({ + event: getEventByModelUuid(selectedAsset.modelUuid), + addEvent, + selectedProduct, + clearSelectedAsset + }); + } else { + handleRemoveEventFromProduct(); + } + }} + /> + + )}
    -
    - - {selectedAsset && ( - - { - if (option === "Add to Product") { - handleAddEventToProduct({ - selectedAsset, - addEvent, - selectedProduct, - clearSelectedAsset, - }); - } else { - handleRemoveEventFromProduct(); - } - }} - /> - - )} -
    - ); + ); }; export default Simulations; diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index c46c0e7..f09f130 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -156,7 +156,7 @@ function processLoadedModel( const model = gltf.clone(); model.uuid = item.modeluuid; model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); - model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid }; + model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid, eventData: item.eventData }; model.position.set(...item.position); model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z); @@ -170,256 +170,141 @@ function processLoadedModel( } }); - itemsGroup?.current?.add(model); - setFloorItems((prevItems) => [ - ...(prevItems || []), - { - modeluuid: item.modeluuid, - modelname: item.modelname, - position: item.position, - rotation: item.rotation, - modelfileID: item.modelfileID, - isLocked: item.isLocked, - isVisible: item.isVisible, - }, - ]); + if (item.eventData) { + setFloorItems((prevItems) => [ + ...(prevItems || []), + { + modeluuid: item.modeluuid, + modelname: item.modelname, + position: item.position, + rotation: item.rotation, + modelfileID: item.modelfileID, + isLocked: item.isLocked, + isVisible: item.isVisible, + eventData: item.eventData, + }, + ]); - if (item.modelfileID === "a1ee92554935007b10b3eb05") { - const data = PointsCalculator( - 'Vehicle', - gltf.clone(), - new THREE.Vector3(...model.rotation) - ); - - if (!data || !data.points) return; - - const vehicleEvent: VehicleEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - state: "idle", - type: "vehicle", - speed: 1, - point: { - uuid: THREE.MathUtils.generateUUID(), - position: [data.points[0].x, data.points[0].y, data.points[0].z], - rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Vehicle Action", - actionType: "travel", - unLoadDuration: 5, - loadCapacity: 10, - pickUpPoint: null, - unLoadPoint: null, - triggers: [] - } - } - }; - addEvent(vehicleEvent); - } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { - const data = PointsCalculator( - 'Conveyor', - gltf.clone(), - new THREE.Vector3(...model.rotation) - ); - - if (!data || !data.points) return; - - const ConveyorEvent: ConveyorEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - state: "idle", - type: "transfer", - speed: 1, - points: data.points.map((point: THREE.Vector3, index: number) => ({ - uuid: THREE.MathUtils.generateUUID(), - position: [point.x, point.y, point.z], - rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: `Action ${index + 1}`, - actionType: 'default', - material: 'Default material', - delay: 0, - spawnInterval: 5, - spawnCount: 1, - triggers: [] - } - })) - }; - addEvent(ConveyorEvent); - } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { - // const data = PointsCalculator( - // 'Conveyor', - // gltf.clone(), - // new THREE.Vector3(...model.rotation) - // ); - - // if (!data || !data.points) return; - - // const points: ConveyorPointSchema[] = data.points.map((point: THREE.Vector3, index: number) => { - // const actionUuid = THREE.MathUtils.generateUUID(); - // return { - // uuid: THREE.MathUtils.generateUUID(), - // position: [point.x, point.y, point.z], - // rotation: [0, 0, 0], - // action: { - // actionUuid, - // actionName: `Action ${index}`, - // actionType: 'default', - // material: 'inherit', - // delay: 0, - // spawnInterval: 5, - // spawnCount: 1, - // triggers: [] - // } - // }; - // }); - - // points.forEach((point, index) => { - // if (index < points.length - 1) { - // const nextPoint = points[index + 1]; - // point.action.triggers.push({ - // triggerUuid: THREE.MathUtils.generateUUID(), - // triggerName: `Trigger 1`, - // triggerType: "onComplete", - // delay: 0, - // triggeredAsset: { - // triggeredModel: { - // modelName: item.modelname, - // modelUuid: item.modeluuid - // }, - // triggeredPoint: { - // pointName: `Point ${index + 1}`, - // pointUuid: nextPoint.uuid - // }, - // triggeredAction: { - // actionName: nextPoint.action.actionName, - // actionUuid: nextPoint.action.actionUuid - // } - // } - // }); - // } - // }); - - // const ConveyorEvent: ConveyorEventSchema = { - // modelUuid: item.modeluuid, - // modelName: item.modelname, - // position: item.position, - // rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - // state: "idle", - // type: "transfer", - // speed: 1, - // points - // }; - // addEvent(ConveyorEvent); - } else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") { - const data = PointsCalculator( - 'Conveyor', - gltf.clone(), - new THREE.Vector3(...model.rotation) - ); - - if (!data || !data.points) return; - - const ConveyorEvent: ConveyorEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - state: "idle", - type: "transfer", - speed: 1, - points: data.points.map((point: THREE.Vector3, index: number) => ({ - uuid: THREE.MathUtils.generateUUID(), - position: [point.x, point.y, point.z], - rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: `Action ${index}`, - actionType: 'default', - material: 'inherit', - delay: 0, - spawnInterval: 5, - spawnCount: 1, - triggers: [] - } - })) - }; - addEvent(ConveyorEvent); - } else if (item.modelfileID === "29dee78715ad5b853f5c346d") { - const data = PointsCalculator( - 'StaticMachine', - gltf.clone(), - new THREE.Vector3(...model.rotation) - ); - - if (!data || !data.points) return; - - const machineEvent: MachineEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - state: "idle", - type: "machine", - point: { - uuid: THREE.MathUtils.generateUUID(), - position: [data.points[0].x, data.points[0].y, data.points[0].z], - rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Process Action", - actionType: "process", - processTime: 10, - swapMaterial: "material-id", - triggers: [] - } - } - }; - addEvent(machineEvent); - } else if (item.modelfileID === "52e6681fbb743a890d96c914") { - const data = PointsCalculator( - 'ArmBot', - gltf.clone(), - new THREE.Vector3(...model.rotation) - ); - - if (!data || !data.points) return; - - const roboticArmEvent: RoboticArmEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, - position: item.position, - rotation: [item.rotation.x, item.rotation.y, item.rotation.z], - state: "idle", - type: "roboticArm", - speed: 1, - point: { - uuid: THREE.MathUtils.generateUUID(), - position: [data.points[0].x, data.points[0].y, data.points[0].z], - rotation: [0, 0, 0], - actions: [ - { + if (item.eventData.type === "vehicle") { + const vehicleEvent: VehicleEventSchema = { + modelUuid: item.modeluuid, + modelName: item.modelname, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "vehicle", + speed: 1, + point: { + uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), + position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], + rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], + action: { actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Pick and Place", - actionType: "pickAndPlace", - process: { - startPoint: [0, 0, 0], - endPoint: [0, 0, 0] - }, + actionName: "Vehicle Action", + actionType: "travel", + unLoadDuration: 5, + loadCapacity: 10, + pickUpPoint: null, + unLoadPoint: null, triggers: [] } - ] - } - }; - addEvent(roboticArmEvent); + } + }; + addEvent(vehicleEvent); + } else if (item.eventData.type === "Conveyor") { + const ConveyorEvent: ConveyorEventSchema = { + modelUuid: item.modeluuid, + modelName: item.modelname, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "transfer", + speed: 1, + points: item.eventData.points?.map((point: any, index: number) => ({ + uuid: point.uuid || THREE.MathUtils.generateUUID(), + position: [point.position[0], point.position[1], point.position[2]], + rotation: [point.rotation[0], point.rotation[1], point.rotation[2]], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${index + 1}`, + actionType: 'default', + material: 'Default material', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: [] + } + })) || [], + }; + addEvent(ConveyorEvent); + } else if (item.eventData.type === "StaticMachine") { + const machineEvent: MachineEventSchema = { + modelUuid: item.modeluuid, + modelName: item.modelname, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "machine", + point: { + uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), + position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], + rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Process Action", + actionType: "process", + processTime: 10, + swapMaterial: "material-id", + triggers: [] + } + } + }; + addEvent(machineEvent); + } else if (item.eventData.type === "ArmBot") { + const roboticArmEvent: RoboticArmEventSchema = { + modelUuid: item.modeluuid, + modelName: item.modelname, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + state: "idle", + type: "roboticArm", + speed: 1, + point: { + uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), + position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], + rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Pick and Place", + actionType: "pickAndPlace", + process: { + startPoint: [0, 0, 0], + endPoint: [0, 0, 0] + }, + triggers: [] + } + ] + } + }; + addEvent(roboticArmEvent); + + } + } else { + setFloorItems((prevItems) => [ + ...(prevItems || []), + { + modeluuid: item.modeluuid, + modelname: item.modelname, + position: item.position, + rotation: item.rotation, + modelfileID: item.modelfileID, + isLocked: item.isLocked, + isVisible: item.isVisible, + }, + ]); } gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' }); diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index d7c278c..ab9d90d 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -164,18 +164,6 @@ async function handleModelLoad( // SOCKET - const data = { - organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, - modelfileID: newFloorItem.modelfileID, - position: newFloorItem.position, - rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, - isLocked: false, - isVisible: true, - socketId: socket.id - }; - if (selectedItem.type) { const data = PointsCalculator( selectedItem.type, @@ -185,6 +173,10 @@ async function handleModelLoad( if (!data || !data.points) return; + const eventData: any = { + type: selectedItem.type, + }; + if (selectedItem.type === "Conveyor") { const ConveyorEvent: ConveyorEventSchema = { modelUuid: newFloorItem.modeluuid, @@ -209,8 +201,14 @@ async function handleModelLoad( triggers: [] } })) - } + }; addEvent(ConveyorEvent); + eventData.points = ConveyorEvent.points.map(point => ({ + uuid: point.uuid, + position: point.position, + rotation: point.rotation + })); + } else if (selectedItem.type === "Vehicle") { const vehicleEvent: VehicleEventSchema = { modelUuid: newFloorItem.modeluuid, @@ -237,6 +235,12 @@ async function handleModelLoad( } }; addEvent(vehicleEvent); + eventData.point = { + uuid: vehicleEvent.point.uuid, + position: vehicleEvent.point.position, + rotation: vehicleEvent.point.rotation + }; + } else if (selectedItem.type === "ArmBot") { const roboticArmEvent: RoboticArmEventSchema = { modelUuid: newFloorItem.modeluuid, @@ -265,6 +269,13 @@ async function handleModelLoad( } }; addEvent(roboticArmEvent); + console.log('roboticArmEvent: ', roboticArmEvent); + eventData.point = { + uuid: roboticArmEvent.point.uuid, + position: roboticArmEvent.point.position, + rotation: roboticArmEvent.point.rotation + }; + } else if (selectedItem.type === "StaticMachine") { const machineEvent: MachineEventSchema = { modelUuid: newFloorItem.modeluuid, @@ -288,19 +299,65 @@ async function handleModelLoad( } }; addEvent(machineEvent); + eventData.point = { + uuid: machineEvent.point.uuid, + position: machineEvent.point.position, + rotation: machineEvent.point.rotation + }; } + + const completeData = { + organization, + modeluuid: newFloorItem.modeluuid, + modelname: newFloorItem.modelname, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id, + eventData: eventData + }; + + model.userData.eventData = eventData; + + newFloorItem.eventData = eventData; + + setFloorItems((prevItems) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + socket.emit("v2:model-asset:add", completeData); + + gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); + gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } }); + } else { + + const data = { + organization, + modeluuid: newFloorItem.modeluuid, + modelname: newFloorItem.modelname, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id + }; + + setFloorItems((prevItems) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); + + socket.emit("v2:model-asset:add", data); + + gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); + gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } }); } - - setFloorItems((prevItems) => { - const updatedItems = [...(prevItems || []), newFloorItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; - }); - - socket.emit("v2:model-asset:add", data); - - gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); - gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } }); } export default addAssetModel; diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index f3f5050..f1da0a4 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -65,6 +65,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject }; getFloorAssets(organization).then((data) => { + console.log('data: ', data); if (data.length > 0) { const uniqueItems = (data as Types.FloorItems).filter((item, index, self) => index === self.findIndex((t) => t.modelfileID === item.modelfileID)); totalAssets = uniqueItems.length; diff --git a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx index 9ca4dd0..c92c98f 100644 --- a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx @@ -137,6 +137,38 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas if (itemsGroupRef.current) { + let updatedEventData = null; + if (obj.userData.eventData) { + updatedEventData = JSON.parse(JSON.stringify(obj.userData.eventData)); + + updatedEventData.modelUuid = THREE.MathUtils.generateUUID(); + + if (updatedEventData.type === "Conveyor" && updatedEventData.points) { + updatedEventData.points = updatedEventData.points.map((point: any) => ({ + ...point, + uuid: THREE.MathUtils.generateUUID() + })); + } + else if (updatedEventData.type === "Vehicle" && updatedEventData.point) { + updatedEventData.point = { + ...updatedEventData.point, + uuid: THREE.MathUtils.generateUUID() + }; + } + else if (updatedEventData.type === "ArmBot" && updatedEventData.point) { + updatedEventData.point = { + ...updatedEventData.point, + uuid: THREE.MathUtils.generateUUID() + }; + } + else if (updatedEventData.type === "StaticMachine" && updatedEventData.point) { + updatedEventData.point = { + ...updatedEventData.point, + uuid: THREE.MathUtils.generateUUID() + }; + } + } + const newFloorItem: Types.FloorItemType = { modeluuid: obj.uuid, modelname: obj.userData.name, @@ -144,7 +176,8 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, isLocked: false, - isVisible: true + isVisible: true, + eventData: updatedEventData }; setFloorItems((prevItems: Types.FloorItems) => { @@ -181,11 +214,18 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas isLocked: false, isVisible: true, socketId: socket.id, + eventData: updatedEventData }; socket.emit("v2:model-asset:add", data); - obj.userData.modeluuid = newFloorItem.modeluuid; + obj.userData = { + name: newFloorItem.modelname, + modelId: newFloorItem.modelfileID, + modeluuid: newFloorItem.modeluuid, + eventData: updatedEventData + }; + itemsGroupRef.current.add(obj); } }); @@ -205,7 +245,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas setSelectedAssets([]); } - return null; // No visible output, but the component handles copy-paste functionality + return null; }; export default CopyPasteControls; \ No newline at end of file diff --git a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx index 39c3e49..c1f4a74 100644 --- a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx @@ -115,6 +115,38 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb if (itemsGroupRef.current) { + let updatedEventData = null; + if (obj.userData.eventData) { + updatedEventData = JSON.parse(JSON.stringify(obj.userData.eventData)); + + updatedEventData.modelUuid = THREE.MathUtils.generateUUID(); + + if (updatedEventData.type === "Conveyor" && updatedEventData.points) { + updatedEventData.points = updatedEventData.points.map((point: any) => ({ + ...point, + uuid: THREE.MathUtils.generateUUID() + })); + } + else if (updatedEventData.type === "Vehicle" && updatedEventData.point) { + updatedEventData.point = { + ...updatedEventData.point, + uuid: THREE.MathUtils.generateUUID() + }; + } + else if (updatedEventData.type === "ArmBot" && updatedEventData.point) { + updatedEventData.point = { + ...updatedEventData.point, + uuid: THREE.MathUtils.generateUUID() + }; + } + else if (updatedEventData.type === "StaticMachine" && updatedEventData.point) { + updatedEventData.point = { + ...updatedEventData.point, + uuid: THREE.MathUtils.generateUUID() + }; + } + } + const newFloorItem: Types.FloorItemType = { modeluuid: obj.uuid, modelname: obj.userData.name, @@ -122,7 +154,8 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, isLocked: false, - isVisible: true + isVisible: true, + eventData: updatedEventData }; setFloorItems((prevItems: Types.FloorItems) => { @@ -159,11 +192,18 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb isLocked: false, isVisible: true, socketId: socket.id, + eventData: updatedEventData }; socket.emit("v2:model-asset:add", data); - obj.userData.modeluuid = newFloorItem.modeluuid; + obj.userData = { + name: newFloorItem.modelname, + modelId: newFloorItem.modelfileID, + modeluuid: newFloorItem.modeluuid, + eventData: updatedEventData + }; + itemsGroupRef.current.add(obj); } }); @@ -183,7 +223,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb setSelectedAssets([]); } - return null; // This component does not render any UI + return null; }; export default DuplicationControls; \ No newline at end of file diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index 2cde3e4..f422d6e 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -1,11 +1,14 @@ import * as THREE from "three"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useEffect, useMemo, useRef } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import { toast } from "react-toastify"; import * as Types from "../../../../types/world/worldTypes"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { useProductStore } from "../../../../store/simulation/useProductStore"; +import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) { const { camera, controls, gl, scene, pointer, raycaster } = useThree(); @@ -176,6 +179,24 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje isVisible: true }; + if (obj.userData.eventData) { + const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modeluuid); + const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modeluuid); + + if (eventData) { + useEventsStore.getState().updateEvent(obj.userData.modeluuid, { + position: [worldPosition.x, worldPosition.y, worldPosition.z], + rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], + }) + } + if (productData) { + useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modeluuid, { + position: [worldPosition.x, worldPosition.y, worldPosition.z], + rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], + }) + } + } + setFloorItems((prevItems: Types.FloorItems) => { const updatedItems = [...(prevItems || []), newFloorItem]; localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); @@ -234,7 +255,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje setSelectedAssets([]); } - return null; // No need to return anything, as this component is used for its side effects + return null; } export default MoveControls \ No newline at end of file diff --git a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx index 5dfaf08..cf66772 100644 --- a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx @@ -1,11 +1,13 @@ import * as THREE from "three"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useEffect, useMemo, useRef } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import { toast } from "react-toastify"; import * as Types from "../../../../types/world/worldTypes"; -import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { useProductStore } from "../../../../store/simulation/useProductStore"; +import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) { const { camera, controls, gl, scene, pointer, raycaster } = useThree(); @@ -177,6 +179,24 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo isVisible: true }; + if (obj.userData.eventData) { + const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modeluuid); + const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modeluuid); + + if (eventData) { + useEventsStore.getState().updateEvent(obj.userData.modeluuid, { + position: [worldPosition.x, worldPosition.y, worldPosition.z], + rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], + }) + } + if (productData) { + useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modeluuid, { + position: [worldPosition.x, worldPosition.y, worldPosition.z], + rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], + }) + } + } + setFloorItems((prevItems: Types.FloorItems) => { const updatedItems = [...(prevItems || []), newFloorItem]; localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); @@ -235,7 +255,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo setSelectedAssets([]); } - return null; // No need to return anything, as this component is used for its side effects + return null; } export default RotateControls \ No newline at end of file diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index c5025dd..8e476d0 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -62,7 +62,7 @@ function PointsCreator() { {events.map((event, i) => { if (event.type === 'transfer') { return ( - + {event.points.map((point, j) => ( @@ -88,7 +89,7 @@ function PointsCreator() { ); } else if (event.type === 'vehicle') { return ( - + @@ -111,7 +113,7 @@ function PointsCreator() { ); } else if (event.type === 'roboticArm') { return ( - + @@ -134,7 +137,7 @@ function PointsCreator() { ); } else if (event.type === 'machine') { return ( - + diff --git a/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts b/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts index 7943c1c..9928578 100644 --- a/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts +++ b/app/src/modules/simulation/events/points/functions/handleAddEventToProduct.ts @@ -1,28 +1,38 @@ +import { upsertProductOrEventApi } from "../../../../../services/simulation/UpsertProductOrEventApi"; + interface HandleAddEventToProductParams { - selectedAsset: any; // Replace `any` with specific type if you have it - addEvent: (productId: string, asset: any) => void; + event: EventsSchema | undefined; + addEvent: (productId: string, event: EventsSchema) => void; selectedProduct: { productId: string; productName: string; - // Add other fields if needed - }; - clearSelectedAsset: () => void; + } + clearSelectedAsset?: () => void; } export const handleAddEventToProduct = ({ - selectedAsset, + event, addEvent, selectedProduct, - clearSelectedAsset, + clearSelectedAsset }: HandleAddEventToProductParams) => { - console.log('selectedProduct: ', selectedProduct); - if (selectedAsset) { - addEvent(selectedProduct.productId, selectedAsset); - // upsertProductOrEventApi({ - // productName: selectedProduct.productName, - // productId: selectedProduct.productId, - // eventDatas: selectedAsset - // }); - clearSelectedAsset(); + if (event && selectedProduct.productId) { + addEvent(selectedProduct.productId, event); + + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + upsertProductOrEventApi({ + productName: selectedProduct.productName, + productId: selectedProduct.productId, + organization: organization, + eventDatas: event + }).then((data) => { + // console.log(data); + }) + + if (clearSelectedAsset) { + clearSelectedAsset(); + } } }; diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index 38175e2..ee1ac42 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -7,28 +7,27 @@ import { upsertProductOrEventApi } from '../../../services/simulation/UpsertProd import { getAllProductsApi } from '../../../services/simulation/getallProductsApi'; function Products() { - const { products, addProduct } = useProductStore(); + const { products, addProduct, setProducts } = useProductStore(); const { setSelectedProduct } = useSelectedProduct(); useEffect(() => { - if (products.length === 0) { - const id = THREE.MathUtils.generateUUID(); - const name = 'Product 1'; - addProduct(name, id); - // upsertProductOrEventApi({ productName: name, productId: id }).then((data) => { - // console.log('data: ', data); - // }); - setSelectedProduct(id, name); - } - }, [products]) + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + getAllProductsApi(organization).then((data) => { + if (data.length === 0) { + const id = THREE.MathUtils.generateUUID(); + const name = 'Product 1'; + addProduct(name, id); + upsertProductOrEventApi({ productName: name, productId: id, organization: organization }) + setSelectedProduct(id, name); + } else { + setProducts(data); + setSelectedProduct(data[0].productId, data[0].productName); + } + }) + }, []) useEffect(() => { - // const email = localStorage.getItem('email') - // const organization = (email!.split("@")[1]).split(".")[0]; - // console.log(organization); - // getAllProductsApi(organization).then((data) => { - // console.log('data: ', data); - // }) }, []) return ( diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 5ca0ec5..f2d208d 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -19,11 +19,11 @@ function Simulation() { const { products } = useProductStore(); useEffect(() => { - // console.log('events: ', events); + console.log('events: ', events); }, [events]) useEffect(() => { - // console.log('products: ', products); + console.log('products: ', products); }, [products]) return ( diff --git a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx index f836ea4..efefa0c 100644 --- a/app/src/modules/simulation/triggers/connector/triggerConnector.tsx +++ b/app/src/modules/simulation/triggers/connector/triggerConnector.tsx @@ -1,19 +1,85 @@ -import { useEffect } from "react"; +import { useEffect, useRef, useState } from "react"; import { useThree } from "@react-three/fiber"; +import * as THREE from "three"; import { useSubModuleStore } from "../../../../store/useModuleStore"; import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; +import { handleAddEventToProduct } from "../../events/points/functions/handleAddEventToProduct"; + +interface ConnectionLine { + id: string; + start: THREE.Vector3; + end: THREE.Vector3; + mid: THREE.Vector3; + trigger: TriggerSchema; +} function TriggerConnector() { const { gl, raycaster, scene } = useThree(); const { subModule } = useSubModuleStore(); - const { getPointByUuid, getIsEventInProduct } = useProductStore(); + const { products, getPointByUuid, getIsEventInProduct, getActionByUuid, addTrigger, addEvent, getEventByModelUuid } = useProductStore(); const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); const { selectedProduct } = useSelectedProduct(); - useEffect(() => { + const [firstSelectedPoint, setFirstSelectedPoint] = useState<{ + productId: string; + modelUuid: string; + pointUuid: string; + actionUuid?: string; + } | null>(null); + const [connections, setConnections] = useState([]); + + useEffect(() => { + const newConnections: ConnectionLine[] = []; + + products.forEach(product => { + product.eventDatas.forEach(event => { + if ('points' in event) { + event.points.forEach(point => { + if ('action' in point && point.action?.triggers) { + point.action.triggers.forEach(trigger => { + if (trigger.triggeredAsset) { + const targetPoint = getPointByUuid( + product.productId, + trigger.triggeredAsset.triggeredModel.modelUuid, + trigger.triggeredAsset.triggeredPoint.pointUuid + ); + + if (targetPoint) { + const startPos = new THREE.Vector3(...point.position); + const endPos = new THREE.Vector3(...targetPoint.position); + const midPos = new THREE.Vector3() + .addVectors(startPos, endPos) + .multiplyScalar(0.5) + .add(new THREE.Vector3(0, 2, 0)); + + newConnections.push({ + id: `${point.uuid}-${targetPoint.uuid}-${trigger.triggerUuid}`, + start: startPos, + end: endPos, + mid: midPos, + trigger + }); + } + } + }); + } + }); + } + }); + }); + + setConnections(newConnections); + }, [products]); + + useEffect(() => { + console.log('connections: ', connections); + }, connections) + + useEffect(() => { const canvasElement = gl.domElement; let drag = false; @@ -44,37 +110,114 @@ function TriggerConnector() { const handleRightClick = (evt: MouseEvent) => { if (drag) return; evt.preventDefault(); - const canvasElement = gl.domElement; - if (!canvasElement) return; - let intersects = raycaster.intersectObjects(scene.children, true); - if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) { - let currentObject = intersects[0].object; + const intersects = raycaster.intersectObjects(scene.children, true); + if (intersects.length === 0) return; - if (currentObject && currentObject.name === 'Event-Sphere') { + const currentObject = intersects[0].object; + if (!currentObject || currentObject.name !== 'Event-Sphere') return; - const isInProduct = getIsEventInProduct( - selectedProduct.productId, - currentObject.userData.modelUuid - ); + const modelUuid = currentObject.userData.modelUuid; + const pointUuid = currentObject.userData.pointUuid; - // You left Here + if (selectedProduct && getIsEventInProduct(selectedProduct.productId, modelUuid)) { - if (isInProduct) { + const point = getPointByUuid( + selectedProduct.productId, + modelUuid, + pointUuid + ); - const event = getPointByUuid( - selectedProduct.productId, - currentObject.userData.modelUuid, - currentObject.userData.pointUuid - ); - console.log('event: ', event); - } else { + if (!point) return; - } + let actionUuid: string | undefined; + if ('action' in point && point.action) { + actionUuid = point.action.actionUuid; + } else if ('actions' in point && point.actions.length === 1) { + actionUuid = point.actions[0].actionUuid; } - } else { + if (!firstSelectedPoint) { + setFirstSelectedPoint({ + productId: selectedProduct.productId, + modelUuid, + pointUuid, + actionUuid + }); + } else { + const trigger: TriggerSchema = { + triggerUuid: THREE.MathUtils.generateUUID(), + triggerName: `Trigger ${firstSelectedPoint.pointUuid.slice(0, 4)} → ${pointUuid.slice(0, 4)}`, + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: currentObject.parent?.parent?.name || 'Unknown', + modelUuid: modelUuid + }, + triggeredPoint: { + pointName: currentObject.name, + pointUuid: pointUuid + }, + triggeredAction: actionUuid ? { + actionName: getActionByUuid(selectedProduct.productId, actionUuid)?.actionName || 'Action', + actionUuid: actionUuid + } : null + } + }; + if (firstSelectedPoint.actionUuid) { + addTrigger(firstSelectedPoint.actionUuid, trigger); + } + setFirstSelectedPoint(null); + } + } else if (!getIsEventInProduct(selectedProduct.productId, modelUuid) && firstSelectedPoint) { + handleAddEventToProduct({ + event: useEventsStore.getState().getEventByModelUuid(modelUuid), + addEvent, + selectedProduct, + }) + + const point = getPointByUuid( + selectedProduct.productId, + modelUuid, + pointUuid + ); + + if (!point) return; + + let actionUuid: string | undefined; + if ('action' in point && point.action) { + actionUuid = point.action.actionUuid; + } else if ('actions' in point && point.actions.length === 1) { + actionUuid = point.actions[0].actionUuid; + } + + const trigger: TriggerSchema = { + triggerUuid: THREE.MathUtils.generateUUID(), + triggerName: `Trigger ${firstSelectedPoint.pointUuid.slice(0, 4)} → ${pointUuid.slice(0, 4)}`, + triggerType: "onComplete", + delay: 0, + triggeredAsset: { + triggeredModel: { + modelName: currentObject.parent?.parent?.name || 'Unknown', + modelUuid: modelUuid + }, + triggeredPoint: { + pointName: currentObject.name, + pointUuid: pointUuid + }, + triggeredAction: actionUuid ? { + actionName: getActionByUuid(selectedProduct.productId, actionUuid)?.actionName || 'Action', + actionUuid: actionUuid + } : null + } + }; + + if (firstSelectedPoint.actionUuid) { + addTrigger(firstSelectedPoint.actionUuid, trigger); + } + setFirstSelectedPoint(null); } }; @@ -92,12 +235,12 @@ function TriggerConnector() { canvasElement.removeEventListener('contextmenu', handleRightClick); }; - }, [gl, subModule]); + }, [gl, subModule, selectedProduct, firstSelectedPoint]); return ( <> - ) + ); } -export default TriggerConnector \ No newline at end of file +export default TriggerConnector; \ No newline at end of file diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index 8ec74cf..de02551 100644 --- a/app/src/store/simulation/useProductStore.ts +++ b/app/src/store/simulation/useProductStore.ts @@ -6,6 +6,7 @@ type ProductsStore = { // Product-level actions addProduct: (productName: string, productId: string) => void; + setProducts: (products: productsSchema) => void; removeProduct: (productId: string) => void; updateProduct: (productId: string, updates: Partial<{ productName: string; eventDatas: EventsSchema[] }>) => void; @@ -78,6 +79,12 @@ export const useProductStore = create()( }); }, + setProducts: (products) => { + set((state) => { + state.products = products; + }); + }, + removeProduct: (productId) => { set((state) => { state.products = state.products.filter(p => p.productId !== productId); diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 811812d..46093d6 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -14,7 +14,7 @@ interface TriggerSchema { triggeredAsset: { triggeredModel: { modelName: string, modelUuid: string }; triggeredPoint: { pointName: string, pointUuid: string }; - triggeredAction: { actionName: string, actionUuid: string }; + triggeredAction: { actionName: string, actionUuid: string } | null; } | null; } diff --git a/app/src/types/world/worldTypes.d.ts b/app/src/types/world/worldTypes.d.ts index fa6c129..20c44da 100644 --- a/app/src/types/world/worldTypes.d.ts +++ b/app/src/types/world/worldTypes.d.ts @@ -196,6 +196,19 @@ export type FloorItemType = { modelfileID: string; isLocked: boolean; isVisible: boolean; + eventData?: { + type: string; + point?: { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; + } + points?: { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; + }[]; + } }; // Array of floor items for managing multiple objects on the floor diff --git a/app/src/utils/indexDB/idbUtils.ts b/app/src/utils/indexDB/idbUtils.ts index c9228d3..24b1448 100644 --- a/app/src/utils/indexDB/idbUtils.ts +++ b/app/src/utils/indexDB/idbUtils.ts @@ -3,43 +3,43 @@ const STORE_NAME = 'models'; const DB_VERSION = 1; export function initializeDB(): Promise { - return new Promise((resolve, reject) => { - const request = indexedDB.open(DB_NAME, DB_VERSION); + return new Promise((resolve, reject) => { + const request = indexedDB.open(DB_NAME, DB_VERSION); - request.onupgradeneeded = () => { - const db = request.result; - if (!db.objectStoreNames.contains(STORE_NAME)) { - db.createObjectStore(STORE_NAME); - } - }; + request.onupgradeneeded = () => { + const db = request.result; + if (!db.objectStoreNames.contains(STORE_NAME)) { + db.createObjectStore(STORE_NAME); + } + }; - request.onsuccess = () => resolve(request.result); - request.onerror = () => reject(request.error); - }); + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }); } export async function storeGLTF(key: string, file: Blob): Promise { - const db = await initializeDB(); + const db = await initializeDB(); - return new Promise((resolve, reject) => { - const transaction = db.transaction(STORE_NAME, 'readwrite'); - const store = transaction.objectStore(STORE_NAME); - const request = store.put(file, key); + return new Promise((resolve, reject) => { + const transaction = db.transaction(STORE_NAME, 'readwrite'); + const store = transaction.objectStore(STORE_NAME); + const request = store.put(file, key); - request.onsuccess = () => resolve(); - request.onerror = () => reject(request.error); - }); + request.onsuccess = () => resolve(); + request.onerror = () => reject(request.error); + }); } export async function retrieveGLTF(key: string): Promise { - const db = await initializeDB(); + const db = await initializeDB(); - return new Promise((resolve, reject) => { - const transaction = db.transaction(STORE_NAME, 'readonly'); - const store = transaction.objectStore(STORE_NAME); - const request = store.get(key); + return new Promise((resolve, reject) => { + const transaction = db.transaction(STORE_NAME, 'readonly'); + const store = transaction.objectStore(STORE_NAME); + const request = store.get(key); - request.onsuccess = () => resolve(request.result as Blob | undefined); - request.onerror = () => reject(request.error); - }); + request.onsuccess = () => resolve(request.result as Blob | undefined); + request.onerror = () => reject(request.error); + }); } \ No newline at end of file From 4b87650528633d089a260d53fe73ea27c4a1f755 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Wed, 30 Apr 2025 11:32:13 +0530 Subject: [PATCH 27/30] added ui and its functionality for changing position of vehicles pickup-point and unloadPoint --- .../simulation/ui/vehicle/vehicleUI.tsx | 45 ++++++++++++------- .../instances/animator/vehicleAnimator.tsx | 13 +++--- .../instances/instance/vehicleInstance.tsx | 6 +-- .../modules/simulation/vehicle/vehicles.tsx | 3 +- 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx index b498431..5dec724 100644 --- a/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx +++ b/app/src/modules/simulation/ui/vehicle/vehicleUI.tsx @@ -46,18 +46,17 @@ const VehicleUI = () => { pickUpPoint.rotation.y, pickUpPoint.rotation.z ); - pickupPosition.y = 0; // Force y to 0 + pickupPosition.y = 0; setStartPosition([pickupPosition.x, 0, pickupPosition.z]); setStartRotation([pickupRotation.x, pickupRotation.y, pickupRotation.z]); } else { const defaultLocal = new THREE.Vector3(0, 0, 1.5); const defaultWorld = selectedEventSphere.localToWorld(defaultLocal); - defaultWorld.y = 0; // Force y to 0 + defaultWorld.y = 0; setStartPosition([defaultWorld.x, 0, defaultWorld.z]); setStartRotation([0, 0, 0]); } - // Initialize end marker position and rotation if (unLoadPoint) { const unLoadPosition = new THREE.Vector3( unLoadPoint.position.x, @@ -109,8 +108,13 @@ const VehicleUI = () => { if (marker) { const rotationSpeed = 10; - marker.rotation.y -= deltaX * rotationSpeed; + marker.rotation.y += deltaX * rotationSpeed; + if (isRotating === 'start') { + setStartRotation([marker.rotation.x, marker.rotation.y, marker.rotation.z]) + } else { + setEndRotation([marker.rotation.x, marker.rotation.y, marker.rotation.z]) + } } }); @@ -133,7 +137,6 @@ const VehicleUI = () => { }; const handlePointerUp = () => { - console.log("nulll"); controls.enabled = true; setIsDragging(null); setIsRotating(null); @@ -180,7 +183,22 @@ const VehicleUI = () => { } }; + useEffect(() => { + const handleGlobalPointerUp = () => { + setIsDragging(null); + setIsRotating(null); + if (controls) controls.enabled = true; + handlePointerUp(); + }; + if (isDragging || isRotating) { + window.addEventListener("pointerup", handleGlobalPointerUp); + } + + return () => { + window.removeEventListener("pointerup", handleGlobalPointerUp); + }; + }, [isDragging, isRotating, startPosition, startRotation, endPosition, endRotation]); return ( startPosition.length > 0 && endPosition.length > 0 ? ( @@ -194,12 +212,10 @@ const VehicleUI = () => { e.stopPropagation(); handlePointerDown(e, "start", "start"); }} - onPointerUp={() => { - handlePointerUp(); - }} onPointerMissed={() => { - console.log("start pointermissed"); - handlePointerUp(); + controls.enabled = true; + setIsDragging(null); + setIsRotating(null); }} /> @@ -212,13 +228,10 @@ const VehicleUI = () => { e.stopPropagation(); handlePointerDown(e, "end", "end"); }} - onPointerUp={() => { - console.log("up"); - handlePointerUp(); - }} onPointerMissed={() => { - console.log("end pointermissed"); - handlePointerUp(); + controls.enabled = true; + setIsDragging(null); + setIsRotating(null); }} /> diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index d232734..2f0b235 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -32,14 +32,18 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai let startTime: number; let fixedInterval: number; let coveredDistance = progressRef.current; + let objectRotation = (agvDetail.point?.action?.pickUpPoint?.rotation || { x: 0, y: 0, z: 0 }) as { x: number; y: number; z: number }; useEffect(() => { if (currentPhase === 'stationed-pickup' && path.length > 0) { setCurrentPath(path); + objectRotation = agvDetail.point.action?.pickUpPoint?.rotation } else if (currentPhase === 'pickup-drop' && path.length > 0) { + objectRotation = agvDetail.point.action?.unLoadPoint?.rotation setCurrentPath(path); } else if (currentPhase === 'drop-pickup' && path.length > 0) { + objectRotation = agvDetail.point.action?.pickUpPoint?.rotation setCurrentPath(path); } }, [currentPhase, path]); @@ -63,10 +67,10 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai setRestingRotation(true); decrementVehicleLoad(agvDetail.modelUuid, 0); const object = scene.getObjectByProperty('uuid', agvUuid); + console.log('currentPhase: ', currentPhase); if (object) { object.position.set(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]); - let objectRotation = agvDetail.point.rotation - object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + object.rotation.set(objectRotation.x, objectRotation.y, objectRotation.z); } } }, [isReset, isPlaying]) @@ -129,12 +133,11 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai if (progressRef.current >= totalDistance) { if (restRotation) { - const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0)); + const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(objectRotation.x, objectRotation.y, objectRotation.z)); object.quaternion.slerp(targetQuaternion, delta * 2); const angleDiff = object.quaternion.angleTo(targetQuaternion); if (angleDiff < 0.01) { - let objectRotation = agvDetail.point.rotation - object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]); + object.rotation.set(objectRotation.x, objectRotation.y, objectRotation.z); setRestingRotation(false); } return; diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index b82c6cd..6a81d3a 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -30,7 +30,7 @@ function VehicleInstance({ agvDetail }: any) { ); function vehicleStatus(modelId: string, status: string) { - console.log(`AGV ${modelId}: ${status}`); + // console.log(`${modelId} , ${status}); } // Function to reset everything @@ -43,7 +43,7 @@ function VehicleInstance({ agvDetail }: any) { const increment = () => { if (isIncrememtable.current) { - console.log('called'); + incrementVehicleLoad(agvDetail.modelUuid, 2); isIncrememtable.current = false; } @@ -51,7 +51,7 @@ function VehicleInstance({ agvDetail }: any) { useEffect(() => { if (isPlaying) { - + if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { const toPickupPath = computePath( new THREE.Vector3(agvDetail?.position[0], agvDetail?.position[1], agvDetail?.position[2]), diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index e54539f..9646174 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -190,7 +190,8 @@ function Vehicles() { // } ]); useEffect(() => { - console.log("vehicles", vehicles); + console.log('vehicles: ', vehicles); + }, [vehicles]) useEffect(() => { From 014bc3a7cae153f0372f1266c71fe33940eb76d1 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 30 Apr 2025 11:46:20 +0530 Subject: [PATCH 28/30] Refactor model identifier naming conventions from 'modeluuid' and 'modelname' to 'modelUuid' and 'modelName' across multiple modules for consistency and clarity. Update related API calls and local storage handling to reflect these changes. Remove unused deleteProductDataApi service and implement deleteProductApi service for product data deletion. Introduce steeringAngle property in vehicle configurations. --- .../sidebarRight/simulation/Simulations.tsx | 10 +++- app/src/components/ui/list/DropDownList.tsx | 4 +- app/src/components/ui/list/List.tsx | 4 +- .../IntialLoad/loadInitialFloorItems.ts | 45 ++++++++-------- .../IntialLoad/loadInitialWallItems.ts | 6 +-- .../geomentries/assets/addAssetModel.ts | 35 ++++++------ .../geomentries/assets/assetManager.ts | 18 +++---- .../geomentries/assets/deleteFloorItems.ts | 17 +++--- .../builder/geomentries/walls/addWallItems.ts | 10 ++-- .../geomentries/walls/deleteWallItems.ts | 8 +-- .../builder/groups/floorItemsGroup.tsx | 1 - .../modules/builder/groups/wallItemsGroup.tsx | 8 +-- .../socket/socketResponses.dev.tsx | 54 +++++++++---------- .../selectionControls/copyPasteControls.tsx | 12 ++--- .../selectionControls/duplicationControls.tsx | 12 ++--- .../selectionControls/moveControls.tsx | 20 +++---- .../selectionControls/rotateControls.tsx | 20 +++---- .../selectionControls/selectionControls.tsx | 13 +++-- .../armInstance/roboticArmInstance.tsx | 4 +- app/src/modules/simulation/simulation.tsx | 4 +- .../modules/simulation/vehicle/vehicles.tsx | 3 ++ .../assest/floorAsset/deleteFloorItemApi.ts | 4 +- .../assest/floorAsset/setFloorItemApi.ts | 6 +-- .../assest/wallAsset/deleteWallItemApi.ts | 4 +- .../assest/wallAsset/setWallItemApi.ts | 6 +-- .../webWorkers/assetManagerWorker.js | 4 +- ...eProductDataApi.ts => deleteProductApi.ts} | 2 +- app/src/store/simulation/useProductStore.ts | 11 +++- app/src/store/simulation/useVehicleStore.ts | 10 ++++ app/src/types/simulationTypes.d.ts | 1 + app/src/types/world/worldTypes.d.ts | 8 +-- 31 files changed, 203 insertions(+), 161 deletions(-) rename app/src/services/simulation/{deleteProductDataApi.ts => deleteProductApi.ts} (89%) diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index ca29087..bad955b 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -18,6 +18,8 @@ import EditWidgetOption from "../../../ui/menu/EditWidgetOption"; import { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { deleteEventDataApi } from "../../../../services/simulation/deleteEventDataApi"; +import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi"; +import { deleteProductApi } from "../../../../services/simulation/deleteProductApi"; interface Event { pathName: string; @@ -41,9 +43,14 @@ const Simulations: React.FC = () => { const { selectedProduct, setSelectedProduct } = useSelectedProduct(); const { getEventByModelUuid } = useEventsStore(); const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; const handleAddProduct = () => { - addProduct(`Product ${products.length + 1}`, generateUUID()); + const id = generateUUID(); + const name = `Product ${products.length + 1}`; + addProduct(name, id); + upsertProductOrEventApi({ productName: name, productId: id, organization: organization }); }; const handleRemoveProduct = (productId: string) => { @@ -68,6 +75,7 @@ const Simulations: React.FC = () => { } removeProduct(productId); + deleteProductApi(productId, organization); }; const handleRenameProduct = (productId: string, newName: string) => { diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index 0416a9e..d0b62e8 100644 --- a/app/src/components/ui/list/DropDownList.tsx +++ b/app/src/components/ui/list/DropDownList.tsx @@ -81,8 +81,8 @@ const DropDownList: React.FC = ({ return isPointInsidePolygon([x, z], polygon2D); }) .map((item: any) => ({ - id: item.modeluuid, - name: item.modelname, + id: item.modelUuid, + name: item.modelName, position: item.position, rotation: item.rotation })); diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index 06419af..cdd2a53 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -136,8 +136,8 @@ const List: React.FC = ({ items = [], remove }) => { console.log('response: ', response); setFloorItems((prevFloorItems: any[]) => prevFloorItems.map((floorItems) => - floorItems.modeluuid === zoneAssetId.id - ? { ...floorItems, modelname: response.modelname } + floorItems.modelUuid === zoneAssetId.id + ? { ...floorItems, modelName: response.modelName } : floorItems ) ); diff --git a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts index f09f130..a351d73 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialFloorItems.ts @@ -72,7 +72,7 @@ async function loadInitialFloorItems( // Check Three.js Cache const cachedModel = THREE.Cache.get(item.modelfileID!); if (cachedModel) { - // console.log(`[Cache] Fetching ${item.modelname}`); + // console.log(`[Cache] Fetching ${item.modelName}`); processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, addEvent); modelsLoaded++; checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); @@ -82,7 +82,7 @@ async function loadInitialFloorItems( // Check IndexedDB const indexedDBModel = await retrieveGLTF(item.modelfileID!); if (indexedDBModel) { - // console.log(`[IndexedDB] Fetching ${item.modelname}`); + // console.log(`[IndexedDB] Fetching ${item.modelName}`); const blobUrl = URL.createObjectURL(indexedDBModel); loader.load(blobUrl, (gltf) => { URL.revokeObjectURL(blobUrl); @@ -94,7 +94,7 @@ async function loadInitialFloorItems( }, undefined, (error) => { - toast.error(`[IndexedDB] Error loading ${item.modelname}:`); + toast.error(`[IndexedDB] Error loading ${item.modelName}:`); URL.revokeObjectURL(blobUrl); resolve(); } @@ -103,7 +103,7 @@ async function loadInitialFloorItems( } // Fetch from Backend - // console.log(`[Backend] Fetching ${item.modelname}`); + // console.log(`[Backend] Fetching ${item.modelName}`); const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`; loader.load(modelUrl, async (gltf) => { const modelBlob = await fetch(modelUrl).then((res) => res.blob()); @@ -115,18 +115,18 @@ async function loadInitialFloorItems( }, undefined, (error) => { - toast.error(`[Backend] Error loading ${item.modelname}:`); + toast.error(`[Backend] Error loading ${item.modelName}:`); resolve(); } ); }); } else { - // console.log(`Item ${item.modelname} is not near`); + // console.log(`Item ${item.modelName} is not near`); setFloorItems((prevItems) => [ ...(prevItems || []), { - modeluuid: item.modeluuid, - modelname: item.modelname, + modelUuid: item.modelUuid, + modelName: item.modelName, position: item.position, rotation: item.rotation, modelfileID: item.modelfileID, @@ -154,9 +154,9 @@ function processLoadedModel( addEvent: (event: EventsSchema) => void, ) { const model = gltf.clone(); - model.uuid = item.modeluuid; + model.uuid = item.modelUuid; model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); - model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid, eventData: item.eventData }; + model.userData = { name: item.modelName, modelId: item.modelfileID, modelUuid: item.modelUuid, eventData: item.eventData }; model.position.set(...item.position); model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z); @@ -176,8 +176,8 @@ function processLoadedModel( setFloorItems((prevItems) => [ ...(prevItems || []), { - modeluuid: item.modeluuid, - modelname: item.modelname, + modelUuid: item.modelUuid, + modelName: item.modelName, position: item.position, rotation: item.rotation, modelfileID: item.modelfileID, @@ -189,8 +189,8 @@ function processLoadedModel( if (item.eventData.type === "vehicle") { const vehicleEvent: VehicleEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, + modelUuid: item.modelUuid, + modelName: item.modelName, position: item.position, rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", @@ -206,6 +206,7 @@ function processLoadedModel( actionType: "travel", unLoadDuration: 5, loadCapacity: 10, + steeringAngle:0, pickUpPoint: null, unLoadPoint: null, triggers: [] @@ -215,8 +216,8 @@ function processLoadedModel( addEvent(vehicleEvent); } else if (item.eventData.type === "Conveyor") { const ConveyorEvent: ConveyorEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, + modelUuid: item.modelUuid, + modelName: item.modelName, position: item.position, rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", @@ -241,8 +242,8 @@ function processLoadedModel( addEvent(ConveyorEvent); } else if (item.eventData.type === "StaticMachine") { const machineEvent: MachineEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, + modelUuid: item.modelUuid, + modelName: item.modelName, position: item.position, rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", @@ -264,8 +265,8 @@ function processLoadedModel( addEvent(machineEvent); } else if (item.eventData.type === "ArmBot") { const roboticArmEvent: RoboticArmEventSchema = { - modelUuid: item.modeluuid, - modelName: item.modelname, + modelUuid: item.modelUuid, + modelName: item.modelName, position: item.position, rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", @@ -296,8 +297,8 @@ function processLoadedModel( setFloorItems((prevItems) => [ ...(prevItems || []), { - modeluuid: item.modeluuid, - modelname: item.modelname, + modelUuid: item.modelUuid, + modelName: item.modelName, position: item.position, rotation: item.rotation, modelfileID: item.modelfileID, diff --git a/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts b/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts index 34273af..f9799a8 100644 --- a/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts +++ b/app/src/modules/builder/IntialLoad/loadInitialWallItems.ts @@ -22,9 +22,9 @@ async function loadInitialWallItems( const loadedWallItems = await Promise.all(storedWallItems.map(async (item) => { const loader = new GLTFLoader(); return new Promise((resolve) => { - loader.load(AssetConfigurations[item.modelname!].modelUrl, (gltf) => { + loader.load(AssetConfigurations[item.modelName!].modelUrl, (gltf) => { const model = gltf.scene; - model.uuid = item.modeluuid!; + model.uuid = item.modelUuid!; model.children[0].children.forEach((child: any) => { if (child.name !== "CSG_REF") { @@ -36,7 +36,7 @@ async function loadInitialWallItems( resolve({ type: item.type, model: model, - modelname: item.modelname, + modelName: item.modelName, scale: item.scale, csgscale: item.csgscale, csgposition: item.csgposition, diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index ab9d90d..0bc7352 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -117,7 +117,7 @@ async function handleModelLoad( socket: Socket ) { const model = gltf.scene.clone(); - model.userData = { name: selectedItem.name, modelId: selectedItem.id, modeluuid: model.uuid }; + model.userData = { name: selectedItem.name, modelId: selectedItem.id, modelUuid: model.uuid }; model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); @@ -137,8 +137,8 @@ async function handleModelLoad( } const newFloorItem: Types.FloorItemType = { - modeluuid: model.uuid, - modelname: selectedItem.name, + modelUuid: model.uuid, + modelName: selectedItem.name, modelfileID: selectedItem.id, position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z], rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, @@ -153,8 +153,8 @@ async function handleModelLoad( // await setFloorItemApi( // organization, - // newFloorItem.modeluuid, - // newFloorItem.modelname, + // newFloorItem.modelUuid, + // newFloorItem.modelName, // newFloorItem.modelfileID, // newFloorItem.position, // { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, @@ -179,8 +179,8 @@ async function handleModelLoad( if (selectedItem.type === "Conveyor") { const ConveyorEvent: ConveyorEventSchema = { - modelUuid: newFloorItem.modeluuid, - modelName: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", @@ -211,8 +211,8 @@ async function handleModelLoad( } else if (selectedItem.type === "Vehicle") { const vehicleEvent: VehicleEventSchema = { - modelUuid: newFloorItem.modeluuid, - modelName: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", @@ -228,6 +228,7 @@ async function handleModelLoad( actionType: "travel", unLoadDuration: 5, loadCapacity: 10, + steeringAngle:0, pickUpPoint: null, unLoadPoint: null, triggers: [] @@ -243,8 +244,8 @@ async function handleModelLoad( } else if (selectedItem.type === "ArmBot") { const roboticArmEvent: RoboticArmEventSchema = { - modelUuid: newFloorItem.modeluuid, - modelName: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", @@ -278,8 +279,8 @@ async function handleModelLoad( } else if (selectedItem.type === "StaticMachine") { const machineEvent: MachineEventSchema = { - modelUuid: newFloorItem.modeluuid, - modelName: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", @@ -308,8 +309,8 @@ async function handleModelLoad( const completeData = { organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, modelfileID: newFloorItem.modelfileID, position: newFloorItem.position, rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, @@ -337,8 +338,8 @@ async function handleModelLoad( const data = { organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, modelfileID: newFloorItem.modelfileID, position: newFloorItem.position, rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, diff --git a/app/src/modules/builder/geomentries/assets/assetManager.ts b/app/src/modules/builder/geomentries/assets/assetManager.ts index 5ff75a3..5f7798e 100644 --- a/app/src/modules/builder/geomentries/assets/assetManager.ts +++ b/app/src/modules/builder/geomentries/assets/assetManager.ts @@ -58,7 +58,7 @@ export default async function assetManager( // Check Three.js Cache const cachedModel = THREE.Cache.get(item.modelfileID!); if (cachedModel) { - // console.log(`[Cache] Fetching ${item.modelname}`); + // console.log(`[Cache] Fetching ${item.modelName}`); processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve); return; } @@ -66,7 +66,7 @@ export default async function assetManager( // Check IndexedDB const indexedDBModel = await retrieveGLTF(item.modelfileID!); if (indexedDBModel) { - // console.log(`[IndexedDB] Fetching ${item.modelname}`); + // console.log(`[IndexedDB] Fetching ${item.modelName}`); const blobUrl = URL.createObjectURL(indexedDBModel); loader.load( blobUrl, @@ -78,7 +78,7 @@ export default async function assetManager( }, undefined, (error) => { - toast.error(`[IndexedDB] Error loading ${item.modelname}:`); + toast.error(`[IndexedDB] Error loading ${item.modelName}:`); resolve(); } ); @@ -86,7 +86,7 @@ export default async function assetManager( } // Fetch from Backend - // console.log(`[Backend] Fetching ${item.modelname}`); + // console.log(`[Backend] Fetching ${item.modelName}`); loader.load( modelUrl, async (gltf) => { @@ -97,7 +97,7 @@ export default async function assetManager( }, undefined, (error) => { - toast.error(`[Backend] Error loading ${item.modelname}:`); + toast.error(`[Backend] Error loading ${item.modelName}:`); resolve(); } ); @@ -112,16 +112,16 @@ 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.`); + // console.log(`Model ${item.modelName} already exists in the scene.`); resolve(); return; } const model = gltf; - model.uuid = item.modeluuid; - model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid }; + model.uuid = item.modelUuid; + model.userData = { name: item.modelName, modelId: item.modelfileID, modelUuid: item.modelUuid }; model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); model.position.set(...item.position); model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z); diff --git a/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts b/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts index 18136b3..f13ebee 100644 --- a/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts +++ b/app/src/modules/builder/geomentries/assets/deleteFloorItems.ts @@ -5,6 +5,8 @@ import * as Types from "../../../../types/world/worldTypes"; // import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi'; import { Socket } from 'socket.io-client'; import { getFloorAssets } from '../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi'; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { useProductStore } from "../../../../store/simulation/useProductStore"; async function DeleteFloorItems( itemsGroup: Types.RefGroup, @@ -22,7 +24,7 @@ async function DeleteFloorItems( const items = await getFloorAssets(organization); const removedItem = items.find( - (item: { modeluuid: string }) => item.modeluuid === hoveredDeletableFloorItem.current?.uuid + (item: { modelUuid: string }) => item.modelUuid === hoveredDeletableFloorItem.current?.uuid ); if (!removedItem) { @@ -31,26 +33,29 @@ async function DeleteFloorItems( //REST - // const response = await deleteFloorItem(organization, removedItem.modeluuid, removedItem.modelname); + // const response = await deleteFloorItem(organization, removedItem.modelUuid, removedItem.modelName); //SOCKET const data = { organization: organization, - modeluuid: removedItem.modeluuid, - modelname: removedItem.modelname, + modelUuid: removedItem.modelUuid, + modelName: removedItem.modelName, socketId: socket.id } const response = socket.emit('v2:model-asset:delete', data) + useEventsStore.getState().removeEvent(removedItem.modelUuid); + useProductStore.getState().deleteEvent(removedItem.modelUuid); + if (response) { const updatedItems = items.filter( - (item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid + (item: { modelUuid: string }) => item.modelUuid !== hoveredDeletableFloorItem.current?.uuid ); const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]'); - const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid); + const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => item.modelUuid !== hoveredDeletableFloorItem.current?.uuid); localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); if (hoveredDeletableFloorItem.current) { diff --git a/app/src/modules/builder/geomentries/walls/addWallItems.ts b/app/src/modules/builder/geomentries/walls/addWallItems.ts index 9c578aa..fd9eb48 100644 --- a/app/src/modules/builder/geomentries/walls/addWallItems.ts +++ b/app/src/modules/builder/geomentries/walls/addWallItems.ts @@ -43,7 +43,7 @@ async function AddWallItems( const newWallItem = { type: config.type, model: model, - modelname: selected, + modelName: selected, scale: config.scale, csgscale: config.csgscale, csgposition: config.csgposition, @@ -59,7 +59,7 @@ async function AddWallItems( // await setWallItem( // organization, // model.uuid, - // newWallItem.modelname, + // newWallItem.modelName, // newWallItem.type!, // newWallItem.csgposition!, // newWallItem.csgscale!, @@ -72,8 +72,8 @@ async function AddWallItems( const data = { organization: organization, - modeluuid: model.uuid, - modelname: newWallItem.modelname, + modelUuid: model.uuid, + modelName: newWallItem.modelName, type: newWallItem.type!, csgposition: newWallItem.csgposition!, csgscale: newWallItem.csgscale!, @@ -92,7 +92,7 @@ async function AddWallItems( const { model, ...rest } = item; return { ...rest, - modeluuid: model?.uuid, + modelUuid: model?.uuid, }; }); diff --git a/app/src/modules/builder/geomentries/walls/deleteWallItems.ts b/app/src/modules/builder/geomentries/walls/deleteWallItems.ts index abbf0c8..b5d40f4 100644 --- a/app/src/modules/builder/geomentries/walls/deleteWallItems.ts +++ b/app/src/modules/builder/geomentries/walls/deleteWallItems.ts @@ -28,14 +28,14 @@ function DeleteWallItems( //REST - // await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelname!) + // await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelName!) //SOCKET const data = { organization: organization, - modeluuid: removedItem?.model?.uuid!, - modelname: removedItem?.modelname!, + modelUuid: removedItem?.model?.uuid!, + modelName: removedItem?.modelName!, socketId: socket.id } @@ -45,7 +45,7 @@ function DeleteWallItems( const { model, ...rest } = item; return { ...rest, - modeluuid: model?.uuid, + modelUuid: model?.uuid, }; }); diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index f1da0a4..f3f5050 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -65,7 +65,6 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject }; getFloorAssets(organization).then((data) => { - console.log('data: ', data); if (data.length > 0) { const uniqueItems = (data as Types.FloorItems).filter((item, index, self) => index === self.findIndex((t) => t.modelfileID === item.modelfileID)); totalAssets = uniqueItems.length; diff --git a/app/src/modules/builder/groups/wallItemsGroup.tsx b/app/src/modules/builder/groups/wallItemsGroup.tsx index 43845e7..f993754 100644 --- a/app/src/modules/builder/groups/wallItemsGroup.tsx +++ b/app/src/modules/builder/groups/wallItemsGroup.tsx @@ -91,7 +91,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable const { model, ...rest } = item; return { ...rest, - modeluuid: model?.uuid, + modelUuid: model?.uuid, }; }); @@ -110,7 +110,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable // await setWallItem( // organization, // currentItem?.model?.uuid, - // currentItem.modelname, + // currentItem.modelName, // currentItem.type!, // currentItem.csgposition!, // currentItem.csgscale!, @@ -123,8 +123,8 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable const data = { organization: organization, - modeluuid: currentItem.model?.uuid!, - modelname: currentItem.modelname!, + modelUuid: currentItem.model?.uuid!, + modelName: currentItem.modelName!, type: currentItem.type!, csgposition: currentItem.csgposition!, csgscale: currentItem.csgscale!, diff --git a/app/src/modules/collaboration/socket/socketResponses.dev.tsx b/app/src/modules/collaboration/socket/socketResponses.dev.tsx index 3d9cddf..86e41c2 100644 --- a/app/src/modules/collaboration/socket/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socket/socketResponses.dev.tsx @@ -99,13 +99,13 @@ export default function SocketResponses({ try { isTempLoader.current = true; - const cachedModel = THREE.Cache.get(data.data.modelname); + const cachedModel = THREE.Cache.get(data.data.modelName); let url; if (cachedModel) { - // console.log(`Getting ${data.data.modelname} from cache`); + // console.log(`Getting ${data.data.modelName} from cache`); const model = cachedModel.scene.clone(); - model.uuid = data.data.modeluuid; - model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; + model.uuid = data.data.modelUuid; + model.userData = { name: data.data.modelName, modelId: data.data.modelfileID, modelUuid: data.data.modelUuid }; model.position.set(...data.data.position as [number, number, number]); model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); @@ -130,8 +130,8 @@ export default function SocketResponses({ } const newFloorItem: Types.FloorItemType = { - modeluuid: data.data.modeluuid, - modelname: data.data.modelname, + modelUuid: data.data.modelUuid, + modelName: data.data.modelName, modelfileID: data.data.modelfileID, position: [...data.data.position as [number, number, number]], rotation: { @@ -153,12 +153,12 @@ export default function SocketResponses({ gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } }); } else { - const indexedDBModel = await retrieveGLTF(data.data.modelname); + const indexedDBModel = await retrieveGLTF(data.data.modelName); if (indexedDBModel) { - // console.log(`Getting ${data.data.modelname} from IndexedDB`); + // console.log(`Getting ${data.data.modelName} from IndexedDB`); url = URL.createObjectURL(indexedDBModel); } else { - // console.log(`Getting ${data.data.modelname} from Backend`); + // console.log(`Getting ${data.data.modelName} from Backend`); url = `${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`; const modelBlob = await fetch(url).then((res) => res.blob()); await storeGLTF(data.data.modelfileID, modelBlob); @@ -178,8 +178,8 @@ export default function SocketResponses({ URL.revokeObjectURL(url); THREE.Cache.remove(url); const model = gltf.scene; - model.uuid = data.data.modeluuid; - model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; + model.uuid = data.data.modelUuid; + model.userData = { name: data.data.modelName, modelId: data.data.modelfileID, modelUuid: data.data.modelUuid }; model.position.set(...data.data.position as [number, number, number]); model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); @@ -204,8 +204,8 @@ export default function SocketResponses({ } const newFloorItem: Types.FloorItemType = { - modeluuid: data.data.modeluuid, - modelname: data.data.modelname, + modelUuid: data.data.modelUuid, + modelName: data.data.modelName, modelfileID: data.data.modelfileID, position: [...data.data.position as [number, number, number]], rotation: { @@ -226,7 +226,7 @@ export default function SocketResponses({ gsap.to(model.position, { y: data.data.position[1], duration: 1.5, ease: 'power2.out' }); gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out', onComplete: () => { toast.success("Model Added!") } }); - THREE.Cache.add(data.data.modelname, gltf); + THREE.Cache.add(data.data.modelName, gltf); }, () => { TempLoader(new THREE.Vector3(...data.data.position), isTempLoader, tempLoader, itemsGroup); }); @@ -234,7 +234,7 @@ export default function SocketResponses({ } else if (data.message === "Model updated successfully") { itemsGroup.current?.children.forEach((item: THREE.Group) => { - if (item.uuid === data.data.modeluuid) { + if (item.uuid === data.data.modelUuid) { item.position.set(...data.data.position as [number, number, number]); item.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); } @@ -246,7 +246,7 @@ export default function SocketResponses({ } let updatedItem: any = null; const updatedItems = prevItems.map((item) => { - if (item.modeluuid === data.data.modeluuid) { + if (item.modelUuid === data.data.modelUuid) { updatedItem = { ...item, position: [...data.data.position] as [number, number, number], @@ -269,15 +269,15 @@ export default function SocketResponses({ return } if (data.message === "Model deleted successfully") { - const deletedUUID = data.data.modeluuid; + const deletedUUID = data.data.modelUuid; let items = JSON.parse(localStorage.getItem("FloorItems")!); const updatedItems = items.filter( - (item: { modeluuid: string }) => item.modeluuid !== deletedUUID + (item: { modelUuid: string }) => item.modelUuid !== deletedUUID ); const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]'); - const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== deletedUUID); + const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => item.modelUuid !== deletedUUID); localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); itemsGroup.current.children.forEach((item: any) => { @@ -519,7 +519,7 @@ export default function SocketResponses({ return } if (data.message === "wallitem deleted") { - const deletedUUID = data.data.modeluuid; + const deletedUUID = data.data.modelUuid; let WallItemsRef = wallItems; const Items = WallItemsRef.filter((item: any) => item.model?.uuid !== deletedUUID); @@ -531,7 +531,7 @@ export default function SocketResponses({ const { model, ...rest } = item; return { ...rest, - modeluuid: model?.uuid, + modelUuid: model?.uuid, }; }); @@ -550,9 +550,9 @@ export default function SocketResponses({ } if (data.message === "wallIitem created") { const loader = new GLTFLoader(); - loader.load(AssetConfigurations[data.data.modelname].modelUrl, async (gltf) => { + loader.load(AssetConfigurations[data.data.modelName].modelUrl, async (gltf) => { const model = gltf.scene; - model.uuid = data.data.modeluuid; + model.uuid = data.data.modelUuid; model.children[0].children.forEach((child) => { if (child.name !== "CSG_REF") { child.castShadow = true; @@ -563,7 +563,7 @@ export default function SocketResponses({ const newWallItem = { type: data.data.type, model: model, - modelname: data.data.modelname, + modelName: data.data.modelName, scale: data.data.scale, csgscale: data.data.csgscale, csgposition: data.data.csgposition, @@ -578,7 +578,7 @@ export default function SocketResponses({ const { model, ...rest } = item; return { ...rest, - modeluuid: model?.uuid, + modelUuid: model?.uuid, }; }); @@ -589,7 +589,7 @@ export default function SocketResponses({ }); }); } else if (data.message === "wallIitem updated") { - const updatedUUID = data.data.modeluuid; + const updatedUUID = data.data.modelUuid; setWallItems((prevItems: any) => { const updatedItems = prevItems.map((item: any) => { @@ -610,7 +610,7 @@ export default function SocketResponses({ const { model, ...rest } = item; return { ...rest, - modeluuid: model?.uuid, + modelUuid: model?.uuid, }; }); diff --git a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx index c92c98f..613fe43 100644 --- a/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/copyPasteControls.tsx @@ -170,8 +170,8 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas } const newFloorItem: Types.FloorItemType = { - modeluuid: obj.uuid, - modelname: obj.userData.name, + modelUuid: obj.uuid, + modelName: obj.userData.name, modelfileID: obj.userData.modelId, position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, @@ -206,8 +206,8 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas const data = { organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, modelfileID: newFloorItem.modelfileID, position: newFloorItem.position, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, @@ -220,9 +220,9 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas socket.emit("v2:model-asset:add", data); obj.userData = { - name: newFloorItem.modelname, + name: newFloorItem.modelName, modelId: newFloorItem.modelfileID, - modeluuid: newFloorItem.modeluuid, + modelUuid: newFloorItem.modelUuid, eventData: updatedEventData }; diff --git a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx index c1f4a74..733e4ac 100644 --- a/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/duplicationControls.tsx @@ -148,8 +148,8 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb } const newFloorItem: Types.FloorItemType = { - modeluuid: obj.uuid, - modelname: obj.userData.name, + modelUuid: obj.uuid, + modelName: obj.userData.name, modelfileID: obj.userData.modelId, position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, @@ -184,8 +184,8 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb const data = { organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, modelfileID: newFloorItem.modelfileID, position: newFloorItem.position, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, @@ -198,9 +198,9 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb socket.emit("v2:model-asset:add", data); obj.userData = { - name: newFloorItem.modelname, + name: newFloorItem.modelName, modelId: newFloorItem.modelfileID, - modeluuid: newFloorItem.modeluuid, + modelUuid: newFloorItem.modelUuid, eventData: updatedEventData }; diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index f422d6e..d371806 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -65,7 +65,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje if (keyCombination === "G") { if (selectedAssets.length > 0) { moveAssets(); - itemsData.current = floorItems.filter((item: { modeluuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modeluuid)); + itemsData.current = floorItems.filter((item: { modelUuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)); } } if (keyCombination === "ESCAPE") { @@ -151,7 +151,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje const moveAssets = () => { - const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modeluuid)); + const updatedItems = floorItems.filter((item: { modelUuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)); setFloorItems(updatedItems); setMovedObjects(selectedAssets); selectedAssets.forEach((asset: any) => { selectionGroup.current.attach(asset); }); @@ -170,8 +170,8 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje if (itemsGroupRef.current) { const newFloorItem: Types.FloorItemType = { - modeluuid: obj.uuid, - modelname: obj.userData.name, + modelUuid: obj.uuid, + modelName: obj.userData.name, modelfileID: obj.userData.modelId, position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, @@ -180,17 +180,17 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje }; if (obj.userData.eventData) { - const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modeluuid); - const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modeluuid); + const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modelUuid); + const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid); if (eventData) { - useEventsStore.getState().updateEvent(obj.userData.modeluuid, { + useEventsStore.getState().updateEvent(obj.userData.modelUuid, { position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], }) } if (productData) { - useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modeluuid, { + useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, { position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], }) @@ -223,8 +223,8 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje const data = { organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, modelfileID: newFloorItem.modelfileID, position: newFloorItem.position, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, diff --git a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx index cf66772..08667b4 100644 --- a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx @@ -64,7 +64,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo if (event.key.toLowerCase() === "r") { if (selectedAssets.length > 0) { rotateAssets(); - itemsData.current = floorItems.filter((item: { modeluuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modeluuid)); + itemsData.current = floorItems.filter((item: { modelUuid: string }) => selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)); } } if (event.key.toLowerCase() === "escape") { @@ -128,7 +128,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo }); const rotateAssets = () => { - const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modeluuid)); + const updatedItems = floorItems.filter((item: { modelUuid: string }) => !selectedAssets.some((asset: any) => asset.uuid === item.modelUuid)); setFloorItems(updatedItems); const box = new THREE.Box3(); @@ -170,8 +170,8 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo if (itemsGroupRef.current) { const newFloorItem: Types.FloorItemType = { - modeluuid: obj.uuid, - modelname: obj.userData.name, + modelUuid: obj.uuid, + modelName: obj.userData.name, modelfileID: obj.userData.modelId, position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, @@ -180,17 +180,17 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo }; if (obj.userData.eventData) { - const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modeluuid); - const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modeluuid); + const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modelUuid); + const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid); if (eventData) { - useEventsStore.getState().updateEvent(obj.userData.modeluuid, { + useEventsStore.getState().updateEvent(obj.userData.modelUuid, { position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], }) } if (productData) { - useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modeluuid, { + useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, { position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], }) @@ -223,8 +223,8 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo const data = { organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, + modelUuid: newFloorItem.modelUuid, + modelName: newFloorItem.modelName, modelfileID: newFloorItem.modelfileID, position: newFloorItem.position, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx index 49b86d2..33a35c9 100644 --- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx @@ -14,6 +14,8 @@ import CopyPasteControls from "./copyPasteControls"; import MoveControls from "./moveControls"; import RotateControls from "./rotateControls"; import useModuleStore from "../../../../store/useModuleStore"; +import { useEventsStore } from "../../../../store/simulation/useEventsStore"; +import { useProductStore } from "../../../../store/simulation/useProductStore"; const SelectionControls: React.FC = () => { const { camera, controls, gl, scene, pointer } = useThree(); @@ -206,7 +208,7 @@ const SelectionControls: React.FC = () => { const storedItems = JSON.parse(localStorage.getItem("FloorItems") || "[]"); const selectedUUIDs = selectedAssets.map((mesh: THREE.Object3D) => mesh.uuid); - const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => !selectedUUIDs.includes(item.modeluuid)); + const updatedStoredItems = storedItems.filter((item: { modelUuid: string }) => !selectedUUIDs.includes(item.modelUuid)); localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); selectedAssets.forEach((selectedMesh: THREE.Object3D) => { @@ -218,13 +220,16 @@ const SelectionControls: React.FC = () => { const data = { organization: organization, - modeluuid: selectedMesh.uuid, - modelname: selectedMesh.userData.name, + modelUuid: selectedMesh.uuid, + modelName: selectedMesh.userData.name, socketId: socket.id, }; socket.emit("v2:model-asset:delete", data); + useEventsStore.getState().removeEvent(selectedMesh.uuid); + useProductStore.getState().deleteEvent(selectedMesh.uuid); + selectedMesh.traverse((child: THREE.Object3D) => { if (child instanceof THREE.Mesh) { if (child.geometry) child.geometry.dispose(); @@ -243,7 +248,7 @@ const SelectionControls: React.FC = () => { itemsGroupRef.current?.remove(selectedMesh); }); - const updatedItems = floorItems.filter((item: { modeluuid: string }) => !selectedUUIDs.includes(item.modeluuid)); + const updatedItems = floorItems.filter((item: { modelUuid: string }) => !selectedUUIDs.includes(item.modelUuid)); setFloorItems(updatedItems); } toast.success("Selected models removed!"); diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 3fe8af1..6bde587 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -36,12 +36,12 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { useEffect(() => { let armItems = floorItems?.filter((val: any) => - val.modeluuid === "3abf5d46-b59e-4e6b-9c02-a4634b64b82d" + val.modelUuid === "3abf5d46-b59e-4e6b-9c02-a4634b64b82d" ); // Get the first matching item let armItem = armItems?.[0]; if (armItem) { - const targetMesh = scene?.getObjectByProperty("uuid", armItem.modeluuid); + const targetMesh = scene?.getObjectByProperty("uuid", armItem.modelUuid); if (targetMesh) { targetMesh.visible = activeModule !== "simulation" } diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index f2d208d..5ca0ec5 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -19,11 +19,11 @@ function Simulation() { const { products } = useProductStore(); useEffect(() => { - console.log('events: ', events); + // console.log('events: ', events); }, [events]) useEffect(() => { - console.log('products: ', products); + // console.log('products: ', products); }, [products]) return ( diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index eaf12a3..c7fd4b6 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -28,6 +28,7 @@ function Vehicles() { actionType: "travel", unLoadDuration: 10, loadCapacity: 2, + steeringAngle:0, pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, unLoadPoint: { position: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, triggers: [ @@ -71,6 +72,7 @@ function Vehicles() { actionType: "travel", unLoadDuration: 10, loadCapacity: 2, + steeringAngle:0, pickUpPoint: { position: { x: 90, y: 0, z: 28 }, rotation: { x: 0, y: 0, z: 0 } }, unLoadPoint: { position: { x: 20, y: 0, z: 10 }, rotation: { x: 0, y: 0, z: 0 } }, triggers: [ @@ -114,6 +116,7 @@ function Vehicles() { actionType: "travel", unLoadDuration: 15, loadCapacity: 5, + steeringAngle:0, pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } }, unLoadPoint: { position: { x: 20, y: 0, z: 10 }, rotation: { x: 0, y: 0, z: 0 } }, triggers: [ diff --git a/app/src/services/factoryBuilder/assest/floorAsset/deleteFloorItemApi.ts b/app/src/services/factoryBuilder/assest/floorAsset/deleteFloorItemApi.ts index fbbb042..908319b 100644 --- a/app/src/services/factoryBuilder/assest/floorAsset/deleteFloorItemApi.ts +++ b/app/src/services/factoryBuilder/assest/floorAsset/deleteFloorItemApi.ts @@ -1,13 +1,13 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -export const deleteFloorItem = async (organization: string, modeluuid: string, modelname: string) => { +export const deleteFloorItem = async (organization: string, modelUuid: string, modelName: string) => { try { const response = await fetch(`${url_Backend_dwinzo}/api/v1/deletefloorItem`, { method: "DELETE", headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ organization, modeluuid, modelname }), + body: JSON.stringify({ organization, modelUuid, modelName }), }); if (!response.ok) { diff --git a/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts b/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts index d587f06..3d7c921 100644 --- a/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts +++ b/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts @@ -1,8 +1,8 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; export const setFloorItemApi = async ( organization: string, - modeluuid?: string, - modelname?: string, + modelUuid?: string, + modelName?: string, modelfileID?: string, position?: Object, rotation?: Object, @@ -10,7 +10,7 @@ export const setFloorItemApi = async ( isVisible?: boolean, ) => { try { - const body: any = { organization, modeluuid, modelname, position, rotation, modelfileID, isLocked, isVisible }; + const body: any = { organization, modelUuid, modelName, position, rotation, modelfileID, isLocked, isVisible }; const response = await fetch(`${url_Backend_dwinzo}/api/v2/setasset`, { method: "POST", diff --git a/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts b/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts index 58f179d..da50167 100644 --- a/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts +++ b/app/src/services/factoryBuilder/assest/wallAsset/deleteWallItemApi.ts @@ -1,13 +1,13 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -export const deleteWallItem = async (organization: string, modeluuid: string, modelname: string) => { +export const deleteWallItem = async (organization: string, modelUuid: string, modelName: string) => { try { const response = await fetch(`${url_Backend_dwinzo}/api/v1/deleteWallItem`, { method: "DELETE", headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ organization, modeluuid, modelname }), + body: JSON.stringify({ organization, modelUuid, modelName }), }); if (!response.ok) { diff --git a/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts b/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts index 79bed55..984adf5 100644 --- a/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts +++ b/app/src/services/factoryBuilder/assest/wallAsset/setWallItemApi.ts @@ -2,8 +2,8 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR export const setWallItem = async ( organization: string, - modeluuid: string, - modelname: string, + modelUuid: string, + modelName: string, type: string, csgposition: Object, csgscale: Object, @@ -17,7 +17,7 @@ export const setWallItem = async ( headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ organization, modeluuid, modelname, position, type, csgposition, csgscale, quaternion, scale }), + body: JSON.stringify({ organization, modelUuid, modelName, position, type, csgposition, csgscale, quaternion, scale }), }); if (!response.ok) { diff --git a/app/src/services/factoryBuilder/webWorkers/assetManagerWorker.js b/app/src/services/factoryBuilder/webWorkers/assetManagerWorker.js index 4ccdbf5..50dac3f 100644 --- a/app/src/services/factoryBuilder/webWorkers/assetManagerWorker.js +++ b/app/src/services/factoryBuilder/webWorkers/assetManagerWorker.js @@ -21,7 +21,7 @@ onmessage = (event) => { const itemPosition = new THREE.Vector3(...item.position); const distance = cameraPos.distanceTo(itemPosition); - if (distance <= renderDistance && !uuids.includes(item.modeluuid)) { + if (distance <= renderDistance && !uuids.includes(item.modelUuid)) { toAdd.push(item); } }); @@ -35,7 +35,7 @@ onmessage = (event) => { // Check for items to be removed uuids.forEach((uuid) => { - const floorItem = floorItems.find((item) => item.modeluuid === uuid); + const floorItem = floorItems.find((item) => item.modelUuid === uuid); if (floorItem) { const itemPosition = new THREE.Vector3(...floorItem.position); const distance = cameraPos.distanceTo(itemPosition); diff --git a/app/src/services/simulation/deleteProductDataApi.ts b/app/src/services/simulation/deleteProductApi.ts similarity index 89% rename from app/src/services/simulation/deleteProductDataApi.ts rename to app/src/services/simulation/deleteProductApi.ts index 06718f8..2987a53 100644 --- a/app/src/services/simulation/deleteProductDataApi.ts +++ b/app/src/services/simulation/deleteProductApi.ts @@ -1,6 +1,6 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -export const deleteProductDataApi = async (productId: string, organization: string) => { +export const deleteProductApi = async (productId: string, organization: string) => { try { const response = await fetch(`${url_Backend_dwinzo}/api/v2/productDataDelete?productId=${productId}&organization=${organization}`, { method: "PATCH", diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index de02551..e6f6ae0 100644 --- a/app/src/store/simulation/useProductStore.ts +++ b/app/src/store/simulation/useProductStore.ts @@ -13,6 +13,7 @@ type ProductsStore = { // Event-level actions addEvent: (productId: string, event: EventsSchema) => void; removeEvent: (productId: string, modelUuid: string) => void; + deleteEvent: (modelUuid: string) => void; updateEvent: (productId: string, modelUuid: string, updates: Partial) => void; // Point-level actions @@ -119,6 +120,14 @@ export const useProductStore = create()( }); }, + deleteEvent: (modelUuid: string) => { + set((state) => { + for (const product of state.products) { + product.eventDatas = product.eventDatas.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid); + } + }); + }, + updateEvent: (productId, modelUuid, updates) => { set((state) => { const product = state.products.find(p => p.productId === productId); @@ -440,7 +449,7 @@ export const useProductStore = create()( getPointByUuid: (productId, modelUuid, pointUuid) => { const event = get().getEventByModelUuid(productId, modelUuid); if (!event) return undefined; - + if ('points' in event) { return (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); } else if ('point' in event && (event as any).point.uuid === pointUuid) { diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts index 449ceb7..a5ea3be 100644 --- a/app/src/store/simulation/useVehicleStore.ts +++ b/app/src/store/simulation/useVehicleStore.ts @@ -22,6 +22,7 @@ interface VehiclesStore { ) => void; setVehicleActive: (modelUuid: string, isActive: boolean) => void; + updateSteeringAngle: (modelUuid: string, steeringAngle: number) => void; incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void; decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void; setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void; @@ -76,6 +77,15 @@ export const useVehicleStore = create()( }); }, + updateSteeringAngle: (modelUuid, steeringAngle) => { + set((state) => { + const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.point.action.steeringAngle = steeringAngle; + } + }); + }, + incrementVehicleLoad: (modelUuid, incrementBy) => { set((state) => { const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 46093d6..cb71864 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -44,6 +44,7 @@ interface VehiclePointSchema { actionType: "travel"; unLoadDuration: number; loadCapacity: number; + steeringAngle: number; pickUpPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null; unLoadPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null; triggers: TriggerSchema[]; diff --git a/app/src/types/world/worldTypes.d.ts b/app/src/types/world/worldTypes.d.ts index 20c44da..c148038 100644 --- a/app/src/types/world/worldTypes.d.ts +++ b/app/src/types/world/worldTypes.d.ts @@ -189,8 +189,8 @@ export type RefTubeGeometry = React.MutableRefObject; // Type for individual items placed on the floor, with positioning and rotation metadata export type FloorItemType = { - modeluuid: string; - modelname: string; + modelUuid: string; + modelName: string; position: [number, number, number]; rotation: { x: number; y: number; z: number }; modelfileID: string; @@ -238,8 +238,8 @@ export type AssetConfigurations = { [key: string]: AssetConfiguration; }; interface WallItem { type: "Fixed-Move" | "Free-Move" | undefined; model?: THREE.Group; - modeluuid?: string; - modelname?: string; + modelUuid?: string; + modelName?: string; scale?: [number, number, number]; csgscale?: [number, number, number]; csgposition?: [number, number, number]; From a20170f69e08d085e555fc95988f36fbbfd77da7 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 30 Apr 2025 11:49:58 +0530 Subject: [PATCH 29/30] Remove commented console log for vehicles in Vehicles component --- app/src/modules/simulation/vehicle/vehicles.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index d5798db..7badec5 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -194,8 +194,7 @@ function Vehicles() { // } ]); useEffect(() => { - console.log('vehicles: ', vehicles); - + // console.log('vehicles: ', vehicles); }, [vehicles]) useEffect(() => { From 304d6689c1f64730e5ca997d17f542fce64bf04e Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 30 Apr 2025 12:46:00 +0530 Subject: [PATCH 30/30] Refactor Simulations component layout: streamline event handling and add comparison functionality --- .../sidebarRight/simulation/Simulations.tsx | 101 +++++++++++------- 1 file changed, 60 insertions(+), 41 deletions(-) diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index 5b375a7..1280693 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -153,54 +153,73 @@ const Simulations: React.FC = () => { />
    {products.length > 1 && ( - <> -
    handleRemoveProduct(product.productId)} - > - -
    - -
    - - {openObjects && events.map((event, index) => )} -
    - - )} - - {selectedAsset && ( - - { - if (option === "Add to Product") { - handleAddEventToProduct({ - event: getEventByModelUuid(selectedAsset.modelUuid), - addEvent, - selectedProduct, - clearSelectedAsset - }); - } else { - handleRemoveEventFromProduct(); - } - }} - /> - +
    handleRemoveProduct(product.productId)} + > + +
    )}
    ))}
    +
    handleResize(e, productsContainerRef)} + > + +
    +
    +
    + +
    + + {openObjects && + events.map((event, index) => )} +
    + +
    +
    + Need to Compare Layout? +
    +
    + Click 'Compare' to review and analyze the layout + differences between them. +
    +
    +
    + + {selectedAsset && ( + + { + if (option === "Add to Product") { + handleAddEventToProduct({ + event: getEventByModelUuid(selectedAsset.modelUuid), + addEvent, + selectedProduct, + clearSelectedAsset + }); + } else { + handleRemoveEventFromProduct(); + } + }} + /> + + )}
    ) };