Dateien nach "frontend/src/tools" hochladen

This commit is contained in:
2026-05-26 12:53:36 +02:00
parent c315760a43
commit 52a77ad1ae

View File

@@ -440,6 +440,75 @@ function BestellungDetail({ id, toast, onBack }) {
);
}
// ── Archiv-Eintrag Modal ─────────────────────────────────────────────────────
function ArchivModal({ calcId, onClose }) {
const [item, setItem] = useState(null);
const [lightbox, setLightbox] = useState(false);
useEffect(() => {
api('/tools/kalkulator3d').then(items => {
setItem(items.find(i => i.id === calcId) || null);
}).catch(() => {});
}, [calcId]);
if (!item) return (
<div style={{position:'fixed',inset:0,background:'rgba(0,0,0,0.8)',zIndex:6000,
display:'flex',alignItems:'center',justifyContent:'center'}} onClick={onClose}>
<div style={{color:'rgba(255,255,255,0.4)',fontFamily:'monospace',fontSize:13}}>Lädt</div>
</div>
);
return (
<div style={{position:'fixed',inset:0,background:'rgba(0,0,0,0.85)',zIndex:6000,
display:'flex',alignItems:'flex-end',justifyContent:'center'}}
onClick={e=>e.target===e.currentTarget&&onClose()}>
{lightbox && <div style={{position:'fixed',inset:0,background:'rgba(0,0,0,0.95)',zIndex:7000,
display:'flex',alignItems:'center',justifyContent:'center'}} onClick={()=>setLightbox(false)}>
<img src={item.image} alt="" style={{maxWidth:'95%',maxHeight:'90vh',borderRadius:10,objectFit:'contain'}}/>
</div>}
<div style={{background:'#1a1a1e',borderRadius:'16px 16px 0 0',width:'100%',maxWidth:600,
maxHeight:'85vh',overflowY:'auto',border:'1px solid rgba(255,255,255,0.1)'}}>
<div style={{padding:'16px 16px 0'}}>
<div style={{width:36,height:4,background:'rgba(255,255,255,0.15)',borderRadius:2,margin:'0 auto 14px'}}/>
<div style={{display:'flex',justifyContent:'space-between',alignItems:'flex-start',marginBottom:12}}>
<div style={{color:'#fff',fontFamily:"'Space Mono',monospace",fontSize:15,fontWeight:700}}>{item.name}</div>
<button onClick={onClose} style={{background:'transparent',border:'none',color:'rgba(255,255,255,0.4)',
fontSize:20,cursor:'pointer',padding:'0 4px',lineHeight:1}}></button>
</div>
</div>
<div style={{padding:'0 16px 24px'}}>
{item.image && (
<img src={item.image} alt={item.name} onClick={()=>setLightbox(true)}
style={{width:'100%',maxHeight:180,objectFit:'cover',borderRadius:8,marginBottom:12,
cursor:'pointer',border:'1px solid rgba(255,255,255,0.1)'}}/>
)}
<div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:6,marginBottom:12}}>
{[['Gewicht',`${item.gramm}g`],['Dauer',`${item.stunden}h`],['Farben',item.farben]].map(([l,v])=>(
<div key={l} style={{background:'rgba(255,255,255,0.04)',borderRadius:8,padding:'8px 10px'}}>
<div style={{color:'rgba(255,255,255,0.55)',fontFamily:'monospace',fontSize:9,marginBottom:3}}>{l.toUpperCase()}</div>
<div style={{color:'#fff',fontFamily:"'Space Mono',monospace",fontSize:13,fontWeight:700}}>{v}</div>
</div>
))}
</div>
<div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:6,marginBottom:12}}>
{[['💖',item.preis_freundschaft,'#ff6b9d'],['🤝',item.preis_normal,'#4ecdc4'],['💼',item.preis_auftrag,'#ffe66d']].map(([e,v,color])=>(
<div key={e} style={{background:`${color}10`,border:`1px solid ${color}25`,borderRadius:8,padding:'8px 6px',textAlign:'center'}}>
<div style={{fontSize:14,marginBottom:3}}>{e}</div>
<div style={{color,fontFamily:"'Space Mono',monospace",fontSize:14,fontWeight:700}}>{v.toFixed(2)}</div>
</div>
))}
</div>
{item.bemerkung && (
<div style={{background:'rgba(255,255,255,0.03)',border:'1px solid rgba(255,255,255,0.07)',
borderRadius:8,padding:'10px 12px'}}>
<div style={{color:'rgba(255,255,255,0.55)',fontFamily:'monospace',fontSize:12,lineHeight:1.6}}>{item.bemerkung}</div>
</div>
)}
</div>
</div>
</div>
);
}
// ── Übersicht ─────────────────────────────────────────────────────────────────
export default function Bestellungen({ toast, mobile }) {
const { confirm, ConfirmDialog } = useConfirm();
@@ -448,8 +517,8 @@ export default function Bestellungen({ toast, mobile }) {
const [search, setSearch] = useState('');
const [filterStatus,setFilter] = useState('warteliste');
const [openId, setOpenId] = useState(null);
const [delId, setDelId] = useState(null);
const [newMode, setNewMode] = useState(false);
const [archivItem, setArchivItem] = useState(null);
const load = () => {
setLoading(true);
@@ -488,6 +557,7 @@ export default function Bestellungen({ toast, mobile }) {
return (
<div style={{padding:mobile?'14px 14px 90px':'36px 44px',maxWidth:860}}>
<ConfirmDialog/>
{archivItem && <ArchivModal calcId={archivItem} onClose={()=>setArchivItem(null)}/>}
<div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:14}}>
<h1 style={{color:'#fff',fontFamily:"'Space Mono',monospace",fontSize:mobile?18:22,margin:0}}>Bestellungen</h1>
<button onClick={()=>{setNewMode(true);setOpenId(null);}} style={{...S.btn('#4ecdc4'),display:'flex',alignItems:'center',gap:6}}>
@@ -500,7 +570,7 @@ export default function Bestellungen({ toast, mobile }) {
<span style={{position:'absolute',left:12,top:'50%',transform:'translateY(-50%)'}}>
<SearchIcon size={14} color="rgba(255,255,255,0.3)"/>
</span>
<input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Name suchen…"
<input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Name oder Modell suchen…"
style={{...S.inp,paddingLeft:34,fontSize:15}}/>
{search && <button onClick={()=>setSearch('')} style={{position:'absolute',right:10,top:'50%',transform:'translateY(-50%)',background:'transparent',border:'none',color:'rgba(255,255,255,0.6)',cursor:'pointer',fontSize:16}}></button>}
</div>
@@ -597,9 +667,19 @@ export default function Bestellungen({ toast, mobile }) {
borderBottom:'1px solid rgba(255,255,255,0.04)'}}>
{/* Status dot */}
<span style={{width:7,height:7,borderRadius:'50%',background:sc,flexShrink:0,display:'inline-block'}}/>
{/* Name */}
{/* Name klickbar wenn calculation_id vorhanden */}
{item.calculation_id ? (
<button onClick={e=>{e.stopPropagation();setArchivItem(item.calculation_id);}}
style={{background:'transparent',border:'none',cursor:'pointer',padding:0,
color:'#4ecdc4',fontFamily:'monospace',fontSize:12,flex:1,textAlign:'left',
overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap',
textDecoration:'underline',textDecorationStyle:'dotted',textUnderlineOffset:2}}>
{item.calc_name}
</button>
) : (
<span style={{color:'rgba(255,255,255,0.75)',fontFamily:'monospace',fontSize:12,flex:1,
overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{item.calc_name}</span>
)}
{/* Stückzahl */}
<span style={{color:'rgba(255,255,255,0.45)',fontFamily:'monospace',fontSize:11,flexShrink:0}}>
×{item.stueckzahl}