From 625efc7f184434eae00f919f6292596f090f84d3 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 6 Oct 2026 10:41:05 +0000 Subject: [PATCH] Finanzen: Rechnung schreiben auf Dialog-Baustein (breit, Enter sendet nie, Esc schliesst Liste zuerst) Co-Authored-By: Claude Sonnet 5.5 --- src/components/finance/InvoiceCreateModal.jsx | 392 ++++++++---------- src/styles/global.css | 62 +-- 2 files changed, 206 insertions(+), 248 deletions(-) diff --git a/src/components/finance/InvoiceCreateModal.jsx b/src/components/finance/InvoiceCreateModal.jsx index 9461021..44ecf91 100644 --- a/src/components/finance/InvoiceCreateModal.jsx +++ b/src/components/finance/InvoiceCreateModal.jsx @@ -1,9 +1,7 @@ import { useEffect, useMemo, useRef, useState } from 'react' -import { FaPlus, FaTrashCan, FaXmark } from 'react-icons/fa6' -import { AutocompleteInput, Button } from '../ui' +import { AutocompleteInput, Button, Dialog, Field } from '../ui' import AddressWarning from './AddressWarning' import { useCustomers } from '../../hooks/useCustomers' -import { useDialogFocus } from '../../hooks/useDialogFocus' import { useScrollIntoView } from '../../hooks/useScrollIntoView' import { createInvoice } from '../../lib/financeApi' import { canInvoice, euro } from '../../lib/financeFormat' @@ -65,10 +63,8 @@ function InvoiceForm({ onClose, onCreated, fixedCustomer, source, onShowOverview const [busy, setBusy] = useState(null) // 'draft' | 'send' const lockRef = useRef(false) const aliveRef = useRef(true) - const dialogRef = useRef(null) const errorRef = useRef(null) - const onOverlayKeyDown = useDialogFocus(dialogRef) // Der Dialog kann höher sein als das Fenster: eine Fehlermeldung oben soll nicht außerhalb des Bildes stehen useScrollIntoView(errorRef, error) @@ -79,14 +75,12 @@ function InvoiceForm({ onClose, onCreated, fixedCustomer, source, onShowOverview } }, []) - useEffect(() => { - const onKey = (e) => { - // Escape schließt auch die Kundenliste (Autovervollständigung): dann nicht den ganzen Dialog - if (e.key === 'Escape' && !e.defaultPrevented && !lockRef.current) onClose() - } - document.addEventListener('keydown', onKey) - return () => document.removeEventListener('keydown', onKey) - }, [onClose]) + // × und Esc kommen vom Dialog (er ignoriert Esc, wenn die Kundenliste die Taste schon behandelt hat, und solange `busy` gilt). + // Die Sperre deckt den Augenblick zwischen Klick und erstem Zeichnen von `busy` ab. + const close = () => { + if (lockRef.current) return + onClose() + } const options = useMemo(() => customerPickerOptions(source?.customers), [source?.customers]) const resolved = fixedCustomer @@ -144,203 +138,183 @@ function InvoiceForm({ onClose, onCreated, fixedCustomer, source, onShowOverview const disabled = busy !== null - return ( -
- -
+ + + -
-
- ) - })} -
- -
- Summe - {euro(total)} -
-
-

Gemäß § 19 UStG ohne Umsatzsteuer.

- - -
-
- - { - setDays(e.target.value) - if (error) setError('') - }} - /> -
-
- -