live updates and file organization
This commit is contained in:
98
frontend/src/contexts/BackendContext.js
Normal file
98
frontend/src/contexts/BackendContext.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import React, { createContext, useContext, useEffect, useRef, useState } from 'react';
|
||||
|
||||
const BackendContext = createContext(null);
|
||||
|
||||
export function useBackend() {
|
||||
return useContext(BackendContext);
|
||||
}
|
||||
|
||||
export function BackendProvider({ children }) {
|
||||
const API_BASE = process.env.REACT_APP_API_BASE || '';
|
||||
const [backendOnline, setBackendOnline] = useState(false);
|
||||
const [checking, setChecking] = useState(true);
|
||||
const esRef = useRef(null);
|
||||
const eventTargetRef = useRef(new EventTarget());
|
||||
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
const check = async () => {
|
||||
if (!mounted) return;
|
||||
setChecking(true);
|
||||
try {
|
||||
const resp = await fetch(`${API_BASE}/api/servers/health`);
|
||||
if (!mounted) return;
|
||||
setBackendOnline(!!(resp && resp.ok));
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
setBackendOnline(false);
|
||||
} finally {
|
||||
if (mounted) setChecking(false);
|
||||
}
|
||||
};
|
||||
check();
|
||||
const iv = setInterval(check, 5000);
|
||||
return () => { mounted = false; clearInterval(iv); };
|
||||
}, [API_BASE]);
|
||||
|
||||
// Single shared EventSource forwarded into a DOM EventTarget
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined' || typeof EventSource === 'undefined') return;
|
||||
const url = `${API_BASE}/api/events`;
|
||||
let es = null;
|
||||
try {
|
||||
es = new EventSource(url);
|
||||
esRef.current = es;
|
||||
} catch (err) {
|
||||
// silently ignore
|
||||
return;
|
||||
}
|
||||
|
||||
const forward = (type) => (e) => {
|
||||
try {
|
||||
const evt = new CustomEvent(type, { detail: e.data ? JSON.parse(e.data) : null });
|
||||
eventTargetRef.current.dispatchEvent(evt);
|
||||
} catch (err) {
|
||||
// ignore parse errors
|
||||
}
|
||||
};
|
||||
|
||||
es.addEventListener('connected', forward('connected'));
|
||||
es.addEventListener('commandToggle', forward('commandToggle'));
|
||||
es.addEventListener('twitchUsersUpdate', forward('twitchUsersUpdate'));
|
||||
es.addEventListener('liveNotificationsUpdate', forward('liveNotificationsUpdate'));
|
||||
|
||||
es.onerror = () => {
|
||||
// Let consumers react to backendOnline state changes instead of surfacing connection errors
|
||||
};
|
||||
|
||||
return () => { try { es && es.close(); } catch (e) {} };
|
||||
}, [process.env.REACT_APP_API_BASE]);
|
||||
|
||||
const forceCheck = async () => {
|
||||
const API_BASE2 = process.env.REACT_APP_API_BASE || '';
|
||||
try {
|
||||
setChecking(true);
|
||||
const resp = await fetch(`${API_BASE2}/api/servers/health`);
|
||||
setBackendOnline(!!(resp && resp.ok));
|
||||
} catch (e) {
|
||||
setBackendOnline(false);
|
||||
} finally {
|
||||
setChecking(false);
|
||||
}
|
||||
};
|
||||
|
||||
const value = {
|
||||
backendOnline,
|
||||
checking,
|
||||
eventTarget: eventTargetRef.current,
|
||||
forceCheck,
|
||||
};
|
||||
|
||||
return (
|
||||
<BackendContext.Provider value={value}>
|
||||
{children}
|
||||
</BackendContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default BackendContext;
|
||||
@@ -2,7 +2,7 @@ import React, { createContext, useState, useMemo, useContext, useEffect } from '
|
||||
import { ThemeProvider as MuiThemeProvider } from '@mui/material/styles';
|
||||
import { lightTheme, darkTheme, discordTheme } from '../themes';
|
||||
import { UserContext } from './UserContext';
|
||||
import axios from 'axios';
|
||||
import { post } from '../lib/api';
|
||||
|
||||
export const ThemeContext = createContext();
|
||||
|
||||
@@ -45,7 +45,7 @@ export const ThemeProvider = ({ children }) => {
|
||||
|
||||
const changeTheme = (name) => {
|
||||
if (user) {
|
||||
axios.post(`${process.env.REACT_APP_API_BASE || ''}/api/user/theme`, { userId: user.id, theme: name });
|
||||
post('/api/user/theme', { userId: user.id, theme: name }).catch(() => {});
|
||||
}
|
||||
localStorage.setItem('themeName', name);
|
||||
setThemeName(name);
|
||||
|
||||
Reference in New Issue
Block a user