Files
backspace/packages/web/src/main.tsx
T
Jannis Braun 4d230711fc feat: launch readiness — PWA, API hardening, memory leak fixes, sticker removal
- Add PWA infrastructure: vite-plugin-pwa, manifest, service worker,
  SW update prompt component, placeholder icons, Apple meta tags
- Harden API client: 401 auto-logout, AbortController timeouts
  (30s standard, 120s uploads), onUnauthorized callback
- Fix memory leaks: clear voice user status on leave, clean up all
  Maps (channelToSpaceMap, permissions, etc.) on removeSpace
- Upgrade error boundary to Aether Drift design with Try Again button,
  collapsible stack trace, and componentDidCatch logging
- Configure desktop icon paths in electron-builder.yml
- Remove sticker feature (server routes, schema, types, UI components)
- Fix Docker build: use **/node_modules in .dockerignore to prevent
  COPY from clobbering pnpm-installed workspace dependencies
- Add vite-env.d.ts declarations for noise suppressor wasm imports
- Exclude test files from tsc build via tsconfig
2026-03-15 15:41:22 +01:00

117 lines
3.6 KiB
TypeScript

import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { App } from './App';
import './styles/globals.css';
class ErrorBoundary extends React.Component<
{ children: React.ReactNode },
{ hasError: boolean; error: Error | null; showStack: boolean }
> {
constructor(props: { children: React.ReactNode }) {
super(props);
this.state = { hasError: false, error: null, showStack: false };
}
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('[ErrorBoundary]', error, errorInfo.componentStack);
}
render() {
if (this.state.hasError) {
return (
<div style={{
height: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#0b0b10',
color: '#efefef',
fontFamily: "'DM Sans', sans-serif",
flexDirection: 'column',
gap: '16px',
padding: '24px',
}}>
<h1 style={{ fontSize: '24px', fontWeight: 'bold' }}>Something went wrong</h1>
<p style={{ color: '#a0a0aa', maxWidth: '480px', textAlign: 'center' }}>{this.state.error?.message}</p>
<div style={{ display: 'flex', gap: '12px' }}>
<button
onClick={() => this.setState({ hasError: false, error: null })}
style={{
padding: '8px 24px',
backgroundColor: '#7c6cf6',
color: 'white',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
fontSize: '14px',
fontFamily: "'DM Sans', sans-serif",
}}
>
Try Again
</button>
<button
onClick={() => window.location.reload()}
style={{
padding: '8px 24px',
backgroundColor: 'transparent',
color: '#a0a0aa',
border: '1px solid rgba(255,255,255,0.1)',
borderRadius: '8px',
cursor: 'pointer',
fontSize: '14px',
fontFamily: "'DM Sans', sans-serif",
}}
>
Reload Page
</button>
</div>
{this.state.error?.stack && (
<details
open={this.state.showStack}
onToggle={(e) => this.setState({ showStack: (e.target as HTMLDetailsElement).open })}
style={{ maxWidth: '600px', width: '100%', marginTop: '8px' }}
>
<summary style={{ color: '#a0a0aa', cursor: 'pointer', fontSize: '13px' }}>
Error details
</summary>
<pre style={{
marginTop: '8px',
padding: '12px',
backgroundColor: 'rgba(255,255,255,0.05)',
borderRadius: '8px',
fontSize: '11px',
color: '#a0a0aa',
overflow: 'auto',
maxHeight: '200px',
whiteSpace: 'pre-wrap',
wordBreak: 'break-word',
}}>
{this.state.error.stack}
</pre>
</details>
)}
</div>
);
}
return this.props.children;
}
}
const root = document.getElementById('root');
if (!root) throw new Error('Root element not found');
ReactDOM.createRoot(root).render(
<React.StrictMode>
<ErrorBoundary>
<BrowserRouter>
<App />
</BrowserRouter>
</ErrorBoundary>
</React.StrictMode>
);