Dateien nach "frontend/src/tools" hochladen
This commit is contained in:
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user