From 7288c10a703b0b7e8ead7813311e81765577916b Mon Sep 17 00:00:00 2001 From: fullsizemalt <106900403+fullsizemalt@users.noreply.github.com> Date: Wed, 17 Dec 2025 03:45:51 -0800 Subject: [PATCH] fix: disable 3D facility viewer temporarily due to library stability issues - Replaces 3D viewer component with maintenance placeholder - Preserves METRC integration and other active features - Prevents application hard crash for users --- frontend/src/pages/Facility3DViewerPage.tsx | 312 ++------------------ 1 file changed, 18 insertions(+), 294 deletions(-) diff --git a/frontend/src/pages/Facility3DViewerPage.tsx b/frontend/src/pages/Facility3DViewerPage.tsx index 9b0136c..6478f79 100644 --- a/frontend/src/pages/Facility3DViewerPage.tsx +++ b/frontend/src/pages/Facility3DViewerPage.tsx @@ -1,305 +1,29 @@ -import { useEffect, useState, Suspense, useRef, useMemo, Component, ReactNode } from 'react'; -import { Canvas, useFrame } from '@react-three/fiber'; -import { OrbitControls, Text, Instances, Instance, Html } from '@react-three/drei'; -import { layoutApi, Floor3DData } from '../lib/layoutApi'; -import * as THREE from 'three'; -import { Loader2, ArrowLeft } from 'lucide-react'; +import { ArrowLeft } from 'lucide-react'; import { Link } from 'react-router-dom'; -// Colors -const COLORS = { - VEG: '#4ade80', // green-400 - FLOWER: '#a855f7', // purple-500 - DRY: '#f59e0b', // amber-500 - CURE: '#78716c', // stone-500 - EMPTY_SLOT: '#374151', // gray-700 - ROOM_FLOOR: '#1f2937', // gray-800 - ROOM_WALL: '#374151', // gray-700 -}; - -// Define State interface -interface ErrorBoundaryState { - hasError: boolean; - error: Error | null; -} - -class ErrorBoundary extends Component<{ children: ReactNode }, ErrorBoundaryState> { - constructor(props: { children: ReactNode }) { - super(props); - this.state = { hasError: false, error: null }; - } - - static getDerivedStateFromError(error: Error): ErrorBoundaryState { - return { hasError: true, error }; - } - - render() { - if (this.state.hasError) { - console.error("3D Viewer Error Caught:", this.state.error); - return ( - -
-

3D Rendering Error

-

{this.state.error?.message}

-
- - ); - } - return this.props.children; - } -} - -function PlantInstances({ positions, onPlantClick }: { positions: any[], onPlantClick: (p: any) => void }) { - if (!positions || !Array.isArray(positions) || positions.length === 0) return null; - - // Safety filter - const safePositions = positions.filter(p => p && typeof p.x === 'number' && typeof p.y === 'number' && typeof p.z === 'number'); - - const plants = safePositions.filter(p => p.plant); - const emptySlots = safePositions.filter(p => !p.plant); - - // Limit instances to prevent crash on huge datasets just in case - if (safePositions.length > 5000) { - console.warn('Too many positions to render:', safePositions.length); - return null; // Or return a subset - } - - return ( - - {/* Active Plants */} - {plants.length > 0 && ( - { - e.stopPropagation(); - const index = e.instanceId; - if (index !== undefined && plants[index]) { - onPlantClick(plants[index]); - } - }} - > - - - {plants.map((pos, i) => ( - - ))} - - )} - - {/* Empty Slots */} - {emptySlots.length > 0 && ( - - - - {emptySlots.map((pos, i) => ( - - ))} - - )} - - ); -} - -function FacilityScene({ data, onSelectPlant }: { data: Floor3DData, onSelectPlant: (p: any) => void }) { - // Process data into flat list of objects for rendering - const roomMeshes = useMemo(() => { - return data.rooms.map(room => { - // Room creates a floor area - return ( - - {/* Floor Label */} - - {room.name} - - - {/* Floor Plane */} - - - - - - {/* Render sections and positions */} - {room.sections.map(section => { - // Calculate positions for this section - const positions = section.positions.map(pos => { - // Simple grid layout logic for position coordinates relative to section - // Assuming typical rack dimensions - const spacing = 0.5; - const x = section.posX + (pos.column * spacing); - const z = section.posY + (pos.row * spacing); // Z is depth/row - const y = 0.5 + (pos.tier * 0.5); // Y is height/tier - - return { ...pos, x, y, z }; - }); - - return ( - - {/* Section Label */} - - {section.code} - - - - ); - })} - - ); - }); - }, [data, onSelectPlant]); - - return ( - <> - - - - - - {roomMeshes} - - - - - - ); -} - export default function Facility3DViewerPage() { - const [status, setStatus] = useState('Initializing...'); - const [floorData, setFloorData] = useState(null); - const [selectedPlant, setSelectedPlant] = useState(null); - - useEffect(() => { - loadData(); - }, []); - - async function loadData() { - setStatus('Loading layout...'); - try { - const props = await layoutApi.getProperties(); - if (props[0]?.buildings[0]?.floors[0]) { - const floorId = props[0].buildings[0].floors[0].id; - setStatus('Fetching 3D assets...'); - const data = await layoutApi.getFloor3D(floorId); - setFloorData(data); - setStatus(''); - } else { - setStatus('No floor layout found'); - } - } catch (err) { - setStatus('Error: ' + (err as Error).message); - } - } - return ( -
- {/* Header Overlay */} -
-
- - Back - -
-

- Facility Viewer 3D - BETA -

-

- {floorData ? `${floorData.floor.name} • ${floorData.stats.occupiedPositions} Plants` : 'Loading...'} -

-
-
- - {/* Legend */} -
-
Veg
-
Flower
-
Dry
-
Empty
-
+
+
+ + Back +
- {/* Error/Status Overlay */} - {status && ( -
-
- -

{status}

- {status.includes('Error') && ( - - )} -
+
+

+ Facility 3D Viewer +

+
+

System Maintenance

+

3D Visualization Engine is currently undergoing upgrades.

+

Please check back later.

- )} - {/* Selection Overlay */} - {selectedPlant && ( -
-
-

{selectedPlant.plant.tagNumber}

- -
-
-
- Strain: - {selectedPlant.plant.strain || 'Unknown'} -
-
- Stage: - {selectedPlant.plant.stage || 'N/A'} -
-
- Batch: - {selectedPlant.plant.batchName || '-'} -
-
- Location: - R{selectedPlant.row} T{selectedPlant.tier} S{selectedPlant.slot} -
-
-
- )} - - - - Loading 3D Scene...}> - {floorData && ( - - )} - - - + + Return to Compliance Dashboard + +
); }