diff --git a/src/pages/MeetingRoom.tsx b/src/pages/MeetingRoom.tsx index 6dfd57e..18aa844 100644 --- a/src/pages/MeetingRoom.tsx +++ b/src/pages/MeetingRoom.tsx @@ -404,10 +404,52 @@ function MiiAvatarBackup({ ); } +// ========================================== +// CLASSES E COMPONENTES DE RESILIÊNCIA +// ========================================== +class AvatarErrorBoundary extends React.Component<{ fallback: React.ReactNode; children: React.ReactNode }, { hasError: boolean }> { + constructor(props: { fallback: React.ReactNode; children: React.ReactNode }) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError() { + return { hasError: true }; + } + + componentDidCatch(error: any) { + console.warn("🚨 [AvatarErrorBoundary] Falha ao carregar o modelo GLB do avatar. Utilizando o avatar de fallback procedural.", error); + } + + render() { + if (this.state.hasError) { + return this.props.fallback; + } + return this.props.children; + } +} + +// O componente principal MiiAvatar agora é um wrapper resiliente com Suspense e ErrorBoundary +function MiiAvatar(props: { + avatarId: number; + username: string; + isTalking?: boolean; + scale?: number; + isLastChatSender?: boolean; +} & Record) { + return ( + }> + }> + + + + ); +} + // ========================================== // NOVOS AVATARES REALISTAS (READY PLAYER ME) // ========================================== -function MiiAvatar({ +function RealMiiAvatar({ avatarId, username, isTalking,