import { useState, useEffect, useRef, useCallback } from 'react'; import { api, S } from '../lib.js'; // ── Konstanten ──────────────────────────────────────────────────────────────── const PRIORITIES = [ { id: 'none', label: 'Keine', color: '#666666' }, { id: 'low', label: 'Niedrig', color: '#4ecdc4' }, { id: 'medium', label: 'Mittel', color: '#ffe66d' }, { id: 'high', label: 'Hoch', color: '#ff6b9d' }, ]; const COL_COLORS = ['#4ecdc4','#60a5fa','#a78bfa','#ff6b9d','#ffe66d','#fb923c','#4ade80','#f472b6','#94a3b8']; const fmtCardDate = s => { if (!s) return ''; const d = new Date(String(s).replace(' ', 'T')); if (isNaN(d)) return ''; return d.toLocaleDateString('de-DE', { day:'2-digit', month:'2-digit', year:'numeric' }) + ' ' + d.toLocaleTimeString('de-DE', { hour:'2-digit', minute:'2-digit' }); }; const prioOf = id => PRIORITIES.find(p => p.id === id) || PRIORITIES[0]; // ── Karten-Modal ────────────────────────────────────────────────────────────── function CardModal({ card, columnId, columns, onSave, onClose, toast }) { const [title, setTitle] = useState(card?.title || ''); const [desc, setDesc] = useState(card?.description || ''); const [prio, setPrio] = useState(card?.priority || 'none'); const [moveToCol, setMoveToCol] = useState(card?.column_id || columnId); const [newColName, setNewColName] = useState(''); const [showNewCol, setShowNewCol] = useState(false); const [saving, setSaving] = useState(false); const titleRef = useRef(null); const newColRef = useRef(null); const isMob = window.innerWidth < 768; useEffect(() => { titleRef.current?.focus(); }, []); useEffect(() => { if (showNewCol) newColRef.current?.focus(); }, [showNewCol]); const save = async () => { if (!title.trim()) return; setSaving(true); try { // Neue Spalte anlegen wenn gewünscht let targetCol = moveToCol; if (showNewCol && newColName.trim()) { const nc = await api('/tools/kanban/columns', { body: { title: newColName.trim() } }); targetCol = nc.id; } if (card) { await api(`/tools/kanban/cards/${card.id}`, { method: 'PATCH', body: { title, description: desc, priority: prio }, }); // Spalte gewechselt? if (targetCol && targetCol !== card.column_id) { await api(`/tools/kanban/cards/${card.id}/move`, { body: { column_id: targetCol } }); } } else { await api('/tools/kanban/cards', { body: { column_id: targetCol || columnId, title, description: desc, priority: prio } }); } onSave(); } catch (e) { toast(e.message, 'error'); } finally { setSaving(false); } }; const onKey = e => { if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) save(); if (e.key === 'Escape') onClose(); }; return (
e.target === e.currentTarget && onClose()} style={{ position:'fixed',inset:0,background:'rgba(0,0,0,0.7)',zIndex:1000, display:'flex', alignItems:isMob?'flex-end':'center', justifyContent:'center', padding:isMob?0:20, // Auf Mobile: unten Platz für die fixe Bottom-Nav (56px + safe-area) lassen paddingBottom: isMob ? 'calc(56px + env(safe-area-inset-bottom, 0px))' : 20, }}>
{/* Drag-Handle + Header – immer sichtbar, nicht scrollend */}
{isMob &&
}
{card ? 'KARTE BEARBEITEN' : 'NEUE KARTE'}
{/* Scrollbarer Inhalt */}
setTitle(e.target.value)} onKeyDown={onKey} placeholder="Titel" style={{ ...S.inp, marginBottom:10 }} />