import { useState, useRef, useEffect, useCallback } from 'react'; import { Container, Typography, Card, CardContent, Grid, FormGroup, FormControlLabel, Switch, Divider, Box, ToggleButtonGroup, ToggleButton, CircularProgress, Button, Chip, } from '@mui/material'; import { Settings as SettingsIcon, Notifications, Palette, Language, SettingsBrightness, LightMode, DarkMode, Widgets, Cloud, LinkOff, Forum, Person, OpenInNew } from '@mui/icons-material'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; import DashboardLayout from '../components/dashboard/DashboardLayout'; import { useThemeMode } from '../contexts/ThemeContext'; import { preferencesApi } from '../services/settings'; import { WIDGETS, WidgetKey } from '../constants/widgets'; import { nextcloudApi } from '../services/nextcloud'; import { useNotification } from '../contexts/NotificationContext'; import { useAuth } from '../contexts/AuthContext'; const POLL_INTERVAL = 2000; const POLL_TIMEOUT = 5 * 60 * 1000; function Settings() { const { themeMode, setThemeMode } = useThemeMode(); const queryClient = useQueryClient(); const { showInfo } = useNotification(); const { user } = useAuth(); const navigate = useNavigate(); const { data: preferences, isLoading: prefsLoading } = useQuery({ queryKey: ['user-preferences'], queryFn: preferencesApi.get, }); const mutation = useMutation({ mutationFn: preferencesApi.update, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['user-preferences'] }); }, }); const isWidgetVisible = (key: WidgetKey) => { return preferences?.widgets?.[key] !== false; }; const toggleWidget = (key: WidgetKey) => { const current = preferences ?? {}; const widgets = { ...(current.widgets ?? {}) }; widgets[key] = !isWidgetVisible(key); mutation.mutate({ ...current, widgets }); }; // Nextcloud Talk connection const { data: ncData, isLoading: ncLoading } = useQuery({ queryKey: ['nextcloud-talk-rooms'], queryFn: () => nextcloudApi.getRooms(), retry: 1, }); const ncConnected = ncData?.connected ?? false; const ncLoginName = ncData?.loginName; const [isConnecting, setIsConnecting] = useState(false); const pollIntervalRef = useRef | null>(null); const popupRef = useRef(null); // Show one-time info snackbar when not connected useEffect(() => { if (!ncLoading && !ncConnected && !sessionStorage.getItem('nextcloud-talk-notified')) { sessionStorage.setItem('nextcloud-talk-notified', '1'); showInfo('Nextcloud Talk ist nicht verbunden. Verbinde dich in den Einstellungen.'); } }, [ncLoading, ncConnected, showInfo]); const stopPolling = useCallback(() => { if (pollIntervalRef.current) { clearInterval(pollIntervalRef.current); pollIntervalRef.current = null; } if (popupRef.current && !popupRef.current.closed) { popupRef.current.close(); } popupRef.current = null; setIsConnecting(false); }, []); useEffect(() => { return () => { if (pollIntervalRef.current) { clearInterval(pollIntervalRef.current); } if (popupRef.current && !popupRef.current.closed) { popupRef.current.close(); } }; }, []); const handleConnect = async () => { try { setIsConnecting(true); const { loginUrl, pollToken, pollEndpoint } = await nextcloudApi.connect(); const popup = window.open(loginUrl, '_blank', 'width=600,height=700'); popupRef.current = popup; const startTime = Date.now(); pollIntervalRef.current = setInterval(async () => { if (Date.now() - startTime > POLL_TIMEOUT) { stopPolling(); return; } if (popup && popup.closed) { stopPolling(); return; } try { const result = await nextcloudApi.poll(pollToken, pollEndpoint); if (result.completed) { stopPolling(); queryClient.invalidateQueries({ queryKey: ['nextcloud', 'connection'] }); queryClient.invalidateQueries({ queryKey: ['nextcloud', 'rooms'] }); } } catch { // Polling error — keep trying until timeout } }, POLL_INTERVAL); } catch { setIsConnecting(false); } }; const handleDisconnect = async () => { try { await nextcloudApi.disconnect(); queryClient.invalidateQueries({ queryKey: ['nextcloud-talk'] }); queryClient.invalidateQueries({ queryKey: ['nextcloud-talk-rooms'] }); } catch { // Disconnect failed silently } }; return ( Einstellungen {/* Widget Visibility */} Dashboard-Widgets {prefsLoading ? ( ) : ( {WIDGETS.map((w) => ( toggleWidget(w.key)} disabled={mutation.isPending} /> } label={w.label} /> ))} )} {/* Nextcloud Talk */} Nextcloud Talk {ncLoading ? ( ) : ncConnected ? ( {ncLoginName && ( als {ncLoginName} )} ) : ( {isConnecting ? ( Warte auf Bestätigung... ) : ( )} )} {/* Mitgliedsprofil */} Mitgliedsprofil Persönliche Daten, Standesbuchnummer und weitere Profileinstellungen. {/* Notification Settings */} Benachrichtigungen } label="E-Mail-Benachrichtigungen" /> } label="Einsatz-Alarme" /> } label="Wartungserinnerungen" /> } label="System-Benachrichtigungen" /> (Bald verfügbar) {/* Display Settings */} Anzeigeoptionen } label="Kompakte Ansicht" /> } label="Animationen" /> (Bald verfügbar) Farbschema { if (value) setThemeMode(value); }} size="small" > System Hell Dunkel {/* Language Settings */} Sprache Aktuelle Sprache: Deutsch Kommende Features: Sprachauswahl, Datumsformat, Zeitzone {/* General Settings */} Allgemein Kommende Features: Dashboard-Layout, Standardansichten, Exporteinstellungen ); } export default Settings;