import { Suspense, useState, useRef } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { motion, AnimatePresence } from 'framer-motion'; import { Canvas, useFrame } from '@react-three/fiber'; import { OrbitControls, Environment, PerspectiveCamera, Html, useGLTF } from '@react-three/drei'; import { ReimaginePanel } from './ReimaginePanel'; import { useProperty } from '../../shared/hooks/useStudio'; import styles from './PropertyEntity.module.css'; /** * PropertyEntity — The unified property page. * Route: /studio/:propertyId * * Layout: * - 3D hero viewport (React Three Fiber) — always prominent * - Property header overlay (name, config, price) — glassmorphic * - Action bar: [View Floorplan] [Reimagine ✨] [Share Brochure] * - ReimaginePanel slides in below hero on "Reimagine" tap * - Media grid below * * Transition into this page: scale(0.94)→scale(1) from Studio * (handled by AuthenticatedShell depth choreography) */ type Tab = 'overview' | 'media'; export default function PropertyEntity() { const { propertyId } = useParams<{ propertyId: string }>(); const navigate = useNavigate(); const [showReimagine, setShowReimagine] = useState(false); const [activeTab, setActiveTab] = useState('overview'); const { property, isLoading } = useProperty(propertyId!); if (isLoading || !property) return ; return (
{/* Back */} {/* ── 3D Hero Viewport ────────────────────────────── */}
Loading model…}> {property.modelUrl ? : } {/* Glassmorphic overlay on hero */}

{property.name}

{property.config} · {property.area} · {property.price}

{/* ── Action bar ──────────────────────────────────── */}
{/* ── ReimaginePanel — slides in below hero (no nav) ─ */} {showReimagine && (
setShowReimagine(false)} />
)}
{/* ── Tab nav ─────────────────────────────────────── */}
{(['overview', 'media'] as Tab[]).map(tab => ( ))}
{/* ── Tab content ─────────────────────────────────── */} {activeTab === 'overview' && (
{property.description && (

{property.description}

)} {property.amenities && (
{(property.amenities || []).map((a, i) => ( {a} ))}
)}
)} {activeTab === 'media' && (
{(property.images ?? []).map((img, i) => ( ))}
)}
); } // ── 3D Model component (R3F) ────────────────────────────────── function PropertyModel({ url }: { url: string }) { const { scene } = useGLTF(url); const meshRef = useRef(null); useFrame((_, delta) => { if (meshRef.current) { meshRef.current.rotation.y += delta * 0.05; } }); return ; } // Placeholder building geometry when no GLB model available function PlaceholderBuilding() { const ref = useRef(null); useFrame((_, delta) => { if (ref.current) ref.current.rotation.y += delta * 0.1; }); return ( ); } function PropertySkeleton() { return (
{[0,1].map(i => (
))}
); }