diff --git a/backend/src/db.js b/backend/src/db.js index dfea999..3538d52 100644 --- a/backend/src/db.js +++ b/backend/src/db.js @@ -246,6 +246,11 @@ if (msgCols2.length && !msgCols2.includes('read_by_recipient')) { db.exec("ALTER TABLE messages ADD COLUMN read_by_recipient INTEGER NOT NULL DEFAULT 0"); } +// User-Preferences (JSON-Blob) +const userCols2 = db.prepare("PRAGMA table_info(users)").all().map(r => r.name); +if (!userCols2.includes('preferences')) + db.exec("ALTER TABLE users ADD COLUMN preferences TEXT DEFAULT NULL"); + // ── Login-Sicherheit ────────────────────────────────────────────────────────── // Spalten für Account-Lockout in users-Tabelle const userCols = db.prepare("PRAGMA table_info(users)").all().map(r => r.name); diff --git a/backend/src/routes/auth.js b/backend/src/routes/auth.js index ea7c230..47f03cb 100644 --- a/backend/src/routes/auth.js +++ b/backend/src/routes/auth.js @@ -150,4 +150,20 @@ router.delete('/account', authenticate, (req, res) => { res.json({ success: true }); }); +// ── GET/PUT /api/auth/preferences ───────────────────────────────────────────── +router.get('/preferences', authenticate, (req, res) => { + const user = db.prepare('SELECT preferences FROM users WHERE id=?').get(req.user.id); + try { res.json(JSON.parse(user?.preferences || '{}')); } + catch { res.json({}); } +}); + +router.put('/preferences', authenticate, (req, res) => { + const user = db.prepare('SELECT preferences FROM users WHERE id=?').get(req.user.id); + let current = {}; + try { current = JSON.parse(user?.preferences || '{}'); } catch {} + const merged = { ...current, ...req.body }; + db.prepare('UPDATE users SET preferences=? WHERE id=?').run(JSON.stringify(merged), req.user.id); + res.json(merged); +}); + module.exports = router; diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index dd783df..b138031 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1660,7 +1660,7 @@ export default function App() { const activeTool = TOOLS.find(t=>t.id===active); // Mobile padding bottom für fixed nav - const mainStyle = { flex:1, overflowY:'auto', ...(mobile ? { paddingBottom:'calc(56px + env(safe-area-inset-bottom, 0px))' } : {}) }; + const mainStyle = { flex:1, overflowY:'auto', ...(mobile ? { paddingBottom: active==='nachrichten' ? 0 : 'calc(56px + env(safe-area-inset-bottom, 0px))' } : {}) }; return( <> diff --git a/frontend/src/tools/nachrichten.jsx b/frontend/src/tools/nachrichten.jsx index d8fbbd0..608f5ae 100644 --- a/frontend/src/tools/nachrichten.jsx +++ b/frontend/src/tools/nachrichten.jsx @@ -82,8 +82,16 @@ export default function Nachrichten({ toast, mobile }) { const [text, setText] = useState(''); const [sending, setSending] = useState(false); const [showPicker, setShowPicker] = useState(false); - const [mirc, setMirc] = useState(() => localStorage.getItem('dd_chat_design') === 'mirc'); - const toggleDesign = () => setMirc(v => { const n = !v; localStorage.setItem('dd_chat_design', n ? 'mirc' : 'modern'); return n; }); + const [mirc, setMirc] = useState(false); + // Preference vom Server laden + useEffect(() => { + api('/auth/preferences').then(p => { if (p.chat_design === 'mirc') setMirc(true); }).catch(()=>{}); + }, []); + const toggleDesign = () => setMirc(v => { + const next = !v; + api('/auth/preferences', { method:'PUT', body:{ chat_design: next ? 'mirc' : 'modern' } }).catch(()=>{}); + return next; + }); const bottomRef = useRef(null); const pollRef = useRef(null); const pickerRef = useRef(null); @@ -247,12 +255,12 @@ export default function Nachrichten({ toast, mobile }) { display:'flex', alignItems:'center', justifyContent:'space-between' }}>