Kundenansicht: Toggle „Deaktivierte Verträge anzeigen"

Der Vertragsbaum beim Kunden blendete DEACTIVATED-Verträge
komplett aus. Da der aktuellste Vertrag die Baumwurzel ist und
Vorgänger als Children hängen, verschwand eine ganze Kette aus
der Ansicht, sobald die Wurzel deaktiviert wurde – so „verschwand"
ein Vertrag scheinbar, als ein aktiver Folgevertrag gelöscht und
der Vorgänger vorher deaktiviert worden war.

getContractTreeForCustomer bekommt ein optionales
includeDeactivated-Flag (Default false = bisheriges Verhalten),
durchgereicht per Query-Param includeDeactivated=true. Toggle-
Button (Eye/EyeOff) im Kunden-Vertragstab; showDeactivated ist
Teil des Query-Keys → frischer Fetch beim Umschalten. Deaktivierte
behalten ihr graues DEACTIVATED-Badge.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 21:45:58 +02:00
co-authored by Claude Opus 4.7
parent d0611b740a
commit d059912c1e
5 changed files with 52 additions and 14 deletions
@@ -1691,11 +1691,13 @@ function ContractsTab({
const queryClient = useQueryClient();
const [expandedContracts, setExpandedContracts] = useState<Set<number>>(new Set());
const [showStatusInfo, setShowStatusInfo] = useState(false);
const [showDeactivated, setShowDeactivated] = useState(false);
// Lade Vertragsbaum statt flacher Liste
// Lade Vertragsbaum statt flacher Liste. showDeactivated ist Teil des
// Query-Keys, damit der Toggle einen frischen Fetch auslöst.
const { data: treeData, isLoading } = useQuery({
queryKey: ['contract-tree', customerId],
queryFn: () => contractApi.getTreeForCustomer(customerId),
queryKey: ['contract-tree', customerId, showDeactivated],
queryFn: () => contractApi.getTreeForCustomer(customerId, showDeactivated),
});
const contractTree = treeData?.data || [];
@@ -1898,16 +1900,25 @@ function ContractsTab({
return (
<div>
{hasPermission('contracts:create') && (
<div className="mb-4">
<div className="mb-4 flex items-center justify-between gap-3 flex-wrap">
{hasPermission('contracts:create') ? (
<Link to={`/contracts/new?customerId=${customerId}`}>
<Button size="sm">
<Plus className="w-4 h-4 mr-2" />
Vertrag anlegen
</Button>
</Link>
</div>
)}
) : <span />}
<Button
size="sm"
variant={showDeactivated ? 'secondary' : 'ghost'}
onClick={() => setShowDeactivated((v) => !v)}
title="Deaktivierte Verträge in der Liste ein-/ausblenden"
>
{showDeactivated ? <EyeOff className="w-4 h-4 mr-2" /> : <Eye className="w-4 h-4 mr-2" />}
{showDeactivated ? 'Deaktivierte ausblenden' : 'Deaktivierte anzeigen'}
</Button>
</div>
{contractTree.length > 0 ? (
<div className="space-y-4">
+4 -2
View File
@@ -815,8 +815,10 @@ export const contractApi = {
const res = await api.get<ApiResponse<Contract[]>>('/contracts', { params });
return res.data;
},
getTreeForCustomer: async (customerId: number) => {
const res = await api.get<ApiResponse<ContractTreeNode[]>>('/contracts', { params: { customerId, tree: 'true' } });
getTreeForCustomer: async (customerId: number, includeDeactivated = false) => {
const res = await api.get<ApiResponse<ContractTreeNode[]>>('/contracts', {
params: { customerId, tree: 'true', ...(includeDeactivated ? { includeDeactivated: 'true' } : {}) },
});
return res.data;
},
getById: async (id: number) => {