🚀 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
+54 -2
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,6 +557,19 @@ function ThreeMeetingRoomScene({ currentActiveModel, presentationState }: { curr
{/* Modelo 3D da Maquete Holográfica */}
<group position={[0, 0.45, 0]}>
<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>
}>
<Suspense fallback={
<mesh>
<sphereGeometry args={[0.1, 16, 16]} />
@@ -548,6 +592,7 @@ function ThreeMeetingRoomScene({ currentActiveModel, presentationState }: { curr
</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;
@@ -743,6 +788,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'}`);
const channel = supabase.channel(`meeting_room_${finalRoomId}`, {