/** * useCatalogObjects Hook * * Fetches RBAC catalog objects (DATA, UI, RESOURCE) from the backend. * Used by AccessRulesEditor to populate object selection dropdowns. */ import { useState, useCallback } from 'react'; import api from '../api'; import { type RuleContext } from './useAccessRules'; // ============================================================================= // TYPES // ============================================================================= export interface CatalogObject { objectKey: string; featureCode: string; label: { [lang: string]: string }; meta?: Record; type: RuleContext; } export interface CatalogObjects { DATA: CatalogObject[]; UI: CatalogObject[]; RESOURCE: CatalogObject[]; } interface UseCatalogObjectsReturn { objects: CatalogObjects; loading: boolean; error: string | null; fetchObjects: (context?: RuleContext, featureCode?: string, mandateId?: string) => Promise; getObjectsByContext: (context: RuleContext) => CatalogObject[]; getObjectByKey: (objectKey: string) => CatalogObject | undefined; } // ============================================================================= // HOOK // ============================================================================= export function useCatalogObjects(): UseCatalogObjectsReturn { const [objects, setObjects] = useState({ DATA: [], UI: [], RESOURCE: [] }); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); /** * Fetch catalog objects from the backend. * * @param context - Optional filter by context type (DATA, UI, RESOURCE) * @param featureCode - Optional filter by feature code * @param mandateId - Optional filter by mandate's active features */ const fetchObjects = useCallback(async ( context?: RuleContext, featureCode?: string, mandateId?: string ): Promise => { setLoading(true); setError(null); try { const params = new URLSearchParams(); if (context) params.append('context', context); if (featureCode) params.append('featureCode', featureCode); if (mandateId) params.append('mandateId', mandateId); const url = `/api/rbac/catalog/objects${params.toString() ? `?${params}` : ''}`; const response = await api.get(url); // Normalize response structure const data: CatalogObjects = { DATA: response.data.DATA || [], UI: response.data.UI || [], RESOURCE: response.data.RESOURCE || [], }; setObjects(data); return data; } catch (err: unknown) { const errorMsg = err instanceof Error ? err.message : (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail || 'Fehler beim Laden der Katalog-Objekte'; setError(errorMsg); return { DATA: [], UI: [], RESOURCE: [] }; } finally { setLoading(false); } }, []); /** * Get objects filtered by context. */ const getObjectsByContext = useCallback((context: RuleContext): CatalogObject[] => { return objects[context] || []; }, [objects]); /** * Get a specific object by its key. */ const getObjectByKey = useCallback((objectKey: string): CatalogObject | undefined => { const allObjects = [...objects.DATA, ...objects.UI, ...objects.RESOURCE]; return allObjects.find(obj => obj.objectKey === objectKey); }, [objects]); return { objects, loading, error, fetchObjects, getObjectsByContext, getObjectByKey, }; } export default useCatalogObjects;