Finanzen nur noch anzeigen, Dashboard und Admin-Konfiguration entfernt (Paket D)

- Finanzen: Liste, Zahlen, PDF und Link zu InvoiceNinja bleiben. Das
  Formular "Rechnung erstellen" (auf der Seite und als "Rechnung aus
  Ticket erstellen" im Ticket) ist weg; Rechnungen entstehen direkt in
  InvoiceNinja. Das Verknüpfen von Kunden mit InvoiceNinja bleibt.
- Filter "Bezahlt" repariert: InvoiceNinja liefert status_id als Text.
- FinancePage.jsx und InvoicePanel.jsx waren Windows-1252 kodiert und
  zeigten live "�"; jetzt UTF-8, dazu Umlaute in den Texten.
- Dashboard entfernt (doppelte Finanzzahlen, "Offen" zählte falsch);
  alte Links führen zu den Tickets.
- Admin: Reiter "Konfiguration" (nur noch Prioritäten, die seit Paket B
  niemand liest) mit useAdminConfig entfernt; Admin startet bei Kunden.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-09-27 16:01:12 +00:00
1 parent 34c4db0228
commit 1a8604f7e6
12 files changed
+40 -617

No files matched your search

+3 -121
View File
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react'
import { useState } from 'react'
import {
FaFloppyDisk,
FaPlus,
@@ -11,22 +11,10 @@ import CopyableCredential, {
getCustomerPortalPassword,
} from '../components/CopyableCredential'
import { useAuth } from '../context/AuthContext'
import { useAdminConfig } from '../hooks/useAdminConfig'
import { useCustomers } from '../hooks/useCustomers'
import { useEmployees } from '../hooks/useEmployees'
import './AdminPage.css'
// Ticketarten, Systeme, Reaktions- und Leistungsarten gibt das Ticketformular
// fest vor; sie sind hier nicht mehr editierbar, bleiben beim Speichern aber
// im Config-Dokument erhalten. Editierbar sind nur noch die Prioritaeten.
const EMPTY_CONFIG = {
ticketTypes: [],
systems: [],
responseLevels: [],
serviceTypes: [],
priorities: [],
}
const EMPTY_CUSTOMER = {
code: '',
name: '',
@@ -51,7 +39,6 @@ function Notice({ notice }) {
export default function AdminPage() {
const { user, isAdmin } = useAuth()
const { config, loading, error, updateConfig } = useAdminConfig()
const {
customers,
loading: customersLoading,
@@ -68,9 +55,7 @@ export default function AdminPage() {
deleteEmployee,
} = useEmployees()
const [activeSection, setActiveSection] = useState('config')
const [localConfig, setLocalConfig] = useState(EMPTY_CONFIG)
const [savingConfig, setSavingConfig] = useState(false)
const [activeSection, setActiveSection] = useState('customers')
const [customerForm, setCustomerForm] = useState(EMPTY_CUSTOMER)
const [editingCustomer, setEditingCustomer] = useState(null)
const [customerBusy, setCustomerBusy] = useState(false)
@@ -80,12 +65,6 @@ export default function AdminPage() {
const [createdCredential, setCreatedCredential] = useState(null)
const [notice, setNotice] = useState(null)
useEffect(() => {
if (config && Object.keys(config).length > 0) {
setLocalConfig({ ...EMPTY_CONFIG, ...config })
}
}, [config])
const showNotice = (type, text) => {
setNotice({ type, text })
window.setTimeout(() => setNotice(null), 4500)
@@ -103,45 +82,6 @@ export default function AdminPage() {
)
}
const addConfigItem = (field) => {
setLocalConfig((current) => ({
...current,
[field]: [
...(current[field] || []),
field === 'priorities'
? { value: current.priorities?.length || 0, label: 'Neue Priorität' }
: '',
],
}))
}
const removeConfigItem = (field, index) => {
setLocalConfig((current) => ({
...current,
[field]: (current[field] || []).filter((_, itemIndex) => itemIndex !== index),
}))
}
const updateConfigItem = (field, index, value) => {
setLocalConfig((current) => {
const next = [...(current[field] || [])]
next[index] = value
return { ...current, [field]: next }
})
}
const saveConfiguration = async () => {
setSavingConfig(true)
const result = await updateConfig(localConfig)
setSavingConfig(false)
showNotice(
result.success ? 'success' : 'error',
result.success
? 'Konfiguration gespeichert.'
: `Speichern fehlgeschlagen: ${result.error || 'Unbekannter Fehler'}`
)
}
const resetCustomerForm = () => {
setCustomerForm(EMPTY_CUSTOMER)
setEditingCustomer(null)
@@ -261,7 +201,7 @@ export default function AdminPage() {
<div>
<span className="admin-eyebrow">Systemverwaltung</span>
<h1>Admin</h1>
<p>Konfiguration, Kundenkonten und Mitarbeiterzugänge zentral verwalten.</p>
<p>Kundenkonten und Mitarbeiterzugänge verwalten.</p>
</div>
<div className="admin-current-user">
<span>Angemeldet als</span>
@@ -270,11 +210,9 @@ export default function AdminPage() {
</header>
<Notice notice={notice} />
{error && <Notice notice={{ type: 'error', text: error }} />}
<nav className="admin-tabs" aria-label="Admin-Bereiche">
{[
['config', 'Konfiguration'],
['customers', `Kunden (${customers.length})`],
['employees', `Mitarbeiter (${employees.length})`],
].map(([id, label]) => (
@@ -289,62 +227,6 @@ export default function AdminPage() {
))}
</nav>
{activeSection === 'config' && (
<section>
{loading && !config ? (
<div className="admin-loading"><FaSpinner className="spinner" /> Konfiguration wird geladen …</div>
) : (
<>
<div className="admin-config-grid">
<section className="admin-config-card priorities">
<div className="admin-section-head">
<div><h3>Prioritäten</h3><span>{localConfig.priorities?.length || 0} Einträge</span></div>
<button type="button" className="admin-icon-button" onClick={() => addConfigItem('priorities')}>
<FaPlus /><span>Hinzufügen</span>
</button>
</div>
<div className="admin-config-list">
{(localConfig.priorities || []).map((priority, index) => (
<div className="admin-priority-row" key={`priority-${index}`}>
<input
type="number"
className="form-control"
value={priority.value}
aria-label="Prioritätswert"
onChange={(event) => updateConfigItem('priorities', index, {
...priority,
value: Number(event.target.value),
})}
/>
<input
className="form-control"
value={priority.label}
aria-label="Prioritätsname"
onChange={(event) => updateConfigItem('priorities', index, {
...priority,
label: event.target.value,
})}
/>
<button type="button" className="admin-icon-button danger" onClick={() => removeConfigItem('priorities', index)}>
<FaTrash />
</button>
</div>
))}
</div>
</section>
</div>
<div className="admin-savebar">
<span>Änderungen gelten für neue und bestehende Ticketformulare.</span>
<button type="button" className="admin-primary-button" disabled={savingConfig} onClick={saveConfiguration}>
{savingConfig ? <FaSpinner className="spin" /> : <FaFloppyDisk />}
Konfiguration speichern
</button>
</div>
</>
)}
</section>
)}
{activeSection === 'customers' && (
<section className="admin-split-layout">
<form className="admin-form-card" onSubmit={submitCustomer}>