diff --git a/backend/prisma/seed-fix-sections.js b/backend/prisma/seed-fix-sections.js new file mode 100644 index 0000000..ba55485 --- /dev/null +++ b/backend/prisma/seed-fix-sections.js @@ -0,0 +1,108 @@ +/** + * FIX SECTION POSITIONS - 777 Wolfpack 3D Viewer + * + * Problem: All sections (A1-A6, B1-B6) have identical coordinates, + * causing all Flower Rooms to stack on top of each other in the 3D viewer. + * + * Solution: Offset each room's sections horizontally so they don't overlap. + * - Flower Room A sections: X offset = 0 + * - Flower Room B sections: X offset = 700 (one room width) + * - Flower Room C sections: X offset = 0, Y offset = 700 (below Room A) + * + * Run: node prisma/seed-fix-sections.js + */ + +const { PrismaClient } = require('@prisma/client'); +const prisma = new PrismaClient(); + +async function main() { + console.log('šŸ”§ Fixing section positions for 3D viewer...\n'); + + // Define room offsets (in pixels) + const roomOffsets = { + 'Flower Room A': { x: 0, y: 0 }, + 'Flower Room B': { x: 700, y: 0 }, // Offset right + 'Flower Room C': { x: 0, y: 700 }, // Offset down + 'Veg Room 1': { x: 1400, y: 0 }, // Far right + 'Veg Room 2': { x: 1400, y: 700 }, // Far right, down + 'Dry Room': { x: 0, y: 1400 }, // Bottom left + 'Cure Room': { x: 700, y: 1400 }, // Bottom center + 'Mother Room': { x: 1400, y: 1400 }, // Bottom right + }; + + // Update room positions to match the layout + console.log('šŸ“ Updating room positions...\n'); + + for (const [roomName, offset] of Object.entries(roomOffsets)) { + const result = await prisma.facilityRoom.updateMany({ + where: { name: roomName }, + data: { + posX: offset.x, + posY: offset.y, + width: 650, // Standard room width + height: 650 // Standard room height + } + }); + + console.log(` ${roomName}: posX=${offset.x}, posY=${offset.y} (updated ${result.count})`); + } + + console.log('\nšŸ“ Updating section positions (relative to rooms)...\n'); + + // Get all rooms with their sections + const rooms = await prisma.facilityRoom.findMany({ + include: { sections: true } + }); + + for (const room of rooms) { + const offset = roomOffsets[room.name]; + if (!offset) continue; + + for (const section of room.sections) { + // Section positions are currently in a 0-700 grid + // Keep them relative, but now the room offset handles separation + const newPosX = section.posX + offset.x; + const newPosY = section.posY + offset.y; + + await prisma.facilitySection.update({ + where: { id: section.id }, + data: { + posX: newPosX, + posY: newPosY + } + }); + + console.log(` ${room.name} / ${section.code}: (${section.posX}, ${section.posY}) → (${newPosX}, ${newPosY})`); + } + } + + // Update floor dimensions to fit all rooms + console.log('\nšŸ“ Updating floor dimensions...\n'); + + await prisma.facilityFloor.updateMany({ + data: { + width: 2100, // 3 columns Ɨ 700 + height: 2100 // 3 rows Ɨ 700 + } + }); + console.log(' Floor dimensions set to 2100 Ɨ 2100'); + + // Verify + console.log('\nāœ… Verification:'); + const verification = await prisma.facilityRoom.findMany({ + select: { name: true, posX: true, posY: true, width: true, height: true }, + orderBy: { name: 'asc' } + }); + + console.table(verification); + console.log('\nšŸŽ‰ Section positions fixed! Redeploy to see changes.'); +} + +main() + .catch((e) => { + console.error('Fix failed:', e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/frontend/src/components/facility3d/FacilityScene.tsx b/frontend/src/components/facility3d/FacilityScene.tsx index 877da9b..4b13263 100644 --- a/frontend/src/components/facility3d/FacilityScene.tsx +++ b/frontend/src/components/facility3d/FacilityScene.tsx @@ -84,6 +84,11 @@ export function FacilityScene({ onPlantClick={onPlantClick} highlightedTags={highlightedTags} dimMode={dimMode} + hierarchy={{ + facility: data.floor.property, + building: data.floor.building, + floor: data.floor.name, + }} /> ))} diff --git a/frontend/src/components/facility3d/RoomObject.tsx b/frontend/src/components/facility3d/RoomObject.tsx index 7872044..73ea519 100644 --- a/frontend/src/components/facility3d/RoomObject.tsx +++ b/frontend/src/components/facility3d/RoomObject.tsx @@ -2,7 +2,7 @@ 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'; +import { SmartRack, HierarchyContext } from './SmartRack'; // Convert pixel coordinates to world units const SCALE = 0.1; @@ -28,9 +28,10 @@ interface RoomObjectProps { onPlantClick: (plant: PlantPosition) => void; highlightedTags?: string[]; dimMode?: boolean; + hierarchy?: Omit; } -export function RoomObject({ room, visMode, onPlantClick, highlightedTags, dimMode }: RoomObjectProps) { +export function RoomObject({ room, visMode, onPlantClick, highlightedTags, dimMode, hierarchy }: RoomObjectProps) { const env = getMockRoomEnv(room.name); // Scale room dimensions to world units @@ -127,7 +128,7 @@ export function RoomObject({ room, visMode, onPlantClick, highlightedTags, dimMo onPlantClick={onPlantClick} highlightedTags={highlightedTags} dimMode={dimMode} - roomName={room.name} + hierarchy={{ ...hierarchy, room: room.name }} /> ))} diff --git a/frontend/src/components/facility3d/SmartRack.tsx b/frontend/src/components/facility3d/SmartRack.tsx index 718d8c0..41a7e36 100644 --- a/frontend/src/components/facility3d/SmartRack.tsx +++ b/frontend/src/components/facility3d/SmartRack.tsx @@ -6,21 +6,27 @@ import { PlantPosition, VisMode } from './types'; import { PlantSystem } from './PlantSystem'; // Convert pixel coordinates to world units -// NOTE: Section posX/posY are RELATIVE to the room (already in room's local space) -// So we scale them for placement within the room group const SCALE = 0.1; +// Hierarchy context passed down from FacilityScene +export interface HierarchyContext { + facility?: string; + building?: string; + floor?: string; + room?: string; +} + interface SmartRackProps { section: Section3D; visMode: VisMode; onPlantClick: (plant: PlantPosition) => void; highlightedTags?: string[]; dimMode?: boolean; - roomName?: string; + hierarchy?: HierarchyContext; } -export function SmartRack({ section, visMode, onPlantClick, highlightedTags, dimMode, roomName }: SmartRackProps) { - // Section positions are RELATIVE to room, scale them +export function SmartRack({ section, visMode, onPlantClick, highlightedTags, dimMode, hierarchy }: SmartRackProps) { + // Section positions are absolute (after our fix), scale them const scaledSection = { posX: section.posX * SCALE, posY: section.posY * SCALE, @@ -39,16 +45,21 @@ export function SmartRack({ section, visMode, onPlantClick, highlightedTags, dim return section.positions.map((pos: Position3D) => ({ ...pos, - // Position plants WITHIN the section, starting from section origin + // Position plants WITHIN the section x: scaledSection.posX + (pos.column * colSpacing), z: scaledSection.posY + (pos.row * rowSpacing), y: 0.4 + (pos.tier * 0.6), + // Full hierarchy breadcrumb breadcrumb: { + facility: hierarchy?.facility, + building: hierarchy?.building, + floor: hierarchy?.floor, + room: hierarchy?.room, section: section.code || section.name, - room: roomName, + tier: pos.tier, }, })); - }, [section, scaledSection, roomName]); + }, [section, scaledSection, hierarchy]); const distinctTiers = [...new Set(positions.map(p => p.tier))].sort((a, b) => a - b); const distinctRows = [...new Set(positions.map(p => p.row))].sort((a, b) => a - b);