+
Benutzer hinzufuegen
+
+ {roles.length > 0 && (
+
+
+
+ {roles.map(role => (
+
+ ))}
+
+
+ )}
+
+
+
+
+ );
+
+ // ==========================================================================
+ // RENDER
+ // ==========================================================================
+
+ const mandateName = selectedMandate ? getMandateName(selectedMandate) : '';
+
+ return (
+
+
+
+
Einladungs-Wizard
+
Erstellen Sie mehrere Einladungen in einem Schritt
+
+
+
+ {error && (
+
+ {error}
+
+
+ )}
+ {success && (
+
+ {success}
+
+
+ )}
+
+ {step < 5 && _renderStepIndicator()}
+
+ {/* â•â•â• STEP 1: SELECT MANDATE â•â•â• */}
+ {step === 1 && (
+
+
Schritt 1: Mandant auswaehlen
+
+
+
+
+
+ )}
+
+ {/* â•â•â• STEP 2: MANDATE INVITEES â•â•â• */}
+ {step === 2 && (
+
+
+
+ Schritt 2: Benutzer fuer Mandant “{mandateName}”
+
+
+ Fuegen Sie Benutzer hinzu, die zum Mandanten eingeladen werden sollen.
+
+ {_renderInviteeList(mandateInvitees, mandateRoles, _removeMandateInvitee)}
+
+
+ {_renderAddForm(mandateInviteeForm, setMandateInviteeForm, mandateRoles, 'mandate', _addMandateInvitee)}
+
+
+
+
+
+
+
+
+
+ )}
+
+ {/* â•â•â• STEP 3: FEATURE INSTANCE (optional) â•â•â• */}
+ {step === 3 && !skipInstance && (
+
+
+
Schritt 3: Feature Instanz auswaehlen (optional)
+ {instances.length === 0 ? (
+
Keine Feature-Instanzen fuer diesen Mandanten verfuegbar.
+ ) : (
+
+ )}
+
+
+
+
+
+
+ )}
+
+ {/* â•â•â• STEP 4: INSTANCE INVITEES â•â•â• */}
+ {step === 4 && !skipInstance && selectedInstance && (
+
+
+
+ Schritt 4: Benutzer fuer Feature Instanz “{selectedInstance.label}”
+
+
+ Fuegen Sie Benutzer hinzu, die zur Feature Instanz eingeladen werden sollen.
+
+ {_renderInviteeList(instanceInvitees, instRoles, _removeInstanceInvitee)}
+
+
+ {_renderAddForm(instanceInviteeForm, setInstanceInviteeForm, instRoles, 'instance', _addInstanceInvitee)}
+
+
+
+
+
+
+ )}
+
+ {/* â•â•â• DISPATCH / SUMMARY STEP â•â•â• */}
+ {((step === 3 && skipInstance) || (step === 5 && !dispatchResults)) && (
+
+
Zusammenfassung & Versand
+
+
+ Mandant: {mandateName}
+
+
+ {mandateInvitees.length > 0 && (
+
+
Mandant-Einladungen ({mandateInvitees.length})
+ {_renderInviteeList(mandateInvitees, mandateRoles, () => {})}
+
+ )}
+
+ {!skipInstance && selectedInstance && instanceInvitees.length > 0 && (
+
+
+ Feature Instanz “{selectedInstance.label}” Einladungen ({instanceInvitees.length})
+
+ {_renderInviteeList(instanceInvitees, instRoles, () => {})}
+
+ )}
+
+
+
+ setExpiresInHours(Number(e.target.value))}
+ />
+
+
+
+
+
+
+
+ )}
+
+ {/* â•â•â• RESULTS â•â•â• */}
+ {step === 5 && dispatchResults && (
+
+
Ergebnis
+
+
+
{dispatchResults.successful}
+
Erfolgreich
+
+
+
{dispatchResults.failed}
+
Fehlgeschlagen
+
+
+
{dispatchResults.total}
+
Gesamt
+
+
+
+ {dispatchResults.results.length > 0 && (
+
+
+
+ | Benutzer |
+ Status |
+ E-Mail |
+
+
+
+ {dispatchResults.results.map((r, idx) => (
+
+ | {r.targetUsername} |
+
+
+ {r.success ? 'Erfolgreich' : r.error || 'Fehler'}
+
+ |
+
+ {r.emailSent ? 'Versendet' : '-'}
+ |
+
+ ))}
+
+
+ )}
+
+
+
+
+
+ )}
+
+ );
+};
+
+export default AdminInvitationWizardPage;
diff --git a/src/pages/admin/AdminMandateWizardPage.tsx b/src/pages/admin/AdminMandateWizardPage.tsx
new file mode 100644
index 0000000..c02dfdb
--- /dev/null
+++ b/src/pages/admin/AdminMandateWizardPage.tsx
@@ -0,0 +1,838 @@
+/**
+ * AdminMandateWizardPage (v4.0 - poweron port)
+ *
+ * 4-step wizard for mandate management:
+ * 1. Select/Create Mandate
+ * 2. Manage Mandate Users (add/remove users to/from mandate)
+ * 3. Manage Feature Instances (CRUD)
+ * 4. Manage Users per Feature Instance (CRUD + Roles)
+ */
+
+import React, { useState, useEffect, useCallback } from 'react';
+import {
+ useUserMandates,
+ type MandateUser,
+ type Mandate,
+ type Role,
+} from '../../hooks/useUserMandates';
+import {
+ useFeatureAccess,
+ type FeatureInstance,
+ type FeatureAccessUser,
+ type FeatureInstanceRole,
+ type Feature,
+} from '../../hooks/useFeatureAccess';
+import { useToast } from '../../contexts/ToastContext';
+import api from '../../api';
+import styles from './Admin.module.css';
+
+const TOTAL_STEPS = 4;
+const STEP_LABELS = ['Mandant', 'Benutzer', 'Instances', 'Feature-Benutzer'];
+
+interface RoleOption {
+ id: string;
+ roleLabel: string;
+}
+
+export const AdminMandateWizardPage: React.FC = () => {
+ const { showSuccess, showError } = useToast();
+
+ const {
+ fetchMandateUsers,
+ addUserToMandate,
+ removeUserFromMandate,
+ fetchMandates: fetchMandatesList,
+ fetchRoles: fetchMandateRolesList,
+ fetchAllUsers,
+ } = useUserMandates();
+
+ const {
+ fetchFeatures,
+ fetchInstances,
+ createInstance,
+ deleteInstance,
+ fetchInstanceUsers,
+ addUserToInstance,
+ removeUserFromInstance,
+ fetchInstanceRoles: fetchInstanceRolesList,
+ } = useFeatureAccess();
+
+ // Wizard state
+ const [step, setStep] = useState(1);
+ const [isLoading, setIsLoading] = useState(false);
+ const [error, setError] = useState