Sasha commited on
Commit
43d1175
·
1 Parent(s): d9a03db

perf: optimize stats polling and add React ErrorBoundary for frontend crash fallback

Browse files
Files changed (2) hide show
  1. client/src/App.jsx +21 -0
  2. client/src/main.jsx +75 -1
client/src/App.jsx CHANGED
@@ -453,6 +453,27 @@ export default function App() {
453
  }
454
  };
455
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456
  const fetchAuthStatus = async () => {
457
  try {
458
  const res = await fetch(`${API_BASE}/api/auth/status`, { credentials: 'include' });
 
453
  }
454
  };
455
 
456
+ // Optimize polling based on page visibility (pause if tab is backgrounded)
457
+ useEffect(() => {
458
+ const handleVisibilityChange = () => {
459
+ if (document.visibilityState === 'hidden') {
460
+ stopPolling();
461
+ } else if (document.visibilityState === 'visible' && selectedStreamId && serverStatus === 'online') {
462
+ fetchAllStats(false);
463
+ const selectedStream = streams.find(s => s.id === parseInt(selectedStreamId));
464
+ const isLive = selectedStream && !selectedStream.end_time;
465
+ if (isLive || selectedStreamId === 'all') {
466
+ startPolling();
467
+ }
468
+ }
469
+ };
470
+
471
+ document.addEventListener('visibilitychange', handleVisibilityChange);
472
+ return () => {
473
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
474
+ };
475
+ }, [selectedStreamId, streams, serverStatus]);
476
+
477
  const fetchAuthStatus = async () => {
478
  try {
479
  const res = await fetch(`${API_BASE}/api/auth/status`, { credentials: 'include' });
client/src/main.jsx CHANGED
@@ -1,10 +1,84 @@
 
1
  import { StrictMode } from 'react'
2
  import { createRoot } from 'react-dom/client'
3
  import './index.css'
4
  import App from './App.jsx'
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  createRoot(document.getElementById('root')).render(
7
  <StrictMode>
8
- <App />
 
 
9
  </StrictMode>,
10
  )
 
1
+ import React, { Component } from 'react'
2
  import { StrictMode } from 'react'
3
  import { createRoot } from 'react-dom/client'
4
  import './index.css'
5
  import App from './App.jsx'
6
 
7
+ class ErrorBoundary extends Component {
8
+ constructor(props) {
9
+ super(props);
10
+ this.state = { hasError: false, error: null };
11
+ }
12
+
13
+ static getDerivedStateFromError(error) {
14
+ return { hasError: true, error };
15
+ }
16
+
17
+ componentDidCatch(error, errorInfo) {
18
+ console.error("ErrorBoundary caught an error", error, errorInfo);
19
+ }
20
+
21
+ render() {
22
+ if (this.state.hasError) {
23
+ return (
24
+ <div style={{
25
+ display: 'flex',
26
+ flexDirection: 'column',
27
+ alignItems: 'center',
28
+ justifyContent: 'center',
29
+ height: '100vh',
30
+ backgroundColor: '#0b0b0f',
31
+ color: '#fff',
32
+ fontFamily: 'sans-serif',
33
+ textAlign: 'center',
34
+ padding: '20px'
35
+ }}>
36
+ <span style={{ fontSize: '3rem' }}>⚠️</span>
37
+ <h1 style={{ color: '#FF4949', fontSize: '1.5rem', marginTop: '10px' }}>Критическая ошибка интерфейса</h1>
38
+ <p style={{ color: '#ADADB8', maxWidth: '500px', margin: '15px 0', fontSize: '0.9rem', lineHeight: '1.5' }}>
39
+ Произошла критическая ошибка при отрисовке фронтенда. Пожалуйста, попробуйте обновить страницу.
40
+ </p>
41
+ <pre style={{
42
+ backgroundColor: '#16161c',
43
+ padding: '12px',
44
+ borderRadius: '6px',
45
+ maxWidth: '100%',
46
+ width: '450px',
47
+ overflowX: 'auto',
48
+ textAlign: 'left',
49
+ color: '#FF6B6B',
50
+ fontSize: '0.8rem',
51
+ border: '1px solid #2F2F35'
52
+ }}>
53
+ {this.state.error && this.state.error.toString()}
54
+ </pre>
55
+ <button
56
+ onClick={() => window.location.reload()}
57
+ style={{
58
+ padding: '10px 20px',
59
+ backgroundColor: '#9146FF',
60
+ color: '#white',
61
+ border: 'none',
62
+ borderRadius: '5px',
63
+ cursor: 'pointer',
64
+ fontWeight: 'bold',
65
+ marginTop: '15px',
66
+ color: '#fff'
67
+ }}
68
+ >
69
+ Обновить страницу
70
+ </button>
71
+ </div>
72
+ );
73
+ }
74
+ return this.props.children;
75
+ }
76
+ }
77
+
78
  createRoot(document.getElementById('root')).render(
79
  <StrictMode>
80
+ <ErrorBoundary>
81
+ <App />
82
+ </ErrorBoundary>
83
  </StrictMode>,
84
  )