import { useConfirm } from '../confirm.jsx'; import { useState, useEffect, useMemo } from 'react'; import { api, S } from '../lib.js'; import { SearchIcon, PlusIcon, XIcon, EditIcon, TrashIcon, ChevronIcon } from '../icons.jsx'; const fmtH = h => { if (!h) return '0h'; const hh = Math.floor(h), mm = Math.round((h - hh) * 60); return mm > 0 ? `${hh}h ${mm}m` : `${hh}h`; }; 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 BEZAHLT = { color:'#c084fc', bg:'rgba(192,132,252,0.12)' }; const STATUS_KEYS = ['warteliste','in_arbeit','fertig']; const PREISE = [ { key:'freundschaft', emoji:'💖', label:'Freundschaft', c:'#ff6b9d' }, { key:'normal', emoji:'🤝', label:'Normal', c:'#4ecdc4' }, { key:'auftrag', emoji:'💼', label:'Auftrag', c:'#ffe66d' }, ]; function StatusBadge({ status, onClick, small }) { const s = STATUS[status] || STATUS.warteliste; return ( ); } // ── Bestellung Detail ───────────────────────────────────────────────────────── function BestellungDetail({ id, toast, onBack }) { const { confirm, ConfirmDialog } = useConfirm(); 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(false); const [form, setForm] = useState({ name:'', bemerkung:'', custom_price:'', status:'warteliste' }); useEffect(() => { api('/tools/kalkulator3d').then(d => setArchiv(d.own || d || [])).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); } }, [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), 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), stunden_total: items.reduce((s,i) => s + (i.stunden||0) * i.stueckzahl, 0), }; }, [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 }; if (id) { 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}); toast('Bestellung angelegt'); onBack(created.id, true); } } catch(e) { toast(e.message,'error'); } }; const addItem = async calcId => { 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 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 => { if (!await confirm('Position wirklich entfernen?')) return; try { const u = await api(`/tools/bestellungen/${id}/items/${itemId}`,{method:'DELETE'}); setOrder(u); toast('Entfernt'); } catch(e) { toast(e.message,'error'); } }; 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…
; // Status aus Stück-Zählern ableiten const itemDisplayStatus = (item) => { const f = item.qty_fertig||0, a = item.qty_in_arbeit||0; if (f >= item.stueckzahl && item.stueckzahl > 0) return 'fertig'; if (f > 0 || a > 0) return 'in_arbeit'; return 'warteliste'; }; const toggleBezahlt = () => api(`/tools/bestellungen/${id}`,{method:'PUT',body:{bezahlt:!order.bezahlt}}) .then(u=>{setOrder(u);toast(u.bezahlt?'Als bezahlt markiert':'Bezahlung aufgehoben');}); return (
{/* Header – nur Zurück, Titel, Status, Edit */}

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

{order && !editMode && !order.bezahlt && ( )} {order && !editMode && !order.bezahlt && ( )}
{/* Bezahlt-Zeile – immer eigene Card unter dem Header */} {order && !editMode && (
{!!order.bezahlt && order.bezahlt_am && ( am {new Date(order.bezahlt_am).toLocaleDateString('de-DE',{day:'2-digit',month:'2-digit',year:'numeric'})} )}
{!!order.bezahlt && (
🔒 Bearbeitung gesperrt.
)}
)} {/* Formular */} {(!id || editMode) && !order?.bezahlt && (
setForm(f=>({...f,name:e.target.value}))} placeholder="z.B. Max Mustermann" style={{...S.inp,fontSize:15}}/>