/** * TrusteePositionDocumentsView * * Verknüpfungs-Verwaltung zwischen Positionen und Dokumenten. * Verwendet FormGeneratorTable mit Spalten aus den Pydantic-Attributen. */ import React, { useState, useMemo, useEffect } from 'react'; import { useTrusteePositionDocuments, useTrusteePositionDocumentOperations, TrusteePositionDocument } from '../../../hooks/useTrustee'; import { useInstanceId } from '../../../hooks/useCurrentInstance'; import { FormGeneratorTable } from '../../../components/FormGenerator/FormGeneratorTable'; import { FormGeneratorForm } from '../../../components/FormGenerator/FormGeneratorForm'; import { FaSync } from 'react-icons/fa'; import styles from '../../admin/Admin.module.css'; import { useLanguage } from '../../../providers/language/LanguageContext'; export const TrusteePositionDocumentsView: React.FC = () => { const { t } = useLanguage(); const instanceId = useInstanceId(); // Entity hook const { positionDocuments: links, attributes, permissions, pagination, loading, error, refetch, removeOptimistically, } = useTrusteePositionDocuments(); // Operations hook const { handlePositionDocumentDelete: handleDelete, handlePositionDocumentCreate: handleCreate, deletingPositionDocuments: deletingItems, } = useTrusteePositionDocumentOperations(); // Modal state const [isCreateMode, setIsCreateMode] = useState(false); const [editingLink, setEditingLink] = useState(null); // Initial fetch useEffect(() => { if (instanceId) { refetch(); } }, [instanceId]); // Generate columns from attributes (like TrusteePositionsView) // Map frontend_options to fkSource for FK resolution const columns = useMemo(() => { if (!attributes || attributes.length === 0) return []; // Exclude system fields from table columns const excludedFields = ['id', 'mandateId', 'featureInstanceId', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt', 'sysModifiedBy']; return attributes .filter((attr: any) => !excludedFields.includes(attr.name)) .map((attr: any) => { // Replace {instanceId} placeholder in options URL let fkSource = attr.options; if (typeof fkSource === 'string' && instanceId) { fkSource = fkSource.replace('{instanceId}', instanceId); } return { key: attr.name, label: attr.label || attr.name, type: attr.type as any, sortable: attr.sortable !== false, filterable: attr.filterable !== false, searchable: attr.searchable !== false, width: attr.width || 200, minWidth: attr.minWidth || 100, maxWidth: attr.maxWidth || 400, // Use frontend_options as fkSource for FK resolution fkSource: typeof fkSource === 'string' ? fkSource : undefined, fkDisplayField: 'label', }; }); }, [attributes, instanceId]); // Check permissions (general level) // Row-level permissions are handled automatically by FormGeneratorTable const canCreate = permissions?.create !== 'n'; const canUpdate = permissions?.update !== 'n'; const canDelete = permissions?.delete !== 'n'; // Handle create click const handleCreateClick = () => { setIsCreateMode(true); }; // Handle edit click const handleEditClick = (link: TrusteePositionDocument) => { setEditingLink(link); }; // Handle create form submit const handleFormSubmit = async (data: Partial) => { const result = await handleCreate(data); if (result.success) { setIsCreateMode(false); refetch(); } }; // Handle edit form submit (position-document links are typically deleted + re-created, not updated) const handleEditSubmit = async (_data: Partial) => { setEditingLink(null); refetch(); }; // Handle delete (confirmation handled by DeleteActionButton) const handleDeleteLink = async (link: TrusteePositionDocument) => { removeOptimistically(link.id); const success = await handleDelete(link.id); if (!success) { refetch(); // Revert on error } }; // Close modal const handleCloseModal = () => { setIsCreateMode(false); }; // Form attributes (exclude system fields) const formAttributes = useMemo(() => { const excludedFields = ['id', 'mandateId', 'featureInstanceId', 'sysCreatedBy', 'sysCreatedAt', 'sysModifiedAt', 'sysModifiedBy']; return (attributes || []).filter((attr: any) => !excludedFields.includes(attr.name)); }, [attributes]); if (error) { return (
⚠️

{t('Fehler beim Laden der Verknüpfungen: {detail}', { detail: String(error) })}

); } return (

{t('trusteePositionDocuments.belegeMitBuchungspositionenVerknuepfen')}

{canCreate && ( )}
deletingItems.has(row.id), // Row-level permissions handled automatically by FormGeneratorTable }] : []), ]} onDelete={handleDeleteLink} hookData={{ refetch, permissions, pagination, handleDelete, }} emptyMessage={t('trusteePositionDocuments.keineVerknuepfungenGefunden')} />
{/* Create Modal */} {isCreateMode && (
e.stopPropagation()}>

{t('trusteePositionDocuments.neueVerknuepfungErstellen')}

{formAttributes.length === 0 ? (
{t('trusteePositionDocuments.ladeFormular')}
) : ( )}
)} {/* Edit Modal */} {editingLink && (
setEditingLink(null)}>
e.stopPropagation()}>

{t('trusteePositionDocuments.verknuepfungBearbeiten')}

{formAttributes.length === 0 ? (
{t('trusteePositionDocuments.ladeFormular')}
) : ( setEditingLink(null)} submitButtonText={t('trusteePositionDocuments.speichern')} cancelButtonText={t('trusteePositionDocuments.abbrechen')} instanceId={instanceId} /> )}
)}
); }; export default TrusteePositionDocumentsView;