Dateien nach "frontend/src/tools" hochladen
This commit is contained in:
@@ -109,54 +109,33 @@ function BestellungDetail({ id, toast, onBack }) {
|
|||||||
|
|
||||||
if (loading) return <div style={{padding:24,color:'rgba(255,255,255,0.3)',fontFamily:'monospace'}}>Lädt…</div>;
|
if (loading) return <div style={{padding:24,color:'rgba(255,255,255,0.3)',fontFamily:'monospace'}}>Lädt…</div>;
|
||||||
|
|
||||||
|
// 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 (
|
return (
|
||||||
<div style={{ padding:'14px 14px 90px', maxWidth:860 }}>
|
<div style={{ padding:'14px 14px 90px', maxWidth:860 }}>
|
||||||
<ConfirmDialog/>
|
<ConfirmDialog/>
|
||||||
{/* Header */}
|
|
||||||
<div style={{ display:'flex', alignItems:'center', gap:10, marginBottom:16 }}>
|
{/* Header – nur Zurück, Titel, Status, Edit */}
|
||||||
|
<div style={{ display:'flex', alignItems:'center', gap:10, marginBottom:12 }}>
|
||||||
<button onClick={() => onBack(null)} style={{ background:'transparent', border:'none', cursor:'pointer', padding:4 }}>
|
<button onClick={() => onBack(null)} style={{ background:'transparent', border:'none', cursor:'pointer', padding:4 }}>
|
||||||
<ChevronIcon size={20} color="rgba(255,255,255,0.5)" dir="left"/>
|
<ChevronIcon size={20} color="rgba(255,255,255,0.5)" dir="left"/>
|
||||||
</button>
|
</button>
|
||||||
<h1 style={{ color:'#fff', fontFamily:"'Space Mono',monospace", fontSize:18, flex:1, margin:0 }}>
|
<h1 style={{ color:'#fff', fontFamily:"'Space Mono',monospace", fontSize:18, flex:1, margin:0, minWidth:0,
|
||||||
|
overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>
|
||||||
{id ? (editMode?'Bearbeiten':order?.name) : 'Neue Bestellung'}
|
{id ? (editMode?'Bearbeiten':order?.name) : 'Neue Bestellung'}
|
||||||
</h1>
|
</h1>
|
||||||
{order && !editMode && <StatusBadge status={order.status} onClick={cycleOrderStatus}/>}
|
{order && !editMode && !order.bezahlt && (
|
||||||
{order && !editMode && (
|
<StatusBadge status={order.status} onClick={cycleOrderStatus}/>
|
||||||
<div style={{...S.card,marginBottom:10,padding:'10px 14px',
|
|
||||||
border:`1px solid ${order.bezahlt?'rgba(192,132,252,0.25)':'rgba(255,255,255,0.06)'}`,
|
|
||||||
background:order.bezahlt?'rgba(192,132,252,0.06)':'rgba(255,255,255,0.02)',
|
|
||||||
display:'flex',flexDirection:'column',gap:8}}>
|
|
||||||
<button
|
|
||||||
onClick={()=>api(`/tools/bestellungen/${id}`,{method:'PUT',body:{bezahlt:!order.bezahlt}}).then(u=>{setOrder(u);toast(u.bezahlt?'Als bezahlt markiert':'Bezahlung aufgehoben');})}
|
|
||||||
style={{
|
|
||||||
alignSelf:'flex-start',
|
|
||||||
background: order.bezahlt ? BEZAHLT.bg : 'rgba(255,255,255,0.05)',
|
|
||||||
border:`1px solid ${order.bezahlt ? BEZAHLT.color+'55' : 'rgba(255,255,255,0.15)'}`,
|
|
||||||
borderRadius:20, padding:'5px 14px',
|
|
||||||
color: order.bezahlt ? BEZAHLT.color : 'rgba(255,255,255,0.45)',
|
|
||||||
fontFamily:'monospace', fontSize:11, cursor:'pointer',
|
|
||||||
}}>
|
|
||||||
{order.bezahlt ? '💜 Als bezahlt markiert' : '○ Als bezahlt markieren'}
|
|
||||||
</button>
|
|
||||||
{order.bezahlt && (
|
|
||||||
<div style={{color:'rgba(192,132,252,0.7)',fontFamily:'monospace',fontSize:11}}>
|
|
||||||
🔒 Bezahlte Bestellungen können nicht bearbeitet werden.
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{order && !editMode && (
|
|
||||||
<button
|
|
||||||
onClick={()=>api(`/tools/bestellungen/${id}`,{method:'PUT',body:{bezahlt:!order.bezahlt}}).then(u=>{setOrder(u);toast(u.bezahlt?'Als bezahlt markiert':'Bezahlung aufgehoben');})}
|
|
||||||
style={{
|
|
||||||
background: order.bezahlt ? BEZAHLT.bg : 'rgba(255,255,255,0.05)',
|
|
||||||
border:`1px solid ${order.bezahlt ? BEZAHLT.color+'55' : 'rgba(255,255,255,0.1)'}`,
|
|
||||||
borderRadius:20, padding:'4px 12px',
|
|
||||||
color: order.bezahlt ? BEZAHLT.color : 'rgba(255,255,255,0.4)',
|
|
||||||
fontFamily:'monospace', fontSize:10, cursor:'pointer', whiteSpace:'nowrap',
|
|
||||||
}}>
|
|
||||||
{order.bezahlt ? '💜 Bezahlt' : '○ Bezahlen'}
|
|
||||||
</button>
|
|
||||||
)}
|
)}
|
||||||
{order && !editMode && !order.bezahlt && (
|
{order && !editMode && !order.bezahlt && (
|
||||||
<button onClick={()=>setEditMode(true)} style={{background:'transparent',border:'none',cursor:'pointer',padding:4}}>
|
<button onClick={()=>setEditMode(true)} style={{background:'transparent',border:'none',cursor:'pointer',padding:4}}>
|
||||||
@@ -165,6 +144,29 @@ function BestellungDetail({ id, toast, onBack }) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Bezahlt-Zeile – immer eigene Card unter dem Header */}
|
||||||
|
{order && !editMode && (
|
||||||
|
<div style={{marginBottom:12,padding:'10px 14px',
|
||||||
|
background:order.bezahlt?'rgba(192,132,252,0.07)':'rgba(255,255,255,0.02)',
|
||||||
|
border:`1px solid ${order.bezahlt?'rgba(192,132,252,0.25)':'rgba(255,255,255,0.07)'}`,
|
||||||
|
borderRadius:10}}>
|
||||||
|
<button onClick={toggleBezahlt} style={{
|
||||||
|
background:order.bezahlt?BEZAHLT.bg:'rgba(255,255,255,0.05)',
|
||||||
|
border:`1px solid ${order.bezahlt?BEZAHLT.color+'55':'rgba(255,255,255,0.12)'}`,
|
||||||
|
borderRadius:20,padding:'5px 14px',
|
||||||
|
color:order.bezahlt?BEZAHLT.color:'rgba(255,255,255,0.45)',
|
||||||
|
fontFamily:'monospace',fontSize:11,cursor:'pointer',
|
||||||
|
}}>
|
||||||
|
{order.bezahlt?'💜 Als bezahlt markiert':'○ Als bezahlt markieren'}
|
||||||
|
</button>
|
||||||
|
{order.bezahlt && (
|
||||||
|
<div style={{color:'rgba(192,132,252,0.65)',fontFamily:'monospace',fontSize:11,marginTop:8}}>
|
||||||
|
🔒 Bezahlte Bestellungen können nicht mehr bearbeitet werden.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Formular */}
|
{/* Formular */}
|
||||||
{(editMode || !id) && !order?.bezahlt && (
|
{(editMode || !id) && !order?.bezahlt && (
|
||||||
<div style={{...S.card,marginBottom:12}}>
|
<div style={{...S.card,marginBottom:12}}>
|
||||||
@@ -238,7 +240,7 @@ function BestellungDetail({ id, toast, onBack }) {
|
|||||||
<div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:8}}>
|
<div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:8}}>
|
||||||
<span style={{color:'#fff',fontFamily:'monospace',fontSize:13,flex:1}}>{item.calc_name}</span>
|
<span style={{color:'#fff',fontFamily:'monospace',fontSize:13,flex:1}}>{item.calc_name}</span>
|
||||||
<div style={{display:'flex',gap:6,alignItems:'center'}}>
|
<div style={{display:'flex',gap:6,alignItems:'center'}}>
|
||||||
<StatusBadge status={item.status||'warteliste'} onClick={order.bezahlt?undefined:()=>cycleItemStatus(item)} small/>
|
<StatusBadge status={itemDisplayStatus(item)} onClick={order.bezahlt?undefined:()=>cycleItemStatus(item)} small/>
|
||||||
{!order.bezahlt && (
|
{!order.bezahlt && (
|
||||||
<button onClick={()=>removeItem(item.id)} style={{background:'transparent',border:'none',cursor:'pointer',padding:2}}>
|
<button onClick={()=>removeItem(item.id)} style={{background:'transparent',border:'none',cursor:'pointer',padding:2}}>
|
||||||
<XIcon size={14} color="rgba(255,255,255,0.3)"/>
|
<XIcon size={14} color="rgba(255,255,255,0.3)"/>
|
||||||
@@ -264,16 +266,20 @@ function BestellungDetail({ id, toast, onBack }) {
|
|||||||
<input type="number" step="0.01" min="0"
|
<input type="number" step="0.01" min="0"
|
||||||
defaultValue={item.custom_price??''}
|
defaultValue={item.custom_price??''}
|
||||||
placeholder="–"
|
placeholder="–"
|
||||||
|
readOnly={order.bezahlt}
|
||||||
onBlur={e=>{
|
onBlur={e=>{
|
||||||
|
if (order.bezahlt) return;
|
||||||
const v = e.target.value==='' ? null : parseFloat(e.target.value);
|
const v = e.target.value==='' ? null : parseFloat(e.target.value);
|
||||||
updateItem(item.id, {custom_price:v});
|
updateItem(item.id, {custom_price:v});
|
||||||
}}
|
}}
|
||||||
style={{...S.inp,fontSize:14,padding:'8px 10px'}}/>
|
style={{...S.inp,fontSize:14,padding:'8px 10px',
|
||||||
|
opacity:order.bezahlt?0.5:1,
|
||||||
|
cursor:order.bezahlt?'not-allowed':'text'}}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Status pro Stück */}
|
{/* Status pro Stück */}
|
||||||
<div style={{marginBottom:10}}>
|
<div style={{marginBottom:10,opacity:order.bezahlt?0.5:1,pointerEvents:order.bezahlt?'none':'auto'}}>
|
||||||
<div style={{...S.head,marginBottom:6}}>STATUS PRO STÜCK</div>
|
<div style={{...S.head,marginBottom:6}}>STATUS PRO STÜCK</div>
|
||||||
<div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:6}}>
|
<div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:6}}>
|
||||||
{[
|
{[
|
||||||
|
|||||||
Reference in New Issue
Block a user