From d7f1c5224df36f0e705d747d5832449230ab78c5 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Thu, 24 Apr 2025 14:05:55 +0530 Subject: [PATCH 01/16] 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/16] 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/16] 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/16] 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 dc77d9ed43bc75828ffade8bcbbb693edc6410a9 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Mon, 28 Apr 2025 12:08:57 +0530 Subject: [PATCH 05/16] armbot trigger events added --- .../instances/animator/roboticArmAnimator.tsx | 8 ++++---- .../instances/armInstance/roboticArmInstance.tsx | 3 ++- .../instances/ikInstance/ikInstance.tsx | 16 +++++++++++++--- .../modules/simulation/roboticArm/roboticArm.tsx | 10 +++++----- .../instances/animator/vehicleAnimator.tsx | 2 -- app/src/modules/simulation/vehicle/vehicles.tsx | 2 +- 6 files changed, 25 insertions(+), 16 deletions(-) diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index fd7590e..7136a79 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -8,7 +8,7 @@ function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, t const { armBots } = useArmBotStore(); const { scene } = useThree(); const restSpeed = 0.1; - const restPosition = new THREE.Vector3(0, 2, 1.6); + const restPosition = new THREE.Vector3(0, 1, -1.6); const initialCurveRef = useRef(null); const initialStartPositionRef = useRef(null); const [initialProgress, setInitialProgress] = useState(0); @@ -26,7 +26,7 @@ function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, t }, [path]) useEffect(() => { - + }, [currentPath]) useFrame((_, delta) => { @@ -42,13 +42,13 @@ function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, t currentPath.map(point => new THREE.Vector3(point[0], point[1], point[2])) ); + const next = initialProgressRef.current + delta * 0.5; if (next >= 1) { - bone.position.copy(restPosition); + // bone.position.copy(restPosition); HandleCallback(); // Call the callback when the path is completed initialProgressRef.current = 0; // Set ref to 1 when done } else { - const point = curve.getPoint(next); // Get the interpolated point from the curve bone.position.copy(point); // Update the bone position along the curve initialProgressRef.current = next; // Update progress diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 86eee6a..7972895 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -16,6 +16,7 @@ interface Process { endPoint?: Vector3; speed: number; } + function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { const { isPlaying } = usePlayButtonStore(); @@ -29,7 +30,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { const groupRef = useRef(null); const [processes, setProcesses] = useState([]); const [armBotCurvePoints, setArmBotCurvePoints] = useState({ start: [], end: [] }) - const restPosition = new THREE.Vector3(0, 2, 1.6); + const restPosition = new THREE.Vector3(0, 1, -1.6); let armBotCurveRef = useRef(null) const [path, setPath] = useState<[number, number, number][]>([]); diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx index a8d8782..7ae16e3 100644 --- a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx @@ -15,6 +15,7 @@ type IKInstanceProps = { setArmBotCurvePoints: any }; function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processes, setArmBotCurvePoints }: IKInstanceProps) { + console.log('robot: ', robot.position, robot.rotation); const { scene } = useThree(); const gltf = useLoader(GLTFLoader, modelUrl, (loader) => { const draco = new DRACOLoader(); @@ -65,15 +66,24 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processe setIkSolver(solver); const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05); - - // scene.add(groupRef.current) + if (solver) { + const bone = solver.mesh.skeleton.bones.find( + (b: any) => b.name === targetBoneName + ) ?? ""; + if (bone) { + const position = new THREE.Vector3(); + bone.getWorldPosition(position); + console.log("world position", position.x, position.y, position.z); // this is the bone's world position + } + } + scene.add(helper) }, [gltf]); return ( <> - + { - + removeArmBot(armBotStatusSample[0].modelUuid); addArmBot('123', armBotStatusSample[0]); // addArmBot('123', armBotStatusSample[1]); diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index a0eeabd..fc5303e 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -140,8 +140,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai const elapsedTime = performance.now() - startTime; if (elapsedTime >= fixedInterval) { - console.log('fixedInterval: ', fixedInterval); - console.log('elapsedTime: ', elapsedTime); let droppedMat = droppedMaterial - 1; decrementVehicleLoad(agvDetail.modelUuid, 1); if (droppedMat === 0) return; diff --git a/app/src/modules/simulation/vehicle/vehicles.tsx b/app/src/modules/simulation/vehicle/vehicles.tsx index f0b4d17..9aa89f4 100644 --- a/app/src/modules/simulation/vehicle/vehicles.tsx +++ b/app/src/modules/simulation/vehicle/vehicles.tsx @@ -148,7 +148,7 @@ function Vehicles() { }, []) useEffect(() => { - console.log('vehicles: ', vehicles); + // console.log('vehicles: ', vehicles); }, [vehicles]) From 3ebadf3c107f126a7b9aef73bf274d2bdcc1d618 Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Mon, 28 Apr 2025 12:26:31 +0530 Subject: [PATCH 06/16] added arm ui --- app/package-lock.json | 66 +-- app/src/assets/gltf-glb/arm_ui_drop.glb | Bin 0 -> 5320 bytes app/src/assets/gltf-glb/arm_ui_pick.glb | Bin 0 -> 5180 bytes app/src/components/icons/analysis.tsx | 93 +++ .../ui/analysis/ProductionCapacity.tsx | 62 ++ app/src/components/ui/analysis/ROISummary.tsx | 22 + .../ui/analysis/ThroughputSummary.tsx | 146 +++++ app/src/components/ui/arm/PickDropPoints.tsx | 54 ++ app/src/components/ui/arm/useDraggableGLTF.ts | 131 ++++ app/src/modules/builder/builder.tsx | 559 +++++++++--------- .../events/points/creator/pointsCreator.tsx | 488 ++++++++++----- app/src/pages/Project.tsx | 10 +- .../styles/components/analysis/analysis.scss | 270 +++++++++ app/src/styles/main.scss | 1 + 14 files changed, 1413 insertions(+), 489 deletions(-) create mode 100644 app/src/assets/gltf-glb/arm_ui_drop.glb create mode 100644 app/src/assets/gltf-glb/arm_ui_pick.glb 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/ThroughputSummary.tsx create mode 100644 app/src/components/ui/arm/PickDropPoints.tsx create mode 100644 app/src/components/ui/arm/useDraggableGLTF.ts create mode 100644 app/src/styles/components/analysis/analysis.scss 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/arm_ui_drop.glb b/app/src/assets/gltf-glb/arm_ui_drop.glb new file mode 100644 index 0000000000000000000000000000000000000000..2a75e7e8dbec084d49fdba2b99025f31cc97be28 GIT binary patch literal 5320 zcmdT{dpuP6-~XO-#$^nHaY;hcB&1o*m@zX(F(O4SlPINPVw5l#LoUflq)4PZspL1M z3$~S7Z3;CMX=|~mWJxY1tBa}Jy74<>tKI$M_j>kup1+=RX6Bsp`F^hN_vdrwoXz1r zE-(O~Nf!XV5&&+iygZXAf|wYggu+dtY!-@yVu2)5OyN>iY!OF_B4fy#F%$BVaG@wz zC?>lu^diSGtr%8JHib%w6N+O(BSo09wH1w$Or;3pB|?!x6yqBs45o1XDJzzH2Ly`+ zL6HFw!k8@qL6H$rVqwg*6?J+sLLd=}Lj~b60Wnd+pxAJM7;~(!`g0)^%V)!1oqG$T zV?)LNZ2-(BCJ3vD!livVi@{P#qKE_$n2fS&dW}jEMFtBM3$zW%n8nwtB#I*8Y11$I zP6^?m3J|dTVuA$Wmrv5|Obg*wVPUjUI8M`T5xGFSQ zQJF*>EBtHC3VQwy%Qw8Rm9OVck>QbI7eUZ8h5i^T)Gyx+7(0JASD=bnP9Nx2OdFbF zW3pKs2AgifNyhZQ)QthHAVVU=3Xj?(_7F-0;o+e{-jT7Jw}>z<6<#(8VuXK>O|xP% zSag~#gKcAL!(g$Q3@Q!V=@`TjUp#!x6JtmG)!8?hl})mO4h0F*?0lo`FEm7nLnA^Z zp>banupGsqn_?x3%OnclYn7{ytC#0Ag`QsC9**u5E}cs8S?cHH<>l=hK%;Q2u`2)U z*{=})hkjL*85AVro8tiUh*KkYCAYefo|nLOPbf*?#M zCQ_{E%_NFqaw0`Sk;Eq<3e&NnTeGN`Fjj;OE|ZC!M+o9EMY@$Ohi1*BTibG2Y#SQ} zn~F(nm^22HiE+!awdF7{3AV;&b8Hw`%VP9ca}+>_Vsq^O9o@>>hRI=Ka%&E@gqcvk z!=~Ma!^9ZGE^TZXG&+Zh>HXmYb3wc69QBVF<$Rx7UzC1Rg|Y6ScLqjI?KK&0WAXwm0J$ zFCp8TI?l2;;>@rnSxh+;Ku^Y#|JkQJx&71H&azAX?W1cy9x96qD+_S@e$?lO$4AS` z)62X!RNMF_>tziYF`YLAS=9^!(uG%NR z?B3ZLM_)|2yTtoaT$o$_y6V^sZlRYO+biP2{E#V_;5>!6WTMkQ$P`u+09a)Zz#{-) zMPdgCfe<_l6eUAI6X}IbHRt0Hy4ov^Oqcee~1Kvmcyj1t*c|CZa{m$+I zVJ46?Uj&ajhSoaOeDJt%g3`3V*mCS@c}Hb)JLBqxoj;Wy;S zG)r+V2=u@!w`O0k4W`aWa%#%chS5f6H&Bz=E-N}(mWteMe7w9YY&OBaMI3xv$>vsm zaI0Q$v;M-o_K!&mUfP;`M5pO+wpOaj+4IZt7u){+gg!9S z8a(Y1K;$3yjT+lAmh+9Q^hK-i+uK9B#`3~PR$SfPLY`uGG`c=sAw}%UXU*|l-*_N- zhwI@v2-@tc5A6Ee!v-I2pUZkms*Uz(-}vxS5%odhnrq(W8PBLyh2M#S&yOE2%0FbQ z*PD&5(;$I!r802!cy)%6(ba9L_1`T4tpzT4bj|4M_FeAlBhZ{gV^`moF@hi8J5g`n z;Z^2U8|}J#yU*jpR)_P^i&>*f!66lKin49a&n(Zk8}Y{RQ3I6HyrP2c zcZ6BkWDOYsAbr=i-U-s(dhtX|uF*0**e@xYC%as9PPOJmgWHVtp18ogS_;qA-&NE~ z>)P`f4*<$i0y6d*xmI}80?8g5RcuOc;Q*+yl&{w`su_a@l%Fjx(*pkC%I-(!1)M&$ zhP1kd976(!M)Co!=taV=w|xr?_?Xqb`Iu#7qj~%;4x%e_#3W110HCcN+>yyxzkw9; zn)u0yFBrre8YM$q1DhkToI9f|5)dI z2z)S<7lkkH-u)s1bNi(6`TmH0*=eWjyR^<@IH2z=hw}PMNM~z4+7-EA3U(?0G~TVg zUVK+RC)24%&}j*QpRx()y{sLA;_Ze{ZFl`-iwBnRJ;*-2w|DKE#s~++uRv3l2e99I z@?x_x-}%63oPHR}a$KU_Faf^;vK5|S@k7)tY*!0EpN^9qcpkgy_#j@EZx05U{*{YD z!OKh)upmY`ke+q2d?cZat0`N$u;EyjbeG>SA&mvz`G6Pe0&8cG_|EAXMK+>rKp4%(){uKgCRT4p<$g+&b@mza=&?Auc z{o=?Mo!ges0mt22`Ru6ydJ&jrnz=z*UN%6Iu1aQ5fl}8!D*Zu8ltMR0`DhfjBqa!CRhY&z<)tH+KMnlV$fs5GuQARyO29 z8r^dnjGS1*l2GQ9xtj}yQqSeci*5sD%&1;@`*GqZ-y zCW;|D@v54Z75cIyB%c&PvEv@%@{4?zO8E3%<2N`iy0E^_5nQOWP`lF%%u<=! z2XY~>Ya>=qIC7@d4zQ;J3n(qA*9F zLw&J__4VpV`(cZQIeS5eGuYUv4X$w(Xlw3U(hF(kEvdlA!{~z_HMF+v2(tr-QdJ-KY2POLlNU-HACQeyZNPjquNCySm1RF;3ms zA*#4rHt7Yq6~b47H6~tZW*#>J*_MeEKtQ-%t@1dLKRg23&mrH3Dd!$BmM`50(&+Fg_G)~FcrISE$7>%7 zr6Z1)Mcd7uOc9rXXbF6R*c$lpa}MGd@*Mr3x4(bJNste4w0bkfS*}8UC%)VRGVC zP&8Nf{FAAPw+|eib7}f}Dym;h^zTd}jqQ3skq=A_b) zo354JCtTC@>z_x4uOD)GwNd^W_tv%`S!u`}{hYL7DuEbs>_QT8biqoF%CF|q+Ryz- zb=5jePSKyf1mStv5zk{PdWWkkCi?qxau5-Ds^OhSaLUbIp3!k$36j*Ab7y$m;WgYB zP_i-gvlaCk_!=>%;dj46V#ABI1v|b4)IU>=PRuCN`E}xXsD&OTt;j@J9C3R_ zi_U=rIR0jDM#;2=EMbcI$YgOr4woiy7&^bC?%AuH6t4d8jW-|1pE#d)9zTnqYT#Dy z3f=CMnOx}=kl6Zq(d)5d6Q^E}eb*d5Uummr(>TDcm_kO{v}*@Q>N>SLzdJ=wlG4Wm zb`!T)p(d3AvvMfm5{R--&T1?1PU2K1geq9GtSr4OW`)k6P7YK1>SOxj;Rr z>h`0?HlH;l!+`hav+aRnU5#b+{9i1x_L>p15sUYiYeWgCpsjITv@(xwHu*o1$HtWH z(LKGHxv>P=wc7kdTgOH;PD%bIMCY_Qx_#cU2-nSsg(i4KO6(|=TQfmZ%ll}_)fu@P zAg!YvXWyvGtyYEHl5~KZ2)VlBS^08{|02(iVpm@Zs|Nh)aCSARm@G)m{Qn-H9xmA$ zy*p2thN~hc)qNUNcQL#?xCJ-^Ww?fdwE|ByWZVa)!ZcWG97V{IPdUV?VuXt}PYt5! zN$cmxoAypF|a|7Hjb6h5FA8bx;T3-#mLgjsO4v literal 0 HcmV?d00001 diff --git a/app/src/assets/gltf-glb/arm_ui_pick.glb b/app/src/assets/gltf-glb/arm_ui_pick.glb new file mode 100644 index 0000000000000000000000000000000000000000..979ade4a56367b6e788d02e6cfabeaced8af66e7 GIT binary patch literal 5180 zcmdT{dpuO@yMNbO<1&W9xFoqulaOX>#*DcsMx@9sQA)+cC}A*$T#}VYkw`hIpm2`*Qv`=j?ONUuR}MGwc1n-{*av=li_Rns;r9 z@O6O!0E=}2xP=42ZMBzYGDQ#@E0j=p$&@WZkx(p^CBimThC@EBmFhL>|DWF)tSYZf-7eHCL!Y439 zEC`MYj1OaJ0oJ9&GLUEWN;%i(XQE{6igsa0s6q!lHaY8Jbuc2-c3xy)gZ}eudhfpGj zhzJYziHh5@RfMUdD8*($tk5YcB1-Hc2%aej78%Wk!{yTHSae)EgTdgku*g_UmJNf+ z<#6dNmW?f!gF!SK8!ne&L$jsRZRuPtjZ39tDnx$s^2d6ZfZ{(K{)t)JrYICs=rkkX zpUVDCsc3OnWSAr@{u@Cck%+@K$4L~!WQw=fYFA%ZFV7j3J-vK99Nj5AI+fzP%-_k& z%f~s8M&a3{{JruDtN&t`D5QuB4Hb&lgbBCLtopxkn1Z>)DjgQAh?0RN_^nDa3r1qQ zg~DT|%+ya1jB#S4#9!;D*soC{p-AGJ7>#jk={77XB{(WhgtZHkiCsqu60l7}x8`za zHcYw=m&0P)+A`Qw46$X>7)&OU&BDsXVPFV0$7XYEvAWr^ZMilah0tMG_XK=Lx3;lm za+nxy!@;I76Y6(ZkJ)mVY$gL6+Hx5*I){q!zOI2SLu0e(Y&sWPLoyQ@Wz8}t2G)bg zSa|M@ioBzZECh0d-=u8&#&zM#_Il4RgP!wD0uOfa`_Um{?|ILXKp}SDDMS}Gv z1IrX6V~AI1=*(S-_LucH%l}BX!Rkidpb5ZIS5M&VR)<}KtI+ne)^my+$x9Ou{@ac0?&ET`COe`FdaI8P%kS?J6c zGL7W~0G1g9@CX1{lGqP~KnNZNij*OsiS)r{nhS6UUG25T3Drc^lLRH)Noax=*lifw zKRwj{>m1Yd0}orx%8uRSxK|D(G}IjEOa9nyUTRP>RAJ@dxHdC$v$wo_c=_j^A$Mw$ zULSv3(n!pKCOF&Z#zltuySzZllB)rJ9Kv4U@%=ol;<=^=@2ALLp1)R{(pxn7K~vgM z7PN=xIcRUxHG9v;yjBK@Eq+3Lg~B$Oo~H_vRFdY=`>o1`o95r0b7L~c=xmVLpwCf% zFV%hdUJpOyytjKum<=Q?m%!uB;dM^6A3ZLfq%{cx71z9HS}(VDE`*+NQrl0w>%br%iql( z5eCFO`Q)dYdAI&dY5Mw~FhnT=?)hW^4fc6Ek1C-eodjXT#qIWn+s54@yUa#%w9-`0 zU07bQg!}tb`rvFE@T^+^k$>DjW^Bh;;caBCFItV?(Gl7`o*yx~^4gwO@-(}%$@R%f zDPmVKXRhCdrh_RvU60H~&=x;^U^mbaKJ;kEJk~Q(U5szXrbm~HsSlIZUiYcUd`_({ z`c4#bVd6+}!C|gmUk+;-SGvg`C4W34pf ziF}ubaiN6k^CBwqAo2?>0yvt{Fwz`)Bdb4;8-3iZr-n6f?MjsNX;}|NnVb7F%k$kP zym3PGAf+t7xUlCvVGh<=!$tr|-?wjYf^@fCIvJa1v|JDNPtM`Xt`whFt$o?(Hfw_? zE-1f_!gmdD6}8d2_kO_xfU=Z;jJ;N_6%oBqve#A>>(blU*{aq`zCqKdb{ra1e!iky z3j{8xl5$YDcyVbjZj*}gH5x4oo z5MEYb4~CclRg1&Gt1K0;FjhH;o_(rfG_jngDOSmF= zoij9!Lee`b=&=W@I;+5=wuYokiZ6I&0wjk1zMl8pC1Is30wGbHG2V~|}AQQ#QjGsX}F5;z`hBU#7M>YCE z8kOC+UL<8z)n3mkI2AP3o*+^hY@dQ?r!N!c<7h>>}iSf&ezd%KW@d zP&9cNIB|iRl|6heNetPESJ$?#)R!eA1*Axd6`vLtzQ+q!r>z6d8^OTH5)@^t0ZI^z z-ac}TJI@3ZMnY%?A5^OOUeRSDdH!ar@(gg`CD-c2deGYKAN4+s@cDzrZ*Y7}QA58Y zxL9SWcDDtXr!ln;=0RZVQSfZn)Rp1);JO?_ubu-yWCDut%KQ&-_WiKN)&0HDPe!K` z0?DtyZ$+iW;f}tC`{R!2>(!GEz?O}3_km7lu&GNMT<0v**4zW5y3M4{yg(q|s|Rpy zIO%MCuzUU~SVdDhMt(F05vV+Ff}`aTtKRF&*6ZtzWTfNKjm8h}E#J$_CxVtbH30tr zq-z!fpra1nTAaG1tR(wM=~35QtUm#mb^xHQSbF2k+KsXxoskj=jJ{t%nBhy_eXQ#x6Kff*rIy6OpnxS>` z$E7t>IY-OPf~$1Y_u|B5PtP@`K!uQjV-a`zlKPWpLbfv9XWkK)?cl=tlXFSlX?pKB z!9SxN>KdcQICW!(=#n1Ulo#Yy1YZr&n0&33M|=vTW6+#Vg6eEdgJGhSSHV9~1^@U$ zZ8Xcy+p?O!?k)emKCT|?RVRqvBcq_>Jo0_Ga^6v6`Lg{Woeqy- zkE3Ua=Myx0z4oI}2I6={w8Q-AG;ukIk-#U3Z9$*Dsx2yCV}0Z{YsG(oJb!tf|+*A0BfXfA=pUHoja}xbshk`e$p<$ywz(zfQggvlM)o z8f|x3v>ZR48uS4fT?A4Mdz0zcb$$rlG@%ZeluQT;?(D{|GLAMtL^pe8VA{x)5vJMcHJOJ zU8hdxcc+*sQpQB!9^zJO)TAm{&f{!Xlq@G_hiI`u_einR7o+qy4U_&rH!r(;oZWyk zW5Uzed3PG?D>cO_R|Cn=UZspw#~>b%2aFwa@g4{r{{$+7{#9#F5vNZ)IzHq)d~{LU zjh-iGVjAvH!JO;MGSiA4Uo=VldHt`?_D75jo~E_@PK-BUA9@`4QChe3(6nt{h|*+0 z^y*fN5mMl;h3di8cOEyj`>rJ!27b7ZV-FnbYprS){9>8C&zzWpSbn%tD@sHK?M>@r zl=*b?ss9Nc7hAqp_skaNrc!A48jF+dotw~jCHdP>oii5bj`_zUUAG{Xn&34lsk2OO z!vxK(A7UieX60>!w2pP2d#ft9ULAT{(g|)Mor})rcP>E( zOnIpFXgmIuDyoNCgL$YL6`oY$&*m?Ov|z&flAC0BYtPO5>5V9rZ^_>WaIh*K%;#I8 z?O+G0#>WGKcb|zOdenXtQB&6>YxJsuUD`5Jpb5z@fyyVKZ6)wl=1<8!Ys%7grh}J+ z=@KVXo>TKa+0dI^E)aQnLjq2|6v(K6&ju1D`7A&K9DZFgz;cF$?(WQkvtf6*4QYc% z;c8VG!CxI%$V~FgfI=ufaRMl4f-j}eA+U+Ri0_S^ejRu-|6kYx^R literal 0 HcmV?d00001 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..331eaaf --- /dev/null +++ b/app/src/components/ui/analysis/ROISummary.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import { ROISummaryIcon } from "../../icons/analysis"; + +const ROISummary = () => { + return ( +
+
+
+
+
ROI Summary
+
From 24 November, 2025
+
+
+ +
+
+
+
+ ); +}; + +export default ROISummary; 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/components/ui/arm/PickDropPoints.tsx b/app/src/components/ui/arm/PickDropPoints.tsx new file mode 100644 index 0000000..4544a46 --- /dev/null +++ b/app/src/components/ui/arm/PickDropPoints.tsx @@ -0,0 +1,54 @@ +import React, { useRef } from "react"; +import * as THREE from "three"; +import { ThreeEvent } from "@react-three/fiber"; + +interface PickDropProps { + position: number[]; + modelUuid: string; + pointUuid: string; + actionType: "pick" | "drop"; + actionUuid: string; + gltfScene: THREE.Group; + selectedPoint: THREE.Mesh | null; + handlePointerDown: (e: ThreeEvent) => void; + isSelected: boolean; +} + +const PickDropPoints: React.FC = ({ + position, + modelUuid, + pointUuid, + actionType, + actionUuid, + gltfScene, + selectedPoint, + handlePointerDown, + isSelected, +}) => { + const groupRef = useRef(null); + + return ( + { + e.stopPropagation(); // Important to prevent event bubbling + if (!isSelected) return; + handlePointerDown(e); + }} + userData={{ modelUuid, pointUuid, actionType, actionUuid }} + > + + + ); +}; + +export default PickDropPoints; diff --git a/app/src/components/ui/arm/useDraggableGLTF.ts b/app/src/components/ui/arm/useDraggableGLTF.ts new file mode 100644 index 0000000..b7e9272 --- /dev/null +++ b/app/src/components/ui/arm/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/builder/builder.tsx b/app/src/modules/builder/builder.tsx index e5ff1c1..d367493 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -18,20 +18,20 @@ import Window from "../../assets/gltf-glb/window.glb"; ////////// Zustand State Imports ////////// import { - useToggleView, - useDeletePointOrLine, - useMovePoint, - useActiveLayer, - useSocketStore, - useWallVisibility, - useRoofVisibility, - useShadows, - useUpdateScene, - useWalls, - useToolMode, - useRefTextUpdate, - useRenderDistance, - useLimitDistance, + useToggleView, + useDeletePointOrLine, + useMovePoint, + useActiveLayer, + useSocketStore, + useWallVisibility, + useRoofVisibility, + useShadows, + useUpdateScene, + useWalls, + useToolMode, + useRefTextUpdate, + useRenderDistance, + useLimitDistance, } from "../../store/store"; ////////// 3D Function Imports ////////// @@ -56,300 +56,301 @@ import ZoneGroup from "./groups/zoneGroup"; import useModuleStore from "../../store/useModuleStore"; import MeasurementTool from "../scene/tools/measurementTool"; import NavMesh from "../simulation/vehicle/navMesh/navMesh"; +import ProductionCapacity from "../../components/ui/analysis/ProductionCapacity"; export default function Builder() { - const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. - const csg = useRef(); // Reference for CSG object, used for 3D modeling. - const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects. - const scene = useRef() as Types.RefScene; // Reference to the scene. - const camera = useRef() as Types.RefCamera; // Reference to the camera object. - const controls = useRef(); // Reference to the controls object. - const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene. - const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control. + const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. + const csg = useRef(); // Reference for CSG object, used for 3D modeling. + const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects. + const scene = useRef() as Types.RefScene; // Reference to the scene. + const camera = useRef() as Types.RefCamera; // Reference to the camera object. + const controls = useRef(); // Reference to the controls object. + const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene. + const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control. - // Assigning the scene and camera from the Three.js state to the references. + // Assigning the scene and camera from the Three.js state to the references. - scene.current = state.scene; - camera.current = state.camera; - controls.current = state.controls; - raycaster.current = state.raycaster; + scene.current = state.scene; + camera.current = state.camera; + controls.current = state.controls; + raycaster.current = state.raycaster; - const plane = useRef(null); // Reference for a plane object for raycaster reference. - const grid = useRef() as any; // Reference for a grid object for raycaster reference. - const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line. - const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end). - const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc... - const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active. - const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point. - const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start). - const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items. - const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active. - const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation. - const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn. - const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn. - const onlyFloorline = useRef([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn. - const onlyFloorlines = useRef([]); // Reference for all the floor lines that are ever drawn. - const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw. - const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not. - const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed. - const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf). - const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors. - const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation. - const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group. - const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn. - const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created. - const floorGroupAisle = useRef() as Types.RefGroup; - const zoneGroup = useRef() as Types.RefGroup; - const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls. - const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted. - const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted. - const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted. - const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted. - const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted. - const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc... + const plane = useRef(null); // Reference for a plane object for raycaster reference. + const grid = useRef() as any; // Reference for a grid object for raycaster reference. + const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line. + const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end). + const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc... + const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active. + const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point. + const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start). + const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items. + const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active. + const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation. + const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn. + const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn. + const onlyFloorline = useRef([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn. + const onlyFloorlines = useRef([]); // Reference for all the floor lines that are ever drawn. + const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw. + const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not. + const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed. + const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf). + const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors. + const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation. + const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group. + const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn. + const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created. + const floorGroupAisle = useRef() as Types.RefGroup; + const zoneGroup = useRef() as Types.RefGroup; + const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls. + const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted. + const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted. + const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted. + const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted. + const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted. + const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc... - const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position. + const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position. - const [selectedItemsIndex, setSelectedItemsIndex] = useState(null); // State for tracking the index of the selected item. - const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx. - const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D. - const { toolMode, setToolMode } = useToolMode(); - const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not. - const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); - const { socket } = useSocketStore(); - const { roofVisibility, setRoofVisibility } = useRoofVisibility(); - const { wallVisibility, setWallVisibility } = useWallVisibility(); - const { shadows, setShadows } = useShadows(); - const { renderDistance, setRenderDistance } = useRenderDistance(); - const { limitDistance, setLimitDistance } = useLimitDistance(); - const { updateScene, setUpdateScene } = useUpdateScene(); - const { walls, setWalls } = useWalls(); - const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); - const { activeModule } = useModuleStore(); + const [selectedItemsIndex, setSelectedItemsIndex] = + useState(null); // State for tracking the index of the selected item. + const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx. + const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D. + const { toolMode, setToolMode } = useToolMode(); + const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not. + const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); + const { socket } = useSocketStore(); + const { roofVisibility, setRoofVisibility } = useRoofVisibility(); + const { wallVisibility, setWallVisibility } = useWallVisibility(); + const { shadows, setShadows } = useShadows(); + const { renderDistance, setRenderDistance } = useRenderDistance(); + const { limitDistance, setLimitDistance } = useLimitDistance(); + const { updateScene, setUpdateScene } = useUpdateScene(); + const { walls, setWalls } = useWalls(); + const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); + const { activeModule } = useModuleStore(); - // const loader = new GLTFLoader(); - // const dracoLoader = new DRACOLoader(); + // const loader = new GLTFLoader(); + // const dracoLoader = new DRACOLoader(); - // dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/'); - // loader.setDRACOLoader(dracoLoader); + // dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/'); + // loader.setDRACOLoader(dracoLoader); - ////////// Assest Configuration Values ////////// + ////////// Assest Configuration Values ////////// - const AssetConfigurations: Types.AssetConfigurations = { - arch: { - modelUrl: arch, - scale: [0.75, 0.75, 0.75], - csgscale: [2, 4, 0.5], - csgposition: [0, 2, 0], - positionY: () => 0, - type: "Fixed-Move", - }, - door: { - modelUrl: door, - scale: [0.75, 0.75, 0.75], - csgscale: [2, 4, 0.5], - csgposition: [0, 2, 0], - positionY: () => 0, - type: "Fixed-Move", - }, - window: { - modelUrl: Window, - scale: [0.75, 0.75, 0.75], - csgscale: [5, 3, 0.5], - csgposition: [0, 1.5, 0], - positionY: (intersectionPoint) => intersectionPoint.point.y, - type: "Free-Move", - }, - }; + const AssetConfigurations: Types.AssetConfigurations = { + arch: { + modelUrl: arch, + scale: [0.75, 0.75, 0.75], + csgscale: [2, 4, 0.5], + csgposition: [0, 2, 0], + positionY: () => 0, + type: "Fixed-Move", + }, + door: { + modelUrl: door, + scale: [0.75, 0.75, 0.75], + csgscale: [2, 4, 0.5], + csgposition: [0, 2, 0], + positionY: () => 0, + type: "Fixed-Move", + }, + window: { + modelUrl: Window, + scale: [0.75, 0.75, 0.75], + csgscale: [5, 3, 0.5], + csgposition: [0, 1.5, 0], + positionY: (intersectionPoint) => intersectionPoint.point.y, + type: "Free-Move", + }, + }; - ////////// All Toggle's ////////// + ////////// All Toggle's ////////// - useEffect(() => { - setRefTextUpdate((prevUpdate: number) => prevUpdate - 1); - if (dragPointControls.current) { - dragPointControls.current.enabled = false; - } - if (toggleView) { - Layer2DVisibility( - activeLayer, - floorPlanGroup, - floorPlanGroupLine, - floorPlanGroupPoint, - currentLayerPoint, - dragPointControls - ); - } else { - setToolMode(null); - setDeletePointOrLine(false); - setMovePoint(false); - loadWalls(lines, setWalls); - setUpdateScene(true); - line.current = []; - } - }, [toggleView]); + useEffect(() => { + setRefTextUpdate((prevUpdate: number) => prevUpdate - 1); + if (dragPointControls.current) { + dragPointControls.current.enabled = false; + } + if (toggleView) { + Layer2DVisibility( + activeLayer, + floorPlanGroup, + floorPlanGroupLine, + floorPlanGroupPoint, + currentLayerPoint, + dragPointControls + ); + } else { + setToolMode(null); + setDeletePointOrLine(false); + setMovePoint(false); + loadWalls(lines, setWalls); + setUpdateScene(true); + line.current = []; + } + }, [toggleView]); - useEffect(() => { - THREE.Cache.clear(); - THREE.Cache.enabled = true; - }, []); + useEffect(() => { + THREE.Cache.clear(); + THREE.Cache.enabled = true; + }, []); - useEffect(() => { - const email = localStorage.getItem("email"); - const organization = email!.split("@")[1].split(".")[0]; + useEffect(() => { + const email = localStorage.getItem("email"); + const organization = email!.split("@")[1].split(".")[0]; - async function fetchVisibility() { - const visibility = await findEnvironment( - organization, - localStorage.getItem("userId")! - ); - if (visibility) { - setRoofVisibility(visibility.roofVisibility); - setWallVisibility(visibility.wallVisibility); - setShadows(visibility.shadowVisibility); - setRenderDistance(visibility.renderDistance); - setLimitDistance(visibility.limitDistance); - } - } - fetchVisibility(); - }, []); + async function fetchVisibility() { + const visibility = await findEnvironment( + organization, + localStorage.getItem("userId")! + ); + if (visibility) { + setRoofVisibility(visibility.roofVisibility); + setWallVisibility(visibility.wallVisibility); + setShadows(visibility.shadowVisibility); + setRenderDistance(visibility.renderDistance); + setLimitDistance(visibility.limitDistance); + } + } + fetchVisibility(); + }, []); - ////////// UseFrame is Here ////////// + ////////// UseFrame is Here ////////// - useFrame(() => { - if (toolMode) { - Draw( - state, - plane, - cursorPosition, - floorPlanGroupPoint, - floorPlanGroupLine, - snappedPoint, - isSnapped, - isSnappedUUID, - line, - lines, - ispreSnapped, - floorPlanGroup, - ReferenceLineMesh, - LineCreated, - setRefTextUpdate, - Tube, - anglesnappedPoint, - isAngleSnapped, - toolMode - ); - } - }); + useFrame(() => { + if (toolMode) { + Draw( + state, + plane, + cursorPosition, + floorPlanGroupPoint, + floorPlanGroupLine, + snappedPoint, + isSnapped, + isSnappedUUID, + line, + lines, + ispreSnapped, + floorPlanGroup, + ReferenceLineMesh, + LineCreated, + setRefTextUpdate, + Tube, + anglesnappedPoint, + isAngleSnapped, + toolMode + ); + } + }); - ////////// Return ////////// + ////////// Return ////////// - return ( - <> - + return ( + <> + - + - + - + - + - + - + - + - + - + - + - - - - ); + + + ); } diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index 1b3defa..f5e61d3 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -1,169 +1,337 @@ -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, useGLTF } from "@react-three/drei"; +import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys"; +import { + useSelectedEventSphere, + useSelectedEventData, +} from "../../../../../store/simulation/useSimulationStore"; +import PickDropPoints from "../../../../../components/ui/arm/PickDropPoints"; +import armPick from "../../../../../assets/gltf-glb/arm_ui_pick.glb"; +import armDrop from "../../../../../assets/gltf-glb/arm_ui_drop.glb"; +import useDraggableGLTF from "../../../../../components/ui/arm/useDraggableGLTF"; + +interface Process { + startPoint: number[] | null; + endPoint: number[] | null; +} + +interface Action { + actionUuid: string; + actionName: string; + actionType: string; + process: Process; + triggers: any[]; +} + +interface Point { + uuid: string; + position: number[]; + rotation: number[]; + actions: Action[]; +} + +interface RoboticArmEvent { + modelUuid: string; + modelName: string; + position: number[]; + rotation: number[]; + state: string; + type: string; + speed: number; + point: Point; +} 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(); - useEffect(() => { - if (selectedEventSphere) { - const eventData = getEventByModelUuid(selectedEventSphere.userData.modelUuid); - if (eventData) { - setSelectedEventData( - eventData, - selectedEventSphere.userData.pointUuid - ); - } else { - clearSelectedEventData(); + const [armBotStatusSample, setArmBotStatusSample] = useState< + RoboticArmEvent[] + >([ + { + modelUuid: "b3556818-9e46-48b0-a869-a75c92857125", + modelName: "robotic_arm", + position: [0, 0, 0], + rotation: [0, 0, 0], + state: "idle", + type: "roboticArm", + speed: 1.5, + point: { + uuid: "point-123", + position: [0, 1.5, 0], + rotation: [0, 0, 0], + actions: [ + { + actionUuid: "action-001", + actionName: "Pick Component", + actionType: "pickAndPlace", + process: { + startPoint: null, + endPoint: null, + }, + triggers: [], + }, + { + actionUuid: "action-002", + actionName: "Pick Component", + actionType: "pickAndPlace", + process: { + startPoint: null, + endPoint: null, + }, + triggers: [], + }, + ], + }, + }, + { + modelUuid: "16a394c7-0808-4bdf-a5d3-e5ca141ffb9f", + modelName: "arm without rig (1)", + position: [0, 0, 0], + rotation: [0, 0, 0], + state: "idle", + type: "roboticArm", + speed: 1.5, + point: { + uuid: "point-123", + position: [0, 1.5, 0], + rotation: [0, 0, 0], + actions: [ + { + actionUuid: "action-001", + actionName: "Pick Component", + actionType: "pickAndPlace", + process: { + startPoint: null, + endPoint: null, + }, + triggers: [], + }, + ], + }, + }, + ]); + + const armUiPick = useGLTF(armPick) as any; + const armUiDrop = useGLTF(armDrop) as any; + + const updatePointToState = (obj: THREE.Object3D) => { + const { modelUuid, pointUuid, actionType, actionUuid } = obj.userData; + const newPosition = obj.position.toArray(); + + setArmBotStatusSample((prev) => + prev.map((event) => { + if (event.modelUuid === modelUuid) { + const updatedActions = event.point.actions.map((action) => { + if (action.actionUuid === actionUuid) { + const updatedProcess = { ...action.process }; + if (actionType === "pick") { + updatedProcess.startPoint = newPosition; + } else if (actionType === "drop") { + updatedProcess.endPoint = newPosition; + } + return { + ...action, + process: updatedProcess, + }; } - } else { - clearSelectedEventData(); + return action; + }); + + return { + ...event, + point: { + ...event.point, + actions: updatedActions, + }, + }; } - }, [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) }} /> - } - - } - + return event; + }) ); + }; + + const { handlePointerDown } = useDraggableGLTF(updatePointToState); + + 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 [selectedPoint, setSelectedPoint] = useState(null); + + const getDefaultPositions = (modelUuid: string) => { + const modelData = getModelByUuid(modelUuid); + if (modelData) { + const baseX = modelData.position?.[0] || 0; + const baseY = modelData.position?.[1] + 2.8 || 1.5; + const baseZ = modelData.position?.[2] || 0; + return { + pick: [baseX, baseY, baseZ - 2.5], + drop: [baseX, baseY, baseZ - 0.5], + default: [baseX, baseY, baseZ - 1.5], + }; + } + return { + pick: [0.5, 1.5, 0], + drop: [-0.5, 1.5, 0], + default: [0, 1.5, 0], + }; + }; + + const getModelByUuid = (modelUuid: string) => { + try { + const modelsJson = localStorage.getItem("FloorItems"); + if (modelsJson) { + const models = JSON.parse(modelsJson); + return models.find((m: any) => m.modeluuid === modelUuid); + } + const storeModels = (useModuleStore.getState() as any).models || []; + return storeModels.find((m: any) => m.modelUuid === modelUuid); + } catch (error) {} + return null; + }; + + useEffect(() => { + console.log("armBotStatusSample: ", armBotStatusSample); + }, [armBotStatusSample]); + return ( + <> + {activeModule === "simulation" && ( + <> + + {armBotStatusSample.map((event, i) => { + if (event.type === "roboticArm") { + const defaultPositions = getDefaultPositions(event.modelUuid); + const isSelected = + selectedPoint?.userData?.modelUuid === event.modelUuid; + + return ( + + (sphereRefs.current[event.point.uuid] = el!)} + onClick={(e) => { + e.stopPropagation(); + setSelectedEventSphere( + sphereRefs.current[event.point.uuid] + ); + setSelectedPoint(e.object as THREE.Mesh); + }} + onPointerMissed={() => { + clearSelectedEventSphere(); + setTransformMode(null); + }} + position={new THREE.Vector3(...defaultPositions.default)} + userData={{ + modelUuid: event.modelUuid, + pointUuid: event.point.uuid, + }} + > + + + + {event.point.actions.map((action) => { + if (action.actionType === "pickAndPlace") { + const pickPosition = + action.process.startPoint || defaultPositions.pick; + const dropPosition = + action.process.endPoint || defaultPositions.drop; + + return ( + + {/* Pick Point */} + + + {/* Drop Point */} + + + ); + } + return null; + })} + + ); + } else { + return null; + } + })} + + + )} + + ); } export default PointsCreator; + + + diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 2daa091..3f6b4cc 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,6 +60,11 @@ const Project: React.FC = () => { return (
+ {/*
+ + + +
*/} {loadingProgress && } {!isPlaying && ( 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..c0d2431 100644 --- a/app/src/styles/main.scss +++ b/app/src/styles/main.scss @@ -25,6 +25,7 @@ @use 'components/simulation/simulation'; @use 'components/menu/menu'; @use 'components/confirmationPopUp'; +@use 'components/analysis/analysis'; // layout @use 'layout/loading'; From 6bf53bf72c1778be66be306ecfed337a0232dfaa Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Mon, 28 Apr 2025 13:35:13 +0530 Subject: [PATCH 07/16] timeout added --- .../armInstance/roboticArmInstance.tsx | 31 +++++++++++-------- .../instances/ikInstance/ikInstance.tsx | 22 ++++++------- .../simulation/roboticArm/roboticArm.tsx | 5 +-- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 7972895..d934a2d 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -53,7 +53,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { if (isPlaying) { //Moving armBot from initial point to rest position. if (!robot?.isActive && robot?.state == "idle" && currentPhase == "init") { - + setArmBotActive(robot.modelUuid, true) setArmBotState(robot.modelUuid, "running") setCurrentPhase("init-to-rest"); @@ -63,7 +63,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { setPath(curve.points.map(point => [point.x, point.y, point.z])); } } - logStatus(robot.modelUuid, "Starting from init to rest") + logStatus(robot.modelUuid, "Moving armBot from initial point to rest position.") } //Waiting for trigger. else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && !robot.currentAction) { @@ -85,7 +85,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { } } } - logStatus(robot.modelUuid, "Starting from rest to start") + logStatus(robot.modelUuid, "Moving armBot from rest point to start position.") } else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "picking" && robot.currentAction) { setArmBotActive(robot.modelUuid, true); @@ -99,10 +99,13 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]) ); if (curve) { - setPath(curve.points.map(point => [point.x, point.y, point.z])); + setTimeout(() => { + logStatus(robot.modelUuid, "waiting to pick box"); + setPath(curve.points.map(point => [point.x, point.y, point.z])); + }, 1500) } } - logStatus(robot.modelUuid, "Starting from start to end") + logStatus(robot.modelUuid, "Moving armBot from start point to end position.") } else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "dropping" && robot.currentAction) { setArmBotActive(robot.modelUuid, true); @@ -113,10 +116,13 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition ); if (curve) { - setPath(curve.points.map(point => [point.x, point.y, point.z])); + setTimeout(() => { + logStatus(robot.modelUuid, "waiting to drop box"); + setPath(curve.points.map(point => [point.x, point.y, point.z])); + }, 1500) } } - logStatus(robot.modelUuid, "Starting from end to rest") + logStatus(robot.modelUuid, "Moving armBot from end point to rest position.") } } @@ -134,28 +140,28 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { const HandleCallback = () => { if (robot.isActive && robot.state == "running" && currentPhase == "init-to-rest") { - console.log("Callback triggered: rest"); + logStatus(robot.modelUuid, "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."); + logStatus(robot.modelUuid, "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."); + logStatus(robot.modelUuid, "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."); + logStatus(robot.modelUuid, "Callback triggered: rest, cycle completed."); setArmBotActive(robot.modelUuid, false) setArmBotState(robot.modelUuid, "idle") setCurrentPhase("rest"); @@ -164,12 +170,11 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { } } const logStatus = (id: string, status: string) => { - console.log(id +","+ status); + console.log(id + "," + status); } return ( <> - { const draco = new DRACOLoader(); @@ -66,16 +66,16 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processe setIkSolver(solver); const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05); - if (solver) { - const bone = solver.mesh.skeleton.bones.find( - (b: any) => b.name === targetBoneName - ) ?? ""; - if (bone) { - const position = new THREE.Vector3(); - bone.getWorldPosition(position); - console.log("world position", position.x, position.y, position.z); // this is the bone's world position - } - } + // if (solver) { + // const bone = solver.mesh.skeleton.bones.find( + // (b: any) => b.name === targetBoneName + // ) ?? ""; + // if (bone) { + // const position = new THREE.Vector3(); + // bone.getWorldPosition(position); + // console.log("world position", position.x, position.y, position.z); // this is the bone's world position + // } + // } scene.add(helper) diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 270c5e3..66db204 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -6,14 +6,15 @@ import { useFloorItems } from "../../../store/store"; function RoboticArm() { const { armBots, addArmBot, removeArmBot } = useArmBotStore(); const { floorItems } = useFloorItems(); + const armBotStatusSample: RoboticArmEventSchema[] = [ { state: "idle", modelUuid: "armbot-xyz-001", modelName: "ArmBot-X200", - position: [0, 0, 0], - rotation: [-3.141592653589793, 0.3861702258311774, -3.141592653589793], + position: [0.20849215906958463, 0, 0.32079278127773675], + rotation: [-1.3768690876192207e-15, 1.4883085074751308, 1.5407776675834467e-15], type: "roboticArm", speed: 1.5, point: { From 1182850a1fec7dcfea47884061a31410e2463825 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Mon, 28 Apr 2025 17:54:55 +0530 Subject: [PATCH 08/16] armbot ui added --- .../events/points/creator/pointsCreator.tsx | 281 +++++------------- .../armInstance/roboticArmInstance.tsx | 2 +- .../instances/ikInstance/ikInstance.tsx | 15 +- .../simulation/roboticArm/roboticArm.tsx | 20 +- .../simulation}/ui/arm/PickDropPoints.tsx | 0 .../simulation}/ui/arm/useDraggableGLTF.ts | 0 6 files changed, 89 insertions(+), 229 deletions(-) rename app/src/{components => modules/simulation}/ui/arm/PickDropPoints.tsx (100%) rename app/src/{components => modules/simulation}/ui/arm/useDraggableGLTF.ts (100%) diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index 24a8ac6..3acee3c 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -8,11 +8,13 @@ import { useSelectedEventSphere, useSelectedEventData, } from "../../../../../store/simulation/useSimulationStore"; -import PickDropPoints from "../../../../../components/ui/arm/PickDropPoints"; +import PickDropPoints from "../../../ui/arm/PickDropPoints"; import armPick from "../../../../../assets/gltf-glb/arm_ui_pick.glb"; import armDrop from "../../../../../assets/gltf-glb/arm_ui_drop.glb"; -import useDraggableGLTF from "../../../../../components/ui/arm/useDraggableGLTF"; +import useDraggableGLTF from "../../../ui/arm/useDraggableGLTF"; +import { useArmBotStore } from "../../../../../store/simulation/useArmBotStore"; +import { useThree } from "@react-three/fiber"; interface Process { startPoint: number[] | null; @@ -47,117 +49,53 @@ interface RoboticArmEvent { function PointsCreator() { const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore(); - - const [armBotStatusSample, setArmBotStatusSample] = useState< - RoboticArmEvent[] - >([ - { - modelUuid: "b3556818-9e46-48b0-a869-a75c92857125", - modelName: "robotic_arm", - position: [0, 0, 0], - rotation: [0, 0, 0], - state: "idle", - type: "roboticArm", - speed: 1.5, - point: { - uuid: "point-123", - position: [0, 1.5, 0], - rotation: [0, 0, 0], - actions: [ - { - actionUuid: "action-001", - actionName: "Pick Component", - actionType: "pickAndPlace", - process: { - startPoint: null, - endPoint: null, - }, - triggers: [], - }, - { - actionUuid: "action-002", - actionName: "Pick Component", - actionType: "pickAndPlace", - process: { - startPoint: null, - endPoint: null, - }, - triggers: [], - }, - ], - }, - }, - { - modelUuid: "16a394c7-0808-4bdf-a5d3-e5ca141ffb9f", - modelName: "arm without rig (1)", - position: [0, 0, 0], - rotation: [0, 0, 0], - state: "idle", - type: "roboticArm", - speed: 1.5, - point: { - uuid: "point-123", - position: [0, 1.5, 0], - rotation: [0, 0, 0], - actions: [ - { - actionUuid: "action-001", - actionName: "Pick Component", - actionType: "pickAndPlace", - process: { - startPoint: null, - endPoint: null, - }, - triggers: [], - }, - ], - }, - }, - ]); + const { armBots, updateArmBot, addArmBot, removeArmBot } = useArmBotStore() const armUiPick = useGLTF(armPick) as any; const armUiDrop = useGLTF(armDrop) as any; const updatePointToState = (obj: THREE.Object3D) => { const { modelUuid, pointUuid, actionType, actionUuid } = obj.userData; - const newPosition = obj.position.toArray(); + + const newPosition = new THREE.Vector3(); + obj.getWorldPosition(newPosition); + const worldPositionArray = newPosition.toArray(); - setArmBotStatusSample((prev) => - prev.map((event) => { - if (event.modelUuid === modelUuid) { - const updatedActions = event.point.actions.map((action) => { - if (action.actionUuid === actionUuid) { - const updatedProcess = { ...action.process }; - if (actionType === "pick") { - updatedProcess.startPoint = newPosition; - } else if (actionType === "drop") { - updatedProcess.endPoint = newPosition; - } - return { - ...action, - process: updatedProcess, - }; - } - return action; - }); + const armBot = armBots.find((a) => a.modelUuid === modelUuid); + if (!armBot) return; - return { - ...event, - point: { - ...event.point, - actions: updatedActions, - }, - }; + const updatedActions = armBot.point.actions.map((action: any) => { + if (action.actionUuid === actionUuid) { + const updatedProcess = { ...action.process }; + + if (actionType === "pick") { + updatedProcess.startPoint = getLocalPosition(modelUuid, worldPositionArray); } - return event; - }) - ); + if (actionType === "drop") { + updatedProcess.endPoint = getLocalPosition(modelUuid, worldPositionArray); + } + return { + ...action, + process: updatedProcess, + }; + } + return action; + }); + + updateArmBot(modelUuid, { + point: { + ...armBot.point, + actions: updatedActions, + }, + }); }; - const { handlePointerDown } = useDraggableGLTF(updatePointToState); + const { handlePointerDown } = useDraggableGLTF(updatePointToState); + const { scene } = useThree(); const { activeModule } = useModuleStore(); const transformRef = useRef(null); + const groupRef = useRef(null); const [transformMode, setTransformMode] = useState< "translate" | "rotate" | null >(null); @@ -206,12 +144,13 @@ function PointsCreator() { const getDefaultPositions = (modelUuid: string) => { const modelData = getModelByUuid(modelUuid); if (modelData) { + const baseX = modelData.position?.[0] || 0; - const baseY = modelData.position?.[1] + 2.8 || 1.5; + const baseY = 2.6; const baseZ = modelData.position?.[2] || 0; return { - pick: [baseX, baseY, baseZ - 2.5], - drop: [baseX, baseY, baseZ - 0.5], + pick: [baseX, baseY, baseZ + 0.4], + drop: [baseX, baseY, baseZ - 1.2], default: [baseX, baseY, baseZ - 1.5], }; } @@ -231,113 +170,61 @@ function PointsCreator() { } const storeModels = (useModuleStore.getState() as any).models || []; return storeModels.find((m: any) => m.modelUuid === modelUuid); - } catch (error) {} + } catch (error) { } return null; }; + function getLocalPosition(parentUuid: string, worldPosArray: [number, number, number] | null): [number, number, number] | null { + if (worldPosArray) { + const worldPos = new THREE.Vector3(...worldPosArray); + const localPos = worldPos.clone(); + + const parentObject = scene.getObjectByProperty('uuid', parentUuid); + if (parentObject) { + parentObject.worldToLocal(localPos); + + return [localPos.x, localPos.y, localPos.z]; + } else { + + } + } + return null; + } + useEffect(() => { - console.log("armBotStatusSample: ", armBotStatusSample); - }, [armBotStatusSample]); + + }, [armBots]); 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") { + {armBots.map((event, i) => { + if (event.type === "roboticArm") { const defaultPositions = getDefaultPositions(event.modelUuid); const isSelected = selectedPoint?.userData?.modelUuid === event.modelUuid; - return ( (sphereRefs.current[event.point.uuid] = el!)} onClick={(e) => { e.stopPropagation(); - setSelectedEventSphere( - sphereRefs.current[event.point.uuid] - ); + setSelectedEventSphere(sphereRefs.current[event.point.uuid]); setSelectedPoint(e.object as THREE.Mesh); }} onPointerMissed={() => { clearSelectedEventSphere(); setTransformMode(null); }} - position={new THREE.Vector3(...defaultPositions.default)} - userData={{ - modelUuid: event.modelUuid, - pointUuid: event.point.uuid, - }} + position={new THREE.Vector3(...event.point.position)} + userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }} > {event.point.actions.map((action) => { if (action.actionType === "pickAndPlace") { + const pickPosition = action.process.startPoint || defaultPositions.pick; const dropPosition = @@ -385,37 +273,6 @@ function PointsCreator() { })} ); - } 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; } diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index d934a2d..fe758c5 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -67,7 +67,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { } //Waiting for trigger. else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && !robot.currentAction) { - console.log("trigger"); + logStatus(robot.modelUuid, "Waiting to trigger CurrentAction") setTimeout(() => { addCurrentAction(robot.modelUuid, 'action-003'); }, 3000); diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx index 29017ee..ca9edde 100644 --- a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx @@ -15,7 +15,7 @@ type IKInstanceProps = { setArmBotCurvePoints: any }; function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processes, setArmBotCurvePoints }: IKInstanceProps) { - + const { scene } = useThree(); const gltf = useLoader(GLTFLoader, modelUrl, (loader) => { const draco = new DRACOLoader(); @@ -65,17 +65,8 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processe const solver = new CCDIKSolver(OOI.Skinned_Mesh, iks); setIkSolver(solver); - const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05); - // if (solver) { - // const bone = solver.mesh.skeleton.bones.find( - // (b: any) => b.name === targetBoneName - // ) ?? ""; - // if (bone) { - // const position = new THREE.Vector3(); - // bone.getWorldPosition(position); - // console.log("world position", position.x, position.y, position.z); // this is the bone's world position - // } - // } + const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05) + scene.add(helper) diff --git a/app/src/modules/simulation/roboticArm/roboticArm.tsx b/app/src/modules/simulation/roboticArm/roboticArm.tsx index 66db204..69e6da0 100644 --- a/app/src/modules/simulation/roboticArm/roboticArm.tsx +++ b/app/src/modules/simulation/roboticArm/roboticArm.tsx @@ -6,12 +6,12 @@ import { useFloorItems } from "../../../store/store"; function RoboticArm() { const { armBots, addArmBot, removeArmBot } = useArmBotStore(); const { floorItems } = useFloorItems(); - + const armBotStatusSample: RoboticArmEventSchema[] = [ { state: "idle", - modelUuid: "armbot-xyz-001", + modelUuid: "3abf5d46-b59e-4e6b-9c02-a4634b64b82d", modelName: "ArmBot-X200", position: [0.20849215906958463, 0, 0.32079278127773675], rotation: [-1.3768690876192207e-15, 1.4883085074751308, 1.5407776675834467e-15], @@ -19,7 +19,7 @@ function RoboticArm() { speed: 1.5, point: { uuid: "point-123", - position: [0, 1.5, 0], + position: [0, 2.6, 0], rotation: [0, 0, 0], actions: [ { @@ -30,6 +30,18 @@ function RoboticArm() { startPoint: [-1, 2, 1], endPoint: [-2, 1, -1], }, + // process: { + // "startPoint": [ + // 0.37114476008711866, + // 1.9999999999999998, + // 1.8418816116721384 + // ], + // "endPoint": [ + // -0.42197069459490777, + // 1, + // -3.159515927851809 + // ] + // }, triggers: [ { triggerUuid: "trigger-001", @@ -154,7 +166,7 @@ function RoboticArm() { }, []); useEffect(() => { - // + }, [armBots]); return ( diff --git a/app/src/components/ui/arm/PickDropPoints.tsx b/app/src/modules/simulation/ui/arm/PickDropPoints.tsx similarity index 100% rename from app/src/components/ui/arm/PickDropPoints.tsx rename to app/src/modules/simulation/ui/arm/PickDropPoints.tsx diff --git a/app/src/components/ui/arm/useDraggableGLTF.ts b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts similarity index 100% rename from app/src/components/ui/arm/useDraggableGLTF.ts rename to app/src/modules/simulation/ui/arm/useDraggableGLTF.ts From 32a44adb7cbd8f64e73707acd15c1929c04a62f6 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Mon, 28 Apr 2025 17:59:28 +0530 Subject: [PATCH 09/16] fix console --- .../roboticArm/instances/animator/roboticArmAnimator.tsx | 1 + .../instances/armInstance/roboticArmInstance.tsx | 7 ++++--- .../roboticArm/instances/ikInstance/ikInstance.tsx | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index 7136a79..c82b73d 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -22,6 +22,7 @@ function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, t const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); useEffect(() => { + setCurrentPath(path) }, [path]) diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index fe758c5..3fe8af1 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -100,7 +100,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { ); if (curve) { setTimeout(() => { - logStatus(robot.modelUuid, "waiting to pick box"); + logStatus(robot.modelUuid, "picking the object"); setPath(curve.points.map(point => [point.x, point.y, point.z])); }, 1500) } @@ -117,7 +117,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { ); if (curve) { setTimeout(() => { - logStatus(robot.modelUuid, "waiting to drop box"); + logStatus(robot.modelUuid, "dropping the object"); setPath(curve.points.map(point => [point.x, point.y, point.z])); }, 1500) } @@ -170,7 +170,8 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) { } } const logStatus = (id: string, status: string) => { - console.log(id + "," + status); + // console.log(id + "," + status); + console.log( status); } return ( diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx index ca9edde..645cbb5 100644 --- a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx @@ -67,7 +67,7 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processe const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05) - scene.add(helper) + // scene.add(helper) }, [gltf]); From 897633d4cc712f55cc84cb7eb27c9fa638699b81 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Mon, 28 Apr 2025 18:08:27 +0530 Subject: [PATCH 10/16] 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 11/16] 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 12/16] 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 13/16] 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 2f65ee6a71747574301ab76df1230ca0001bd096 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 29 Apr 2025 09:29:18 +0530 Subject: [PATCH 14/16] 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 dd853a66d409acd8ff2ecaf2a661b9d475374a94 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 29 Apr 2025 10:30:28 +0530 Subject: [PATCH 15/16] 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 16/16] 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 {