Dateien nach "frontend/src/tools" hochladen

This commit is contained in:
2026-05-26 01:12:40 +02:00
parent 9bf8415a43
commit 0c0ee34ede
2 changed files with 32 additions and 29 deletions

View File

@@ -1,3 +1,4 @@
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';
@@ -30,6 +31,7 @@ function StatusBadge({ status, onClick, small }) {
// ── 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([]);
@@ -85,6 +87,7 @@ function BestellungDetail({ id, toast, onBack }) {
};
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'); }
};
@@ -108,6 +111,7 @@ function BestellungDetail({ id, toast, onBack }) {
return (
<div style={{ padding:'14px 14px 90px', maxWidth:860 }}>
<ConfirmDialog/>
{/* Header */}
<div style={{ display:'flex', alignItems:'center', gap:10, marginBottom:16 }}>
<button onClick={() => onBack(null)} style={{ background:'transparent', border:'none', cursor:'pointer', padding:4 }}>
@@ -117,6 +121,13 @@ function BestellungDetail({ id, toast, onBack }) {
{id ? (editMode?'Bearbeiten':order?.name) : 'Neue Bestellung'}
</h1>
{order && !editMode && <StatusBadge status={order.status} onClick={cycleOrderStatus}/>}
{order?.bezahlt && !editMode && (
<div style={{...S.card,marginBottom:10,padding:'10px 14px',border:'1px solid rgba(192,132,252,0.2)',background:'rgba(192,132,252,0.06)'}}>
<div style={{color:'rgba(192,132,252,0.8)',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');})}
@@ -130,7 +141,7 @@ function BestellungDetail({ id, toast, onBack }) {
{order.bezahlt ? '💜 Bezahlt' : '○ Bezahlen'}
</button>
)}
{order && !editMode && (
{order && !editMode && !order.bezahlt && (
<button onClick={()=>setEditMode(true)} style={{background:'transparent',border:'none',cursor:'pointer',padding:4}}>
<EditIcon size={18} color="rgba(255,255,255,0.5)"/>
</button>
@@ -138,7 +149,7 @@ function BestellungDetail({ id, toast, onBack }) {
</div>
{/* Formular */}
{(editMode || !id) && (
{(editMode || !id) && !order?.bezahlt && (
<div style={{...S.card,marginBottom:12}}>
<div style={{marginBottom:10}}>
<label style={{...S.head,display:'block',marginBottom:4}}>NAME / PERSON</label>
@@ -190,10 +201,12 @@ function BestellungDetail({ id, toast, onBack }) {
<div style={{...S.card,marginBottom:10}}>
<div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:12}}>
<div style={S.head}>POSITIONEN</div>
{!order.bezahlt && (
<button onClick={()=>{setShowPicker(true);setPickerSearch('');}}
style={{...S.btn('#4ecdc4',true),display:'flex',alignItems:'center',gap:5}}>
<PlusIcon size={13} color="#4ecdc4"/> Hinzufügen
</button>
)}
</div>
{order.items.length===0 && (
@@ -386,6 +399,7 @@ function BestellungDetail({ id, toast, onBack }) {
// ── Übersicht ─────────────────────────────────────────────────────────────────
export default function Bestellungen({ toast, mobile }) {
const { confirm, ConfirmDialog } = useConfirm();
const [orders, setOrders] = useState([]);
const [loading, setLoading] = useState(true);
const [search, setSearch] = useState('');
@@ -401,6 +415,7 @@ export default function Bestellungen({ toast, mobile }) {
useEffect(()=>{ load(); },[]);
const del = async id => {
if (!await confirm('Bestellung wirklich löschen?')) return;
try { await api(`/tools/bestellungen/${id}`,{method:'DELETE'}); setOrders(p=>p.filter(o=>o.id!==id)); toast('Gelöscht'); }
catch(e) { toast(e.message,'error'); } finally { setDelId(null); }
};
@@ -427,6 +442,7 @@ export default function Bestellungen({ toast, mobile }) {
return (
<div style={{padding:mobile?'14px 14px 90px':'36px 44px',maxWidth:860}}>
<ConfirmDialog/>
<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}}>
@@ -522,16 +538,9 @@ export default function Bestellungen({ toast, mobile }) {
<div style={{display:'flex',gap:6,justifyContent:'flex-end'}}>
<button onClick={()=>setOpenId(order.id)} style={{...S.btn('#4ecdc4',true),flex:1,textAlign:'center'}}>Öffnen</button>
{delId===order.id?(
<div style={{display:'flex',gap:5,alignItems:'center'}}>
<button onClick={()=>del(order.id)} style={S.btn('#ff6b9d',true)}> Ja</button>
<button onClick={()=>setDelId(null)} style={S.btn('rgba(255,255,255,0.4)',true)}>Nein</button>
</div>
):(
<button onClick={()=>setDelId(order.id)} style={S.btn('#ff6b9d',true)}>
<button onClick={()=>del(order.id)} style={S.btn('#ff6b9d',true)}>
<TrashIcon size={13} color="#ff6b9d"/>
</button>
)}
</div>
</div>
);

View File

@@ -1,3 +1,4 @@
import { useConfirm } from '../confirm.jsx';
import { useState, useMemo, useEffect, useRef } from 'react';
import { api, S } from '../lib.js';
@@ -289,6 +290,7 @@ export default function Kalkulator3D({ toast, editData, onEditDone, mobile }) {
// ── Archiv ──────────────────────────────────────────────────────────────
export function SavedList({ toast, mobile }) {
const { confirm, ConfirmDialog } = useConfirm();
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
const [delId, setDelId] = useState(null);
@@ -407,18 +409,10 @@ export function SavedList({ toast, mobile }) {
</div>
{/* Aktionen */}
{delId === item.id ? (
<div style={{ display:'flex', gap:6, alignItems:'center', marginTop:8 }}>
<span style={{ color:'rgba(255,255,255,0.35)', fontSize:11, fontFamily:'monospace', flex:1 }}>Wirklich löschen?</span>
<button onClick={() => del(item.id)} style={S.btn('#ff6b9d', true)}> Ja</button>
<button onClick={() => setDelId(null)} style={S.btn('rgba(255,255,255,0.4)', true)}>Nein</button>
</div>
) : (
<div style={{ display:'flex', gap:6, marginTop:10 }}>
<button onClick={() => setEditData(item)} style={{ ...S.btn('#4ecdc4', true), flex:1, textAlign:'center' }}> Bearbeiten</button>
<button onClick={() => setDelId(item.id)} style={{ ...S.btn('#ff6b9d', true), flex:1, textAlign:'center' }}> Löschen</button>
<button onClick={() => del(item.id)} style={{ ...S.btn('#ff6b9d', true), flex:1, textAlign:'center' }}> Löschen</button>
</div>
)}
</div>
))}
</div>