🚀 Auto-deploy: melhoria no snap e medição AR em 25/05/2026 00:47:27

This commit is contained in:
2026-05-25 00:47:27 +00:00
parent 6ef7c3ae8f
commit 887e172526
+75 -23
View File
@@ -1,5 +1,36 @@
import { useEffect, useRef, useState, useMemo, Suspense } from 'react';
import React, { useEffect, useRef, useState, useMemo, Suspense } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
interface ErrorBoundaryProps {
children: React.ReactNode;
fallback: React.ReactNode;
}
interface ErrorBoundaryState {
hasError: boolean;
}
class ModelErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error: any, errorInfo: any) {
console.error("🚨 [ModelErrorBoundary] Falha de renderização/rede no modelo:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return this.props.fallback;
}
return this.props.children;
}
}
import { Canvas, useFrame } from '@react-three/fiber';
import { OrbitControls, Text, useGLTF } from '@react-three/drei';
import * as THREE from 'three';
@@ -526,28 +557,42 @@ function ThreeMeetingRoomScene({ currentActiveModel, presentationState }: { curr
{/* Modelo 3D da Maquete Holográfica */}
<group position={[0, 0.45, 0]}>
<Suspense fallback={
<mesh>
<sphereGeometry args={[0.1, 16, 16]} />
<meshBasicMaterial color="#00f5ff" wireframe />
</mesh>
<ModelErrorBoundary fallback={
// Se falhar ao carregar o modelo (ex: blob local do host inacessível por convidados), renderiza o holograma geométrico
<group rotation={[0, Date.now() * 0.00012, 0]}>
<mesh position={[0, 0, 0]}>
<octahedronGeometry args={[0.22]} />
<meshStandardMaterial color="#f43f5e" transparent opacity={0.7} wireframe emissive="#f43f5e" emissiveIntensity={0.5} />
</mesh>
<mesh position={[0, -0.15, 0]}>
<boxGeometry args={[0.3, 0.02, 0.3]} />
<meshStandardMaterial color="#ef4444" transparent opacity={0.4} />
</mesh>
</group>
}>
{currentActiveModel ? (
<HologramModel model={currentActiveModel} presentationState={presentationState} />
) : (
// Holograma Padrão Geométrico se não houver maquete carregada
<group rotation={[0, Date.now() * 0.00012, 0]}>
<mesh position={[0, 0, 0]}>
<octahedronGeometry args={[0.22]} />
<meshStandardMaterial color="#0ea5e9" transparent opacity={0.7} wireframe emissive="#0ea5e9" emissiveIntensity={0.5} />
</mesh>
<mesh position={[0, 0, 0]} rotation={[0, Math.PI / 4, 0]}>
<boxGeometry args={[0.25, 0.04, 0.25]} />
<meshStandardMaterial color="#3b82f6" transparent opacity={0.4} emissive="#3b82f6" emissiveIntensity={0.2} />
</mesh>
</group>
)}
</Suspense>
<Suspense fallback={
<mesh>
<sphereGeometry args={[0.1, 16, 16]} />
<meshBasicMaterial color="#00f5ff" wireframe />
</mesh>
}>
{currentActiveModel ? (
<HologramModel model={currentActiveModel} presentationState={presentationState} />
) : (
// Holograma Padrão Geométrico se não houver maquete carregada
<group rotation={[0, Date.now() * 0.00012, 0]}>
<mesh position={[0, 0, 0]}>
<octahedronGeometry args={[0.22]} />
<meshStandardMaterial color="#0ea5e9" transparent opacity={0.7} wireframe emissive="#0ea5e9" emissiveIntensity={0.5} />
</mesh>
<mesh position={[0, 0, 0]} rotation={[0, Math.PI / 4, 0]}>
<boxGeometry args={[0.25, 0.04, 0.25]} />
<meshStandardMaterial color="#3b82f6" transparent opacity={0.4} emissive="#3b82f6" emissiveIntensity={0.2} />
</mesh>
</group>
)}
</Suspense>
</ModelErrorBoundary>
</group>
</group>
@@ -721,7 +766,7 @@ export default function MeetingRoom() {
};
// Inicializa o Supabase Presence & Broadcast para conexões oficiais
const connectToRoom = (targetRoomId: string) => {
const connectToRoom = async (targetRoomId: string) => {
if (!name.trim()) {
toast.error('Digite seu nome primeiro');
return;
@@ -742,6 +787,13 @@ export default function MeetingRoom() {
const finalRoomId = targetRoomId.trim().toUpperCase() || Math.random().toString(36).substring(3, 8).toUpperCase();
setRoomCode(finalRoomId);
// Evita o erro "cannot add presence callbacks ... after subscribe()" removendo canais antigos com o mesmo tópico
const oldChannels = supabase.getChannels().filter(c => c.topic === `realtime:meeting_room_${finalRoomId}`);
for (const old of oldChannels) {
console.log(`🔌 [MeetingRoom] Removendo canal antigo ativo para evitar conflitos: ${old.topic}`);
await supabase.removeChannel(old);
}
console.log(`🔌 [MeetingRoom] Conectando à sala: ${finalRoomId} como ${isPresenter ? 'Apresentador' : 'Convidado'}`);