ca-grow-ops-manager/frontend/src/components/facility3d/RoomObject.tsx
fullsizemalt 4d900d7bec
Some checks are pending
Deploy to Production / deploy (push) Waiting to run
Test / backend-test (push) Waiting to run
Test / frontend-test (push) Waiting to run
feat: add plant search, beacon highlights, and timeline slider (phases 2+3)
2025-12-18 00:19:21 -08:00

102 lines
3.6 KiB
TypeScript

import { Text } from '@react-three/drei';
import * as THREE from 'three';
import type { Room3D } from '../../lib/layoutApi';
import { PlantPosition, VisMode, COLORS } from './types';
import { SmartRack } from './SmartRack';
// Mock environment data
const getMockRoomEnv = (roomName: string) => {
const hash = roomName.split('').reduce((a, b) => a + b.charCodeAt(0), 0);
return {
temp: 68 + (hash % 15),
humidity: 40 + (hash % 40),
};
};
const lerpColor = (c1: string, c2: string, t: number) => {
const c1c = new THREE.Color(c1);
const c2c = new THREE.Color(c2);
return '#' + c1c.lerp(c2c, Math.min(1, Math.max(0, t))).getHexString();
};
interface RoomObjectProps {
room: Room3D;
visMode: VisMode;
onPlantClick: (plant: PlantPosition) => void;
highlightedTags?: string[];
dimMode?: boolean;
}
export function RoomObject({ room, visMode, onPlantClick, highlightedTags, dimMode }: RoomObjectProps) {
const env = getMockRoomEnv(room.name);
let floorColor: string = COLORS.ROOM_FLOOR;
if (visMode === 'TEMP') {
const t = (env.temp - 65) / 20;
floorColor = t < 0.5
? lerpColor(COLORS.TEMP_LOW, COLORS.TEMP_OPTIMAL, t * 2)
: lerpColor(COLORS.TEMP_OPTIMAL, COLORS.TEMP_HIGH, (t - 0.5) * 2);
} else if (visMode === 'HUMIDITY') {
const t = (env.humidity - 40) / 40;
floorColor = t < 0.5
? lerpColor(COLORS.HUMIDITY_DRY, COLORS.HUMIDITY_OPTIMAL, t * 2)
: lerpColor(COLORS.HUMIDITY_OPTIMAL, COLORS.HUMIDITY_WET, (t - 0.5) * 2);
}
return (
<group position={[room.posX, 0, room.posY]}>
<Text
position={[room.width / 2, 0.05, room.height / 2]}
rotation={[-Math.PI / 2, 0, 0]}
fontSize={Math.min(room.width, room.height) / 6}
color="#f8fafc"
fillOpacity={0.7}
anchorX="center"
anchorY="middle"
>
{room.name}
</Text>
{(visMode === 'TEMP' || visMode === 'HUMIDITY') && (
<Text
position={[room.width / 2, 4, room.height / 2]}
rotation={[-Math.PI / 4, 0, 0]}
fontSize={4}
color="#fff"
outlineColor="#000"
outlineWidth={0.15}
anchorX="center"
>
{visMode === 'TEMP' ? `${env.temp}°F` : `${env.humidity}%`}
</Text>
)}
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[room.width / 2, 0, room.height / 2]} receiveShadow>
<planeGeometry args={[room.width, room.height]} />
<meshStandardMaterial
color={floorColor}
roughness={0.95}
metalness={0.05}
transparent={visMode !== 'STANDARD'}
opacity={visMode !== 'STANDARD' ? 0.85 : 1}
/>
</mesh>
<lineSegments position={[room.width / 2, 0.02, room.height / 2]} rotation={[-Math.PI / 2, 0, 0]}>
<edgesGeometry args={[new THREE.PlaneGeometry(room.width, room.height)]} />
<lineBasicMaterial color="#64748b" />
</lineSegments>
{room.sections.map(section => (
<SmartRack
key={section.id}
section={section}
visMode={visMode}
onPlantClick={onPlantClick}
highlightedTags={highlightedTags}
dimMode={dimMode}
/>
))}
</group>
);
}