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 */}
-
-