ui-nyla/src/pages/admin/AdminMandatesPage.tsx

260 lines
8.2 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* AdminMandatesPage
*
* Admin page for managing Mandates (tenants) using FormGeneratorTable.
*/
import React, { useState, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAdminMandates, type Mandate } from '../../hooks/useMandates';
import { FormGeneratorTable } from '../../components/FormGenerator/FormGeneratorTable';
import { FormGeneratorForm, type AttributeDefinition } from '../../components/FormGenerator/FormGeneratorForm';
import { FaPlus, FaSync, FaBuilding, FaUsers } from 'react-icons/fa';
import styles from './Admin.module.css';
export const AdminMandatesPage: React.FC = () => {
const navigate = useNavigate();
const {
mandates,
attributes,
columns,
permissions,
pagination,
loading,
error,
refetch,
fetchMandateById,
handleCreate,
handleUpdate,
handleDelete,
handleInlineUpdate,
updateOptimistically,
} = useAdminMandates();
// Form attributes from backend - filter for create/edit forms
const formAttributes: AttributeDefinition[] = useMemo(() => {
const excludedFields = ['id'];
return attributes
.filter(attr => !excludedFields.includes(attr.name))
.map(attr => ({
...attr,
type: attr.type,
})) as AttributeDefinition[];
}, [attributes]);
const [showCreateModal, setShowCreateModal] = useState(false);
const [editingMandate, setEditingMandate] = useState<Mandate | null>(null);
// Check if user can create
const canCreate = permissions?.create !== 'n';
const canUpdate = permissions?.update !== 'n';
const canDelete = permissions?.delete !== 'n';
// Handle edit click
const handleEditClick = async (mandate: Mandate) => {
const fullMandate = await fetchMandateById(mandate.id);
if (fullMandate) {
setEditingMandate(fullMandate);
}
};
// Handle create submit
const handleCreateSubmit = async (data: Partial<Mandate>) => {
const success = await handleCreate(data);
if (success) {
setShowCreateModal(false);
}
};
// Handle edit submit
const handleEditSubmit = async (data: Partial<Mandate>) => {
if (!editingMandate) return;
const success = await handleUpdate(editingMandate.id, data);
if (success) {
setEditingMandate(null);
}
};
// Handle delete (confirmation handled by DeleteActionButton)
const handleDeleteMandate = async (mandate: Mandate) => {
await handleDelete(mandate.id);
};
if (error) {
return (
<div className={styles.adminPage}>
<div className={styles.errorContainer}>
<span className={styles.errorIcon}></span>
<p className={styles.errorMessage}>Fehler beim Laden der Mandanten: {error}</p>
<button className={styles.secondaryButton} onClick={() => refetch()}>
<FaSync /> Erneut versuchen
</button>
</div>
</div>
);
}
return (
<div className={styles.adminPage}>
<div className={styles.pageHeader}>
<div>
<h1 className={styles.pageTitle}>Mandanten</h1>
<p className={styles.pageSubtitle}>Verwalten Sie alle Mandanten im System</p>
</div>
<div className={styles.headerActions}>
<button
type="button"
className={styles.secondaryButton}
onClick={() => navigate('/admin/user-mandates')}
>
<FaUsers /> Benutzer-Zuweisungen
</button>
<button
className={styles.secondaryButton}
onClick={() => refetch()}
disabled={loading}
>
<FaSync className={loading ? 'spinning' : ''} /> Aktualisieren
</button>
{canCreate && (
<button
className={styles.primaryButton}
onClick={() => setShowCreateModal(true)}
>
<FaPlus /> Neuer Mandant
</button>
)}
</div>
</div>
<div className={styles.tableContainer}>
{loading && mandates.length === 0 ? (
<div className={styles.loadingContainer}>
<div className={styles.spinner} />
<span>Lade Mandanten...</span>
</div>
) : mandates.length === 0 ? (
<div className={styles.emptyState}>
<FaBuilding className={styles.emptyIcon} />
<h3 className={styles.emptyTitle}>Keine Mandanten vorhanden</h3>
<p className={styles.emptyDescription}>
Erstellen Sie einen neuen Mandanten, um loszulegen.
</p>
{canCreate && (
<button
className={styles.primaryButton}
onClick={() => setShowCreateModal(true)}
>
<FaPlus /> Ersten Mandanten erstellen
</button>
)}
</div>
) : (
<FormGeneratorTable
data={mandates}
columns={columns}
loading={loading}
pagination={true}
pageSize={25}
searchable={true}
filterable={true}
sortable={true}
selectable={false}
actionButtons={[
...(canUpdate ? [{
type: 'edit' as const,
onAction: handleEditClick,
title: 'Bearbeiten',
}] : []),
...(canDelete ? [{
type: 'delete' as const,
title: 'Löschen',
}] : []),
]}
onDelete={handleDeleteMandate}
hookData={{
refetch,
permissions,
pagination,
handleDelete,
handleInlineUpdate,
updateOptimistically,
}}
emptyMessage="Keine Mandanten gefunden"
/>
)}
</div>
{/* Create Modal */}
{showCreateModal && (
<div className={styles.modalOverlay} onClick={() => setShowCreateModal(false)}>
<div className={styles.modal} onClick={e => e.stopPropagation()}>
<div className={styles.modalHeader}>
<h2 className={styles.modalTitle}>Neuer Mandant</h2>
<button
className={styles.modalClose}
onClick={() => setShowCreateModal(false)}
>
</button>
</div>
<div className={styles.modalContent}>
{formAttributes.length === 0 ? (
<div className={styles.loadingContainer}>
<div className={styles.spinner} />
<span>Lade Formular...</span>
</div>
) : (
<FormGeneratorForm
attributes={formAttributes}
mode="create"
onSubmit={handleCreateSubmit}
onCancel={() => setShowCreateModal(false)}
submitButtonText="Erstellen"
cancelButtonText="Abbrechen"
/>
)}
</div>
</div>
</div>
)}
{/* Edit Modal */}
{editingMandate && (
<div className={styles.modalOverlay} onClick={() => setEditingMandate(null)}>
<div className={styles.modal} onClick={e => e.stopPropagation()}>
<div className={styles.modalHeader}>
<h2 className={styles.modalTitle}>Mandant bearbeiten</h2>
<button
className={styles.modalClose}
onClick={() => setEditingMandate(null)}
>
</button>
</div>
<div className={styles.modalContent}>
{formAttributes.length === 0 ? (
<div className={styles.loadingContainer}>
<div className={styles.spinner} />
<span>Lade Formular...</span>
</div>
) : (
<FormGeneratorForm
attributes={formAttributes}
data={editingMandate}
mode="edit"
onSubmit={handleEditSubmit}
onCancel={() => setEditingMandate(null)}
submitButtonText="Speichern"
cancelButtonText="Abbrechen"
/>
)}
</div>
</div>
</div>
)}
</div>
);
};
export default AdminMandatesPage;