/** * AdminMandatesPage * * Admin page for managing Mandates (tenants) using FormGeneratorTable. */ import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useAdminMandates, useMandateFormAttributes, type Mandate } from '../../hooks/useMandates'; import { useApiRequest } from '../../hooks/useApi'; import { fetchSettingsAdmin, updateSettingsAdmin } from '../../api/billingApi'; import { mergeBillingIntoMandateFormData, splitMandateAndBillingFromForm, } from '../../utils/mandateBillingFormMerge'; import { useToast } from '../../contexts/ToastContext'; import { FormGeneratorTable } from '../../components/FormGenerator/FormGeneratorTable'; import { FormGeneratorForm } from '../../components/FormGenerator/FormGeneratorForm'; import { FaPlus, FaSync, FaBuilding, FaUsers, FaLock } from 'react-icons/fa'; import styles from './Admin.module.css'; export const AdminMandatesPage: React.FC = () => { const navigate = useNavigate(); const { request } = useApiRequest(); const { showWarning, showSuccess } = useToast(); const { mandates, columns, permissions, pagination, loading, error, refetch, fetchMandateById, handleCreate, handleUpdate, handleDelete, handleInlineUpdate, updateOptimistically, } = useAdminMandates(); const { formAttributes, createFormAttributes, formAttributesWithBilling, createFormAttributesWithBilling, loading: mandateAttrsLoading, } = useMandateFormAttributes(); const [showCreateModal, setShowCreateModal] = useState(false); /** Mandate row merged with billing fields for FormGenerator */ const [editingFormData, setEditingFormData] = useState | null>(null); const [editingBillingWarning, setEditingBillingWarning] = useState(null); // Check if user can create const canCreate = permissions?.create !== 'n'; const canUpdate = permissions?.update !== 'n'; const canDelete = permissions?.delete !== 'n'; // Handle edit click — load mandate + billing settings (separate persistence) const handleEditClick = async (mandate: Mandate) => { setEditingBillingWarning(null); const fullMandate = await fetchMandateById(mandate.id); if (!fullMandate) return; try { const settings = await fetchSettingsAdmin(request, fullMandate.id); setEditingFormData( mergeBillingIntoMandateFormData(fullMandate as Record, settings) ); } catch { setEditingFormData(mergeBillingIntoMandateFormData(fullMandate as Record, null)); setEditingBillingWarning( 'Abrechnungseinstellungen konnten nicht geladen werden. Nur Mandantendaten sind sicher bearbeitbar.' ); } }; // Handle create submit — POST mandate, then billing settings const handleCreateSubmit = async (data: Record) => { const { mandatePayload, billingUpdate } = splitMandateAndBillingFromForm(data); const created = await handleCreate(mandatePayload as Partial); if (!created?.id) return; try { await updateSettingsAdmin(request, created.id, billingUpdate); showSuccess('Erstellt', 'Mandant inkl. Abrechnungseinstellungen gespeichert.'); } catch (e: unknown) { console.error(e); showWarning( 'Mandant erstellt', 'Abrechnungseinstellungen konnten nicht gespeichert werden. Bitte unter Administration → Abrechnung nachpflegen.' ); } setShowCreateModal(false); }; // Handle edit submit — PUT mandate + POST billing settings const handleEditSubmit = async (data: Record) => { if (!editingFormData?.id) return; const mandateId = String(editingFormData.id); const { mandatePayload, billingUpdate } = splitMandateAndBillingFromForm(data); const mandateOk = await handleUpdate(mandateId, mandatePayload as Partial); if (!mandateOk) return; try { await updateSettingsAdmin(request, mandateId, billingUpdate); showSuccess('Gespeichert', 'Mandant und Abrechnung aktualisiert.'); } catch (e: unknown) { console.error(e); showWarning('Teilweise gespeichert', 'Mandant gespeichert, Abrechnung konnte nicht aktualisiert werden.'); } setEditingFormData(null); setEditingBillingWarning(null); }; // Handle delete (confirmation handled by DeleteActionButton) // System mandates (isSystem=true) are protected from deletion const handleDeleteMandate = async (mandate: Mandate) => { if (mandate.isSystem) { return; // Safety guard - should not be reachable due to disabled button } await handleDelete(mandate.id); }; if (error) { return (
⚠️

Fehler beim Laden der Mandanten: {error}

); } return (

Mandanten

Verwalten Sie alle Mandanten im System

{canCreate && ( )}
{loading && mandates.length === 0 ? (
Lade Mandanten...
) : mandates.length === 0 ? (

Keine Mandanten vorhanden

Erstellen Sie einen neuen Mandanten, um loszulegen.

{canCreate && ( )}
) : ( row.isSystem ? { disabled: true, message: 'System-Mandanten können nicht gelöscht werden' } : false }] : []), ]} onDelete={handleDeleteMandate} hookData={{ refetch, permissions, pagination, handleDelete, handleInlineUpdate, updateOptimistically, }} emptyMessage="Keine Mandanten gefunden" /> )}
{/* Create Modal */} {showCreateModal && (
setShowCreateModal(false)}>
e.stopPropagation()}>

Neuer Mandant

Stammdaten kommen aus dem Modell Mandate (API). Abrechnung wird in{' '} BillingSettings pro Mandant gespeichert.

{mandateAttrsLoading || createFormAttributes.length === 0 ? (
Lade Formular...
) : ( setShowCreateModal(false)} submitButtonText="Erstellen" cancelButtonText="Abbrechen" /> )}
)} {/* Edit Modal */} {editingFormData && (
{ setEditingFormData(null); setEditingBillingWarning(null); }} >
e.stopPropagation()}>

Mandant bearbeiten

{Boolean(editingFormData.isSystem) && (
Dies ist ein System-Mandant. Er kann nicht gelöscht werden und der Name sollte nicht geändert werden.
)} {editingBillingWarning && (
{editingBillingWarning}
)} {formAttributes.length === 0 ? (
Lade Formular...
) : ( { setEditingFormData(null); setEditingBillingWarning(null); }} submitButtonText="Speichern" cancelButtonText="Abbrechen" /> )}
)}
); }; export default AdminMandatesPage;