+
+ {isOpen && (
+
+ 0 ? '#4ecdc4' : 'rgba(255,255,255,0.35)',
+ fontSize:12, fontFamily:'monospace' }}>
+ {unreadMsgs > 0
+ ? `${unreadMsgs} ungelesene Nachricht${unreadMsgs !== 1 ? 'en' : ''}`
+ : 'Keine neuen Nachrichten'}
+
+
+
+ )}
+
+ );
+}
+
+// โโ Pushover Settings โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+function PushoverSettings({ toast }) {
+ const [form, setForm] = useState({ user_key:'', app_token:'' });
+ const [busy, setBusy] = useState(false);
+ const [hasSaved, setHasSaved] = useState(false);
+
+ useEffect(() => {
+ api('/tools/nachrichten/pushover')
+ .then(d => {
+ const v = { user_key: d.user_key||'', app_token: d.app_token||'' };
+ setForm(v);
+ setHasSaved(!!(v.user_key && v.app_token));
+ }).catch(()=>{});
+ }, []);
+
+ const save = async () => {
+ if (!form.user_key.trim() || !form.app_token.trim()) { toast('Beide Felder ausfรผllen', 'error'); return; }
+ setBusy(true);
+ try { await api('/tools/nachrichten/pushover', { body: form }); toast('Gespeichert'); setHasSaved(true); }
+ catch(e) { toast(e.message, 'error'); }
+ setBusy(false);
+ };
+
+ const test = async () => {
+ setBusy(true);
+ try { await api('/tools/nachrichten/pushover/test', { method:'POST' }); toast('Testbenachrichtigung gesendet โ'); }
+ catch(e) { toast(e.message, 'error'); }
+ setBusy(false);
+ };
+
+ const clear = async () => {
+ try {
+ await api('/tools/nachrichten/pushover', { method:'DELETE' });
+ setForm({ user_key:'', app_token:'' });
+ setHasSaved(false);
+ toast('Pushover entfernt');
+ } catch(e) { toast(e.message, 'error'); }
+ };
+
+ return (
+
@@ -699,6 +815,7 @@ function Dashboard({ toast, mobile }) {
+
@@ -1111,6 +1228,9 @@ function AdminPanel({ toast, mobile, user }) {
+
+
+
)}
@@ -1171,6 +1291,7 @@ export default function App() {
const [toastMsg,setToastMsg]=useState({msg:'',type:'success'});
const [updateInfo,setUpdateInfo]=useState(null);
const [showUpd,setShowUpd]=useState(false);
+ const [unreadMsgs,setUnreadMsgs]=useState(0);
const [authChecked, setAuthChecked] = useState(false);
useEffect(()=>{
@@ -1192,6 +1313,14 @@ export default function App() {
return()=>clearInterval(t);
},[user]);
+ useEffect(()=>{
+ if(!user)return;
+ const poll=()=>api('/tools/nachrichten/unread').then(d=>setUnreadMsgs(d.count||0)).catch(()=>{});
+ poll();
+ const t=setInterval(poll,30*1000);
+ return()=>clearInterval(t);
+ },[user]);
+
const toast=useCallback((msg,type='success')=>{
setToastMsg({msg,type});
setTimeout(()=>setToastMsg({msg:'',type:'success'}),3500);
@@ -1222,10 +1351,11 @@ export default function App() {
{!mobile && (