feat: CRM-Dashboard, Content-Verwaltung und Wort-Autocomplete
- Home-Seite nach Login mit Begrüßung und 3 Kacheln (Content erstellen, Content verwalten, User verwalten) - AuthContext speichert User-Profil + Rolle; AdminRoute blockt Nicht-Admins - Content verwalten (admin-only): Status-Dashboard pro Collection, Liste/Kachel-View, generisches Edit-Formular - Nur aktive db_-Collections im Dashboard (alte pictures/objects/words/questions entfernt) - Wort-Autocomplete in DrawIt: ab dem ersten Buchstaben Vorschläge aus db_words, Tastatur-Navigation, Duplikat-Filter - Backend: /users/me Proxy, db-words/search Endpoint, generische Collection-Endpoints Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import { useState, useEffect, useCallback, useRef } from 'react'
|
||||
import DrawCanvas, { type DrawCanvasHandle } from '../components/DrawCanvas'
|
||||
import BlurhashCanvas from '../components/BlurhashCanvas'
|
||||
import Topbar from '../components/Topbar'
|
||||
import WordAutocomplete from '../components/WordAutocomplete'
|
||||
import {
|
||||
getDbPictures,
|
||||
updateDbPicture,
|
||||
@@ -362,13 +363,14 @@ export default function DrawIt() {
|
||||
))}
|
||||
</div>
|
||||
<div style={{ display: 'flex', gap: 4 }}>
|
||||
<input
|
||||
type="text"
|
||||
<WordAutocomplete
|
||||
value={pictureWordInput}
|
||||
onChange={e => setPictureWordInput(e.target.value)}
|
||||
onKeyDown={e => { if (e.key === 'Enter') handleAddPictureWord() }}
|
||||
onChange={setPictureWordInput}
|
||||
onSubmit={handleAddPictureWord}
|
||||
token={token}
|
||||
placeholder="Hauptwort hinzufügen…"
|
||||
style={{ flex: 1, padding: '4px 8px', borderRadius: 'var(--r-sm)', border: '1px solid var(--border)', background: 'var(--surface-2)', color: 'var(--text-1)', fontFamily: 'var(--font)', fontSize: 12 }}
|
||||
excludeTitles={pictureWords.map(w => w.titel_de)}
|
||||
inputStyle={{ flex: 1, padding: '4px 8px', borderRadius: 'var(--r-sm)', border: '1px solid var(--border)', background: 'var(--surface-2)', color: 'var(--text-1)', fontFamily: 'var(--font)', fontSize: 12, width: '100%' }}
|
||||
/>
|
||||
<button
|
||||
onClick={handleAddPictureWord}
|
||||
@@ -654,17 +656,18 @@ export default function DrawIt() {
|
||||
|
||||
{/* Add word input */}
|
||||
<div style={{ display:'flex', gap:4 }}>
|
||||
<input
|
||||
type="text"
|
||||
<WordAutocomplete
|
||||
value={selectedObjectId ? (wordInputs[selectedObjectId] || '') : newWordInput}
|
||||
onChange={e => selectedObjectId
|
||||
? setWordInputs(prev => ({ ...prev, [selectedObjectId]: e.target.value }))
|
||||
: setNewWordInput(e.target.value)}
|
||||
onKeyDown={e => {
|
||||
if (e.key === 'Enter') selectedObjectId ? handleAddObjectWord(selectedObjectId) : handleAddPendingWord()
|
||||
}}
|
||||
onChange={v => selectedObjectId
|
||||
? setWordInputs(prev => ({ ...prev, [selectedObjectId]: v }))
|
||||
: setNewWordInput(v)}
|
||||
onSubmit={() => selectedObjectId ? handleAddObjectWord(selectedObjectId) : handleAddPendingWord()}
|
||||
token={token}
|
||||
placeholder="Wort hinzufügen…"
|
||||
style={{ flex:1, padding:'4px 8px', borderRadius:'var(--r-sm)', border:'1px solid var(--border)', background:'var(--surface-2)', color:'var(--text-1)', fontFamily:'var(--font)', fontSize:12 }}
|
||||
excludeTitles={selectedObjectId
|
||||
? (objectWords[selectedObjectId] || []).map(w => w.titel_de)
|
||||
: pendingWords}
|
||||
inputStyle={{ flex:1, padding:'4px 8px', borderRadius:'var(--r-sm)', border:'1px solid var(--border)', background:'var(--surface-2)', color:'var(--text-1)', fontFamily:'var(--font)', fontSize:12, width: '100%' }}
|
||||
/>
|
||||
<button
|
||||
onClick={() => selectedObjectId ? handleAddObjectWord(selectedObjectId) : handleAddPendingWord()}
|
||||
|
||||
Reference in New Issue
Block a user