From 0cd426777dd43f66caaf4551e59864ad4dd77e39 Mon Sep 17 00:00:00 2001 From: schakal00783 Date: Mon, 21 Sep 2026 18:05:25 +0200 Subject: [PATCH] feat(kunden): Filter "Inaktiv" in Kundenliste und Kundenreport Mit den 25 stillgelegten Kunden aus der Harvest-Historie war "Aktiv" oder "Alle" zu grob: wer nachsehen will, wen wir stillgelegt haben, musste ihn zwischen allen 63 suchen. Kundenliste und Kundenreport haben jetzt drei Stufen - Aktiv, Inaktiv, Alle. Im Kundenreport bleibt der gewaehlte Kunde in der Auswahl stehen, auch wenn der Filter ihn sonst ausblenden wuerde; stillgelegte sind mit "(inaktiv)" gekennzeichnet. Im Zeitreport stehen sie unter "Inaktiv" in einer eigenen Gruppe, damit sie die Auswahl nicht zuwachsen lassen - die Historie bleibt ja auswertbar. Co-Authored-By: Claude Opus 5 (1M context) --- src/components/customers/Customers.tsx | 15 +++++++-- src/components/reports/CustomerReport.tsx | 38 +++++++++++++++++------ src/components/reports/Reports.tsx | 22 ++++++++++--- 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/components/customers/Customers.tsx b/src/components/customers/Customers.tsx index 64c4d61..5edc136 100644 --- a/src/components/customers/Customers.tsx +++ b/src/components/customers/Customers.tsx @@ -17,7 +17,7 @@ export const Customers: React.FC = () => { const { navigate } = useRouter(); const { addToast } = useToast(); const [search, setSearch] = useState(''); - const [status, setStatus] = useState<'active' | 'all'>('active'); + const [status, setStatus] = useState<'active' | 'inactive' | 'all'>('active'); const [form, setForm] = useState<{ customer: Customer | null } | null>(null); const [remove, setRemove] = useState(null); const [expanded, setExpanded] = useState(null); @@ -26,7 +26,7 @@ export const Customers: React.FC = () => { const customers = useMemo(() => { const q = search.trim().toLowerCase(); return (data?.customers ?? []) - .filter((c) => (status === 'all' || c.is_active) && (!q || `${c.name} ${c.short_name} ${c.city ?? ''}`.toLowerCase().includes(q))) + .filter((c) => (status === 'all' || (status === 'inactive' ? !c.is_active : c.is_active)) && (!q || `${c.name} ${c.short_name} ${c.city ?? ''}`.toLowerCase().includes(q))) .sort((a, b) => b.earned + b.open - (a.earned + a.open) || a.name.localeCompare(b.name, 'de')); }, [data, search, status]); @@ -74,7 +74,16 @@ export const Customers: React.FC = () => { setSearch(e.target.value)} /> - + = ({ id }) => { const { navigate } = useRouter(); const customers = useLoader(() => customersApi.list(), []); const report = useLoader(() => (id ? reportsApi.customer(id) : Promise.resolve(null)), [id]); + const [status, setStatus] = useState<'active' | 'inactive' | 'all'>('active'); + + // Der gewaehlte Kunde bleibt in der Liste, auch wenn der Filter ihn sonst + // ausblenden wuerde - sonst springt die Auswahl beim Umschalten weg. + const auswahl = (customers.data ?? []).filter( + (c) => c.id === id || status === 'all' || (status === 'inactive' ? !c.is_active : c.is_active) + ); return (
- +
+ + +
{!id ? ( ) : report.error ? ( diff --git a/src/components/reports/Reports.tsx b/src/components/reports/Reports.tsx index 29c825f..d8733f9 100644 --- a/src/components/reports/Reports.tsx +++ b/src/components/reports/Reports.tsx @@ -147,11 +147,23 @@ const TimeReport: React.FC = () => { )}