diff --git a/package.json b/package.json index 80b302d..b318583 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lageplan", - "version": "1.8.1", + "version": "1.8.2", "description": "Feuerwehr Lageplan - Krokier-App für Einsatzdokumentation", "private": true, "scripts": { diff --git a/src/components/journal/module-manager-dialog.tsx b/src/components/journal/module-manager-dialog.tsx index 3090c30..111ecc0 100644 --- a/src/components/journal/module-manager-dialog.tsx +++ b/src/components/journal/module-manager-dialog.tsx @@ -8,7 +8,7 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from '@/components/ui/dialog' import { - ArrowUp, ArrowDown, Plus, Trash2, Loader2, Blocks, X, + ArrowUp, ArrowDown, Plus, Trash2, Loader2, Blocks, X, Pencil, PanelLeft, Columns2, Check, } from 'lucide-react' import { MODULE_PRESETS, type CockpitModule, type ModuleColumn, type ModuleColumnType } from '@/lib/modules' @@ -30,10 +30,12 @@ export function ModuleManagerDialog({ open, onOpenChange, modules, onSaved }: Mo const [isSaving, setIsSaving] = useState(false) const [error, setError] = useState('') - // Neues Modul aus Vorlage + // Neues Modul aus Vorlage / Bearbeiten const [showAdd, setShowAdd] = useState(false) + const [editId, setEditId] = useState(null) // null = neu, sonst Modul-ID const [presetKey, setPresetKey] = useState(MODULE_PRESETS[0].key) const [newName, setNewName] = useState('') + const [newSlot, setNewSlot] = useState<'main' | 'side'>(MODULE_PRESETS[0].slot) const [newColumns, setNewColumns] = useState(MODULE_PRESETS[0].columns) useEffect(() => { @@ -41,6 +43,7 @@ export function ModuleManagerDialog({ open, onOpenChange, modules, onSaved }: Mo setWorking(modules) setError('') setShowAdd(false) + setEditId(null) } }, [open, modules]) @@ -64,25 +67,49 @@ export function ModuleManagerDialog({ open, onOpenChange, modules, onSaved }: Mo const preset = MODULE_PRESETS.find(p => p.key === key)! setPresetKey(key) setNewName(preset.key === 'leer' ? '' : preset.name) + setNewSlot(preset.slot) setNewColumns(preset.columns) } + const openNew = () => { + setEditId(null) + selectPreset(MODULE_PRESETS[0].key) + setShowAdd(true) + } + + const openEdit = (m: CockpitModule) => { + setEditId(m.id) + setNewName(m.name) + setNewSlot(m.slot) + const cols: ModuleColumn[] = m.columns && m.columns.length ? m.columns : [{ key: 'text', label: 'Text', type: 'text' }] + setNewColumns(cols.map(c => ({ ...c }))) + setShowAdd(true) + } + const addModule = () => { const preset = MODULE_PRESETS.find(p => p.key === presetKey)! const name = newName.trim() || preset.name - const mod: CockpitModule = { - id: `custom-${Date.now().toString(36)}`, - type: 'table', - name, - icon: preset.icon, - slot: preset.slot, - enabled: true, - sortOrder: working.length, - columns: newColumns.filter(c => c.label.trim()), + const columns = newColumns.filter(c => c.label.trim()) + if (columns.length === 0) return + + if (editId) { + // Bestehendes Modul aktualisieren (Name/Slot/Spalten) + setWorking(prev => prev.map(m => m.id === editId ? { ...m, name, slot: newSlot, columns } : m)) + } else { + const mod: CockpitModule = { + id: `custom-${Date.now().toString(36)}`, + type: 'table', + name, + icon: preset.icon, + slot: newSlot, + enabled: true, + sortOrder: working.length, + columns, + } + setWorking(prev => [...prev, mod]) } - if (!mod.columns || mod.columns.length === 0) return - setWorking(prev => [...prev, mod]) setShowAdd(false) + setEditId(null) setNewName('') } @@ -121,6 +148,7 @@ export function ModuleManagerDialog({ open, onOpenChange, modules, onSaved }: Mo const COLUMN_TYPES: { value: ModuleColumnType; label: string }[] = [ { value: 'text', label: 'Text' }, + { value: 'number', label: 'Zahl' }, { value: 'check', label: 'Haken' }, { value: 'time', label: 'Zeit (auto)' }, ] @@ -167,6 +195,11 @@ export function ModuleManagerDialog({ open, onOpenChange, modules, onSaved }: Mo + {m.type === 'table' && ( + + )} {m.type === 'table' && ( ) : (
-

Neues Modul

- +

{editId ? 'Modul bearbeiten' : 'Neues Modul'}

+
- {/* Vorlagen */} -
- {MODULE_PRESETS.map(p => ( - - ))} -
+ {/* Vorlagen — nur beim Neuanlegen */} + {!editId && ( +
+ {MODULE_PRESETS.map(p => ( + + ))} +
+ )}
setNewName(e.target.value)} placeholder="z.B. Atemschutz Zug 1" className="h-8 text-sm" />
+ {/* Anzeige-Bereich (Slot) frei wählbar */} +
+ +
+ + +
+
+ {/* Spalten-Editor */}
@@ -242,7 +298,7 @@ export function ModuleManagerDialog({ open, onOpenChange, modules, onSaved }: Mo
)} diff --git a/src/components/journal/modules/table-module.tsx b/src/components/journal/modules/table-module.tsx index 4376ec2..4e053f4 100644 --- a/src/components/journal/modules/table-module.tsx +++ b/src/components/journal/modules/table-module.tsx @@ -35,7 +35,8 @@ export function TableModule({ projectId, module, canEdit, notifyChanged }: Table const [draft, setDraft] = useState>({}) const columns: ModuleColumn[] = module.columns || [] - const textColumns = columns.filter(c => c.type === 'text') + // Eingebbare Spalten: Text UND Zahl (Zeit = auto, Haken = Klick) + const textColumns = columns.filter(c => c.type === 'text' || c.type === 'number') const load = useCallback(async () => { try { @@ -116,7 +117,7 @@ export function TableModule({ projectId, module, canEdit, notifyChanged }: Table // Grid-Template aus Spalten ableiten (+ Lösch-Spalte) const gridCols = columns.map(c => - c.type === 'check' ? '32px' : c.type === 'time' ? '52px' : 'minmax(0,1fr)' + c.type === 'check' ? '32px' : c.type === 'time' ? '52px' : c.type === 'number' ? 'minmax(0,0.6fr)' : 'minmax(0,1fr)' ).join(' ') + (canEdit ? ' 24px' : '') return ( @@ -167,6 +168,13 @@ export function TableModule({ projectId, module, canEdit, notifyChanged }: Table ) } + if (c.type === 'number') { + return ( +
+ {item.data[c.key] || } +
+ ) + } return (
{item.data[c.key] || } @@ -193,10 +201,11 @@ export function TableModule({ projectId, module, canEdit, notifyChanged }: Table setDraft(prev => ({ ...prev, [c.key]: e.target.value }))} onKeyDown={(e) => e.key === 'Enter' && addRow()} - className={`h-6 text-[11px] ${i === 0 ? 'flex-1 min-w-0' : 'w-20 shrink-0'}`} + className={`h-6 text-[11px] ${i === 0 && c.type !== 'number' ? 'flex-1 min-w-0' : 'w-20 shrink-0'}`} /> ))}