diff --git a/frontend/src/tools/bestellungen.jsx b/frontend/src/tools/bestellungen.jsx index 1e6ec87..688e900 100644 --- a/frontend/src/tools/bestellungen.jsx +++ b/frontend/src/tools/bestellungen.jsx @@ -1,12 +1,13 @@ import { useState, useEffect, useMemo } from 'react'; import { api, S } from '../lib.js'; -import { SearchIcon, PlusIcon, XIcon, EditIcon, TrashIcon, CheckIcon, ChevronIcon } from '../icons.jsx'; +import { SearchIcon, PlusIcon, XIcon, EditIcon, TrashIcon, ChevronIcon } from '../icons.jsx'; const STATUS = { warteliste: { label:'Warteliste', color:'#ffe66d', bg:'rgba(255,230,109,0.12)' }, in_arbeit: { label:'In Arbeit', color:'#4ecdc4', bg:'rgba(78,205,196,0.12)' }, fertig: { label:'Fertig', color:'#6bcb77', bg:'rgba(107,203,119,0.12)' }, }; +const STATUS_KEYS = ['warteliste','in_arbeit','fertig']; const PREISE = [ { key:'freundschaft', emoji:'πŸ’–', label:'Freundschaft', c:'#ff6b9d' }, @@ -18,104 +19,105 @@ function StatusBadge({ status, onClick, small }) { const s = STATUS[status] || STATUS.warteliste; return ( ); } -// ── Bestellung Detail / Bearbeiten ──────────────────────────────────────────── -function BestellungDetail({ id, toast, onBack, onSaved }) { - const [order, setOrder] = useState(null); - const [loading, setLoading] = useState(true); - const [archiv, setArchiv] = useState([]); - const [showPicker, setShowPicker] = useState(false); - const [pickerSearch, setPickerSearch] = useState(''); - const [editMode, setEditMode] = useState(!id); // neue Bestellung direkt im Edit-Mode - const [form, setForm] = useState({ name:'', bemerkung:'', custom_price:'', status:'warteliste' }); +// ── Bestellung Detail ───────────────────────────────────────────────────────── +function BestellungDetail({ id, toast, onBack }) { + const [order, setOrder] = useState(null); + const [loading, setLoading] = useState(true); + const [archiv, setArchiv] = useState([]); + const [showPicker, setShowPicker] = useState(false); + const [pickerSearch,setPickerSearch]= useState(''); + const [editMode, setEditMode] = useState(!id); + const [form, setForm] = useState({ name:'', bemerkung:'', custom_price:'', status:'warteliste' }); useEffect(() => { - api('/tools/kalkulator3d').then(setArchiv).catch(() => {}); + api('/tools/kalkulator3d').then(setArchiv).catch(()=>{}); if (id) { api(`/tools/bestellungen/${id}`) .then(o => { setOrder(o); setForm({ name:o.name, bemerkung:o.bemerkung, custom_price:o.custom_price??'', status:o.status }); }) .catch(e => toast(e.message,'error')) .finally(() => setLoading(false)); - } else { - setLoading(false); - } + } else { setLoading(false); } }, [id]); const totals = useMemo(() => { const items = order?.items || []; return { - freundschaft: items.reduce((s,i) => s + i.preis_freundschaft * i.stueckzahl, 0), - normal: items.reduce((s,i) => s + i.preis_normal * i.stueckzahl, 0), - auftrag: items.reduce((s,i) => s + i.preis_auftrag * i.stueckzahl, 0), + freundschaft: items.reduce((s,i) => s + i.preis_freundschaft * i.stueckzahl, 0), + normal: items.reduce((s,i) => s + i.preis_normal * i.stueckzahl, 0), + auftrag: items.reduce((s,i) => s + i.preis_auftrag * i.stueckzahl, 0), + custom_sum: items.reduce((s,i) => s + (i.custom_price != null ? i.custom_price * i.stueckzahl : 0), 0), + has_any_custom: items.some(i => i.custom_price != null), }; }, [order]); const saveOrder = async () => { if (!form.name.trim()) { toast('Name erforderlich','error'); return; } try { - const payload = { ...form, custom_price: form.custom_price !== '' ? parseFloat(form.custom_price) : null }; + const payload = { ...form, custom_price: form.custom_price!=='' ? parseFloat(form.custom_price) : null }; if (id) { - const updated = await api(`/tools/bestellungen/${id}`, { method:'PUT', body:payload }); - setOrder(updated); setEditMode(false); toast('Gespeichert'); + const u = await api(`/tools/bestellungen/${id}`,{method:'PUT',body:payload}); + setOrder(u); setEditMode(false); toast('Gespeichert'); } else { - const created = await api('/tools/bestellungen', { body:payload }); + const created = await api('/tools/bestellungen',{body:payload}); toast('Bestellung angelegt'); - onSaved(created.id); + onBack(created.id); } } catch(e) { toast(e.message,'error'); } }; const addItem = async calcId => { - try { - const updated = await api(`/tools/bestellungen/${id}/items`, { body:{ calculation_id:calcId, stueckzahl:1 } }); - setOrder(updated); setShowPicker(false); toast('HinzugefΓΌgt'); - } catch(e) { toast(e.message,'error'); } + try { const u = await api(`/tools/bestellungen/${id}/items`,{body:{calculation_id:calcId,stueckzahl:1}}); setOrder(u); setShowPicker(false); toast('HinzugefΓΌgt'); } + catch(e) { toast(e.message,'error'); } }; - const updateQty = async (itemId, qty) => { - if (qty < 1) return; - try { const u = await api(`/tools/bestellungen/${id}/items/${itemId}`, { method:'PUT', body:{ stueckzahl:qty } }); setOrder(u); } + const updateItem = async (itemId, patch) => { + try { const u = await api(`/tools/bestellungen/${id}/items/${itemId}`,{method:'PUT',body:patch}); setOrder(u); } catch(e) { toast(e.message,'error'); } }; const removeItem = async itemId => { - try { const u = await api(`/tools/bestellungen/${id}/items/${itemId}`, { method:'DELETE' }); setOrder(u); toast('Entfernt'); } + try { const u = await api(`/tools/bestellungen/${id}/items/${itemId}`,{method:'DELETE'}); setOrder(u); toast('Entfernt'); } catch(e) { toast(e.message,'error'); } }; - const cycleStatus = async () => { - const states = ['warteliste','in_arbeit','fertig']; - const next = states[(states.indexOf(order.status)+1) % states.length]; - try { const u = await api(`/tools/bestellungen/${id}`, { method:'PUT', body:{...order, status:next} }); setOrder(u); } + const cycleOrderStatus = async () => { + const next = STATUS_KEYS[(STATUS_KEYS.indexOf(order.status)+1) % STATUS_KEYS.length]; + try { const u = await api(`/tools/bestellungen/${id}`,{method:'PUT',body:{...order,status:next}}); setOrder(u); } catch(e) { toast(e.message,'error'); } }; + const cycleItemStatus = item => { + const next = STATUS_KEYS[(STATUS_KEYS.indexOf(item.status||'warteliste')+1) % STATUS_KEYS.length]; + updateItem(item.id, { status: next }); + }; + const filteredArchiv = pickerSearch ? archiv.filter(a => a.name.toLowerCase().includes(pickerSearch.toLowerCase())) : archiv; - if (loading) return
LΓ€dt…
; + if (loading) return
LΓ€dt…
; return (
{/* Header */} -
-

- {id ? (editMode ? 'Bearbeiten' : order?.name) : 'Neue Bestellung'} + {id ? (editMode?'Bearbeiten':order?.name) : 'Neue Bestellung'}

- {order && !editMode && } + {order && !editMode && } {order && !editMode && ( - )} @@ -123,175 +125,202 @@ function BestellungDetail({ id, toast, onBack, onSaved }) { {/* Formular */} {(editMode || !id) && ( -
-
- +
+
+ setForm(f=>({...f,name:e.target.value}))} - placeholder="z.B. Max Mustermann" - style={{ ...S.inp, fontSize:15 }} /> + placeholder="z.B. Max Mustermann" style={{...S.inp,fontSize:15}}/>
-
- +
+