// Lernmaterial-Verwaltung (Anlegen, Bearbeiten, Löschen) function LernmaterialCreateDialog({ accent, onClose, onSave }) { const kategorien = (window.CONSTANTS && window.CONSTANTS.LERNMATERIAL_KATEGORIEN) || []; const [name, setName] = React.useState(''); const [kategorie, setKategorie] = React.useState(kategorien[0] || ''); const [preis, setPreis] = React.useState(''); const [bestand, setBestand] = React.useState(''); const valid = name.trim() && kategorie && preis; const fieldStyle = { width: '100%', padding: '8px 11px', border: '1px solid #e2e8f0', borderRadius: 7, fontSize: 13.5, fontFamily: 'inherit', color: '#0f172a', background: '#fff', outline: 'none', }; const labelStyle = { fontSize: 11.5, color: '#475569', fontWeight: 500, marginBottom: 5, display: 'block' }; return (
Lernmaterial anlegen
Neues Material in den Bestand aufnehmen.
setName(e.target.value)} placeholder="z.B. Hausaufgabenhefter A5" style={fieldStyle} />
setPreis(e.target.value)} placeholder="2.50" style={{ ...fieldStyle, fontFamily: 'JetBrains Mono, monospace' }} />
setBestand(e.target.value)} placeholder="100" style={{ ...fieldStyle, fontFamily: 'JetBrains Mono, monospace' }} />
Abbrechen onSave({ name, kategorie, preis, bestand })}> Anlegen
); } function LernmaterialEditDialog({ accent, item, onClose, onSave }) { const kategorien = (window.CONSTANTS && window.CONSTANTS.LERNMATERIAL_KATEGORIEN) || []; const [name, setName] = React.useState(item.name || ''); const [kategorie, setKategorie] = React.useState(item.kategorie || (kategorien[0] || '')); const [preis, setPreis] = React.useState(item.preis_cents ? (item.preis_cents / 100).toFixed(2) : ''); const [bestand, setBestand] = React.useState(item.bestand_gesamt != null ? String(item.bestand_gesamt) : ''); const valid = name.trim() && kategorie && preis; const fieldStyle = { width: '100%', padding: '8px 11px', border: '1px solid #e2e8f0', borderRadius: 7, fontSize: 13.5, fontFamily: 'inherit', color: '#0f172a', background: '#fff', outline: 'none', }; const labelStyle = { fontSize: 11.5, color: '#475569', fontWeight: 500, marginBottom: 5, display: 'block' }; return (
Lernmaterial bearbeiten
{item.id}
setName(e.target.value)} style={fieldStyle} />
setPreis(e.target.value)} style={{ ...fieldStyle, fontFamily: 'JetBrains Mono, monospace' }} />
setBestand(e.target.value)} style={{ ...fieldStyle, fontFamily: 'JetBrains Mono, monospace' }} />
Abbrechen onSave({ name, kategorie, preis, bestand })}> Speichern
); } window.LernmaterialListe = function LernmaterialListe({ accent }) { const [items, setItems] = React.useState([]); const [total, setTotal] = React.useState(0); const [query, setQuery] = React.useState(''); const [showCreate, setShowCreate] = React.useState(false); const [editingItem, setEditingItem] = React.useState(null); const [confirmDelete, setConfirmDelete] = React.useState(null); function fetchAll() { window.api.lernmaterial.list({ q: query }).then(res => { setItems(res.items || []); setTotal(res.total || 0); }).catch(err => { console.error(err); setItems([]); setTotal(0); }); } React.useEffect(() => { fetchAll(); }, [query]); function addItem(data) { window.api.lernmaterial.create({ name: data.name, kategorie: data.kategorie, preis_cents: Math.round(parseFloat(data.preis) * 100), bestand_gesamt: parseInt(data.bestand, 10) || 0, }).then(() => { setShowCreate(false); fetchAll(); window.showToast('success', `„${data.name}" wurde angelegt.`); }).catch(err => { console.error(err); window.showToast('error', err.message || 'Fehler beim Anlegen.'); }); } function saveItem(id, data) { window.api.lernmaterial.update(id, { name: data.name, kategorie: data.kategorie, preis_cents: Math.round(parseFloat(data.preis) * 100), bestand_gesamt: parseInt(data.bestand, 10) || 0, }).then(() => { setEditingItem(null); fetchAll(); window.showToast('success', `„${data.name}" wurde aktualisiert.`); }).catch(err => { console.error(err); window.showToast('error', err.message || 'Fehler beim Speichern.'); }); } function removeItem(id) { const name = confirmDelete ? confirmDelete.name : 'Material'; window.api.lernmaterial.remove(id).then(() => { setConfirmDelete(null); fetchAll(); window.showToast('success', `„${name}" wurde entfernt.`); }).catch(err => { console.error(err); window.showToast('error', err.message || 'Fehler beim Entfernen.'); }); } const KATEGORIE_FARBEN = { 'Hefter': 210, 'Taschenrechner': 160, 'Formelsammlung': 280, 'Lineal': 40, 'Zirkel': 20, 'Tintenkiller': 330, 'Sonstiges': 0, }; function kategorieHue(kat) { return (KATEGORIE_FARBEN[kat] != null ? KATEGORIE_FARBEN[kat] : (kat.charCodeAt(0) * 7) % 360); } return (

Lernmaterial

{total} Artikel im Bestand
setShowCreate(true)}>Material anlegen
Bezeichnung
Kategorie
Preis
Bestand
{items.length === 0 ? (
{query ? 'Keine passenden Artikel gefunden.' : 'Noch kein Lernmaterial angelegt.'}
) : items.map((item, index) => { const hue = kategorieHue(item.kategorie); return (
{item.name}
{item.id}
{item.kategorie}
{(item.preis_cents / 100).toFixed(2).replace('.', ',')} €
{item.bestand_frei}/{item.bestand_gesamt}
); })}
{showCreate && ( setShowCreate(false)} onSave={addItem} /> )} {editingItem && ( setEditingItem(null)} onSave={(data) => saveItem(editingItem.id, data)} /> )} {confirmDelete && ( Möchten Sie {confirmDelete.name} ({confirmDelete.id}) wirklich entfernen?} confirmLabel="Endgültig entfernen" accent={accent} onCancel={() => setConfirmDelete(null)} onConfirm={() => removeItem(confirmDelete.id)} /> )}
); };