diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index fe8c0df..2e55b00 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -1,6 +1,7 @@
import { useState, useEffect, useRef, useCallback } from 'react';
import { api, S } from './lib.js';
import { TOOLS, getGroupedTools } from './toolRegistry.js';
+import { useConfirm } from './confirm.jsx';
import { HomeIcon, AppsIcon, AdminIcon, MoreIcon, UserIcon, LogOutIcon, ChevronIcon, UpdateIcon } from './icons.jsx';
const ICONS = ['๐','๐','๐','๐','๐ ','๐ง','๐','๐พ','๐ฅ','๐ก','๐','๐','๐ฏ','โก','๐ ','๐ง','๐ฑ','๐ฎ','๐','๐ก'];
@@ -330,6 +331,7 @@ function BottomNav({ active, setActive, user, onLogout, updateInfo, onUpdateClic
// โโ Dashboard Widgets โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function QuickLinks({ toast, mobile }) {
+ const { confirm, ConfirmDialog } = useConfirm();
const [links, setLinks] = useState([]);
const [editMode, setEdit] = useState(false);
const [showForm, setForm] = useState(false);
@@ -356,12 +358,14 @@ function QuickLinks({ toast, mobile }) {
};
const del = async id => {
+ if (!await confirm('Link wirklich lรถschen?')) return;
try { await api(`/dashboard/links/${id}`, { method:'DELETE' }); setLinks(p => p.filter(l => l.id!==id)); toast('Gelรถscht'); }
catch(e) { toast(e.message, 'error'); }
};
return (
+
SCHNELLZUGRIFF
@@ -539,6 +543,64 @@ function Notepad({ toast }) {
);
}
+
+// โโ Bestell-Statistik Widget โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+function BestellStats() {
+ const [stats, setStats] = useState(null);
+ const [open, setOpen] = useState(false);
+ const [loaded, setLoaded] = useState(false);
+
+ const load = () => {
+ if (loaded) return;
+ api('/dashboard/stats').then(s => { setStats(s); setLoaded(true); }).catch(() => {});
+ };
+
+ const toggle = () => { setOpen(v => !v); if (!open) load(); };
+
+ const Row = ({label, val, color='#fff'}) => (
+
+ {label}
+ {val}
+
+ );
+
+ return (
+
+
+ {open && (
+
+ {!stats ? (
+
Lรคdtโฆ
+ ) : (
+ <>
+
+
BESTELLUNGEN
+
+
+
+
+
+
+
+
+ >
+ )}
+
+ )}
+
+ );
+}
+
function Dashboard({ toast, mobile }) {
return (
@@ -549,6 +611,7 @@ function Dashboard({ toast, mobile }) {
+
diff --git a/frontend/src/confirm.jsx b/frontend/src/confirm.jsx
new file mode 100644
index 0000000..6722f1e
--- /dev/null
+++ b/frontend/src/confirm.jsx
@@ -0,0 +1,49 @@
+// โโ Globaler Bestรคtigungs-Dialog โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+// Verwendung: const { confirm, ConfirmDialog } = useConfirm();
+// await confirm('Wirklich lรถschen?') && deleteFn();
+import { useState, useCallback } from 'react';
+
+export function useConfirm() {
+ const [state, setState] = useState({ open:false, msg:'', resolve:null });
+
+ const confirm = useCallback((msg='Wirklich fortfahren?') => {
+ return new Promise(resolve => {
+ setState({ open:true, msg, resolve });
+ });
+ }, []);
+
+ const handle = yes => {
+ state.resolve?.(yes);
+ setState({ open:false, msg:'', resolve:null });
+ };
+
+ const ConfirmDialog = () => !state.open ? null : (
+
handle(false)}>
+
e.stopPropagation()}>
+
+
{state.msg}
+
+
+
+
+
+
+ );
+
+ return { confirm, ConfirmDialog };
+}