diff --git a/client/src/components/Budget/BudgetPanel.tsx b/client/src/components/Budget/BudgetPanel.tsx index e1f117bc..f85f4079 100644 --- a/client/src/components/Budget/BudgetPanel.tsx +++ b/client/src/components/Budget/BudgetPanel.tsx @@ -75,9 +75,29 @@ function InlineEditCell({ value, onSave, type = 'text', style = {}, placeholder if (v !== value) onSave(v) } + const handlePaste = (e) => { + if (type !== 'number') return + e.preventDefault() + let text = e.clipboardData.getData('text').trim() + // Strip everything except digits, dots, commas, minus + text = text.replace(/[^\d.,-]/g, '') + // Remove all thousand separators (dots or commas before 3-digit groups), keep last separator as decimal + const lastComma = text.lastIndexOf(',') + const lastDot = text.lastIndexOf('.') + const decimalPos = Math.max(lastComma, lastDot) + if (decimalPos > -1) { + const intPart = text.substring(0, decimalPos).replace(/[.,]/g, '') + const decPart = text.substring(decimalPos + 1) + text = intPart + '.' + decPart + } else { + text = text.replace(/[.,]/g, '') + } + setEditValue(text) + } + if (editing) { return setEditValue(e.target.value)} onBlur={save} + onChange={e => setEditValue(e.target.value)} onBlur={save} onPaste={handlePaste} onKeyDown={e => { if (e.key === 'Enter') save(); if (e.key === 'Escape') { setEditValue(value ?? ''); setEditing(false) } }} style={{ width: '100%', border: '1px solid var(--accent)', borderRadius: 4, padding: '4px 6px', fontSize: 13, outline: 'none', background: 'var(--bg-input)', color: 'var(--text-primary)', fontFamily: 'inherit', ...style }} placeholder={placeholder} /> @@ -131,6 +151,7 @@ function AddItemRow({ onAdd, t }: AddItemRowProps) { setPrice(e.target.value)} onKeyDown={e => e.key === 'Enter' && handleAdd()} + onPaste={e => { e.preventDefault(); let t = e.clipboardData.getData('text').trim().replace(/[^\d.,-]/g, ''); const lc = t.lastIndexOf(','), ld = t.lastIndexOf('.'), dp = Math.max(lc, ld); if (dp > -1) { t = t.substring(0, dp).replace(/[.,]/g, '') + '.' + t.substring(dp + 1) } else { t = t.replace(/[.,]/g, '') } setPrice(t) }} placeholder="0,00" inputMode="decimal" style={{ ...inp, textAlign: 'center' }} /> diff --git a/client/src/components/Collab/CollabNotes.tsx b/client/src/components/Collab/CollabNotes.tsx index 3f8aef70..66a4dbd7 100644 --- a/client/src/components/Collab/CollabNotes.tsx +++ b/client/src/components/Collab/CollabNotes.tsx @@ -313,7 +313,6 @@ function NoteFormModal({ onClose, onSubmit, onDeleteFile, existingCategories, ca padding: 16, fontFamily: FONT, }} - onClick={onClose} >
{ URL.revokeObjectURL(a.href); a.remove() }, 100) +} + function formatDateWithLocale(dateStr, locale) { if (!dateStr) return '' try { @@ -113,6 +125,12 @@ function ImageLightbox({ files, initialIndex, onClose }: ImageLightboxProps) { title={t('files.openTab')}> + @@ -514,6 +532,10 @@ export default function FileManager({ files = [], onUpload, onDelete, onUpdate, onMouseEnter={e => e.currentTarget.style.color = 'var(--text-primary)'} onMouseLeave={e => e.currentTarget.style.color = 'var(--text-faint)'}> + {can('file_delete', trip) && +