frontend_nyla/src/hooks/useCatalogObjects.ts
2026-01-25 03:01:07 +01:00

117 lines
3.6 KiB
TypeScript

/**
* 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<string, unknown>;
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<CatalogObjects>;
getObjectsByContext: (context: RuleContext) => CatalogObject[];
getObjectByKey: (objectKey: string) => CatalogObject | undefined;
}
// =============================================================================
// HOOK
// =============================================================================
export function useCatalogObjects(): UseCatalogObjectsReturn {
const [objects, setObjects] = useState<CatalogObjects>({ DATA: [], UI: [], RESOURCE: [] });
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(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<CatalogObjects> => {
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<CatalogObjects>(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;