diff --git a/src/components/legal/ContractForm.jsx b/src/components/legal/ContractForm.jsx
index cc42ba8..42c9c70 100644
--- a/src/components/legal/ContractForm.jsx
+++ b/src/components/legal/ContractForm.jsx
@@ -1,6 +1,6 @@
-import { useState } from 'react'
-import { FaTimes } from 'react-icons/fa'
-import { Button } from '../ui'
+import { useRef, useState } from 'react'
+import { useScrollIntoView } from '../../hooks/useScrollIntoView'
+import { Button, Dialog, Field } from '../ui'
const FIELDS = ['provider', 'purpose', 'cost', 'costInterval', 'startDate', 'termMonths', 'renewalMonths', 'noticeValue', 'noticeUnit', 'note']
const NUMBERS = ['termMonths', 'renewalMonths', 'noticeValue']
@@ -31,6 +31,8 @@ export default function ContractForm({ contract, onSave, onClose }) {
const [files, setFiles] = useState([])
const [saving, setSaving] = useState(false)
const [error, setError] = useState(null)
+ const errorRef = useRef(null)
+ useScrollIntoView(errorRef, error)
const set = (key) => (e) => setForm((f) => ({ ...f, [key]: e.target.value }))
const submit = async (e) => {
@@ -47,60 +49,59 @@ export default function ContractForm({ contract, onSave, onClose }) {
}
const input = (key, label, props = {}) => (
-
-
-
-
+
+
+
)
return (
-
-
-
-
{contract ? 'Vertrag bearbeiten' : 'Neuer Vertrag'}
- {error &&
{error}
}
-
+
+ {input('startDate', 'Vertragsbeginn', { type: 'date' })}
+
+ {input('termMonths', 'Laufzeit (Monate, 0 = jederzeit kündbar)', { type: 'number', min: 0 })}
+ {input('renewalMonths', 'Verlängert sich um (Monate, 0 = endet)', { type: 'number', min: 0 })}
+
+
+ {input('noticeValue', 'Kündigungsfrist', { type: 'number', min: 0 })}
+
+
+
+
+
+
+
+
+ setFiles([...e.target.files])} />
+
+
)
}
diff --git a/src/components/legal/VersionForm.jsx b/src/components/legal/VersionForm.jsx
index 21293b0..018d7b3 100644
--- a/src/components/legal/VersionForm.jsx
+++ b/src/components/legal/VersionForm.jsx
@@ -1,6 +1,6 @@
-import { useState } from 'react'
-import { FaTimes } from 'react-icons/fa'
-import { Button } from '../ui'
+import { useRef, useState } from 'react'
+import { useScrollIntoView } from '../../hooks/useScrollIntoView'
+import { Button, Dialog, Field } from '../ui'
import { todayIso } from './legalUi'
export default function VersionForm({ title, onSave, onClose }) {
@@ -8,6 +8,8 @@ export default function VersionForm({ title, onSave, onClose }) {
const [files, setFiles] = useState([])
const [saving, setSaving] = useState(false)
const [error, setError] = useState(null)
+ const errorRef = useRef(null)
+ useScrollIntoView(errorRef, error)
const set = (key) => (e) => setForm((f) => ({ ...f, [key]: e.target.value }))
const submit = async (e) => {
@@ -24,41 +26,39 @@ export default function VersionForm({ title, onSave, onClose }) {
}
return (
-
-
-
-
Neue Version: {title}
- {error &&
{error}
}
-
-
-
+
)
}
diff --git a/src/styles/global.css b/src/styles/global.css
index 65ea61f..68eba80 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -615,8 +615,8 @@ a.list-row:hover .cell-title { color: var(--accent-ink); }
.legal-files .legal-dl { color: var(--text-2); }
.legal-msg { margin: 0 0 12px; }
.legal-doc h2.section .link { white-space: nowrap; } /* "Neue Version" bleibt am Handy eine Zeile */
-.legal-error { background: var(--danger); color: #fff; padding: 8px 12px; border-radius: var(--r-sm); margin: 8px 0; }
-.legal-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
+.legal-file { padding: 2px 1px; font-size: 13px; color: var(--text-2); } /* Platz für den Ring des Knopfs, das Dateifeld schneidet ihn sonst ab */
+.legal-file::file-selector-button { height: 28px; padding: 0 10px; margin-right: 10px; border: 0; border-radius: var(--radius); background: var(--bg); box-shadow: var(--ring); font: inherit; font-weight: 500; color: var(--text); cursor: pointer; }
.legal-contracts { margin-top: var(--sp-2); }
.legal-contracts .cell-title .link { text-align: left; } /* Knopf zentriert sonst lange Anbieternamen */
.legal-contracts tr.row:has(+ .legal-detail) td { border-bottom: 0; } /* offene Zeile und Detail bilden einen Block, die Haarlinie steht darunter */