/** * FeatureInstanceWizard * * Guided flow: Create instance → Sync roles → Add users (optional). */ import React, { useState, useMemo } from 'react'; import { useFeatureAccess } from '../../../hooks/useFeatureAccess'; import { FormGeneratorForm, type AttributeDefinition } from '../../../components/FormGenerator/FormGeneratorForm'; import { useToast } from '../../../contexts/ToastContext'; import api from '../../../api'; import type { Mandate } from '../../../hooks/useUserMandates'; import type { Feature } from '../../../hooks/useFeatureAccess'; import styles from '../Admin.module.css'; import wizardStyles from './FeatureInstanceWizard.module.css'; import { useLanguage } from '../../../providers/language/LanguageContext'; function getMandateName(m: Mandate): string { if (typeof m.name === 'object') return m.name.de || m.name.en || Object.values(m.name)[0] || m.id; return m.name || m.id; } function getFeatureLabel(f: Feature): string { if (typeof f.label === 'object') return f.label.de || f.label.en || f.code; return f.label || f.code; } export interface FeatureInstanceWizardProps { mandateId: string; mandates: Mandate[]; features: Feature[]; onClose: () => void; onComplete: () => void; } const STEPS = [ { id: 'create', title: 'Instanz erstellen' }, { id: 'roles', title: 'Rollen' }, { id: 'users', title: 'Benutzer (optional)' }, ]; export const FeatureInstanceWizard: React.FC = ({ mandateId: initialMandateId, mandates, features, onClose, onComplete, }) => { const { createInstance, addUserToInstance, fetchInstanceRoles } = useFeatureAccess(); const { showSuccess, showError } = useToast(); const { t } = useLanguage(); const [step, setStep] = useState(0); const [mandateId, setMandateId] = useState(initialMandateId || ''); const [featureCode, setFeatureCode] = useState(''); const [label, setLabel] = useState(''); const [enabled, setEnabled] = useState(true); const [copyTemplateRoles, setCopyTemplateRoles] = useState(true); const [createdInstanceId, setCreatedInstanceId] = useState(null); const [submitting, setSubmitting] = useState(false); const [mandateUsers, setMandateUsers] = useState>([]); const [instanceRoles, setInstanceRoles] = useState>([]); const [selectedUserRoles, setSelectedUserRoles] = useState>([]); const featureOptions = useMemo( () => features.map((f) => ({ value: f.code, label: getFeatureLabel(f) })), [features] ); const mandateOptions = useMemo( () => mandates.map((m) => ({ value: m.id, label: getMandateName(m) })), [mandates] ); const createFields: AttributeDefinition[] = useMemo( () => [ { name: 'mandateId', label: t('featureInstanceWizard.mandant'), type: 'enum' as const, required: true, options: mandateOptions }, { name: 'featureCode', label: t('featureInstanceWizard.feature'), type: 'enum' as const, required: true, options: featureOptions }, { name: 'label', label: t('featureInstanceWizard.bezeichnung'), type: 'string' as const, required: true, editable: true }, { name: 'enabled', label: t('featureInstanceWizard.aktiv'), type: 'boolean' as const, required: false, editable: true }, ], [mandateOptions, featureOptions] ); const handleStep1Submit = async (data: { mandateId: string; featureCode: string; label: string; enabled?: boolean; }) => { setSubmitting(true); try { const result = await createInstance(data.mandateId, { featureCode: data.featureCode, label: data.label, enabled: data.enabled !== false, copyTemplateRoles: copyTemplateRoles, }); if (result.success && result.data) { setMandateId(data.mandateId); setFeatureCode(data.featureCode); setLabel(data.label); setEnabled(data.enabled !== false); setCreatedInstanceId(result.data.id); setStep(1); } else { showError('Fehler', result.error || 'Instanz konnte nicht erstellt werden'); } } finally { setSubmitting(false); } }; const handleStep2Next = async () => { if (createdInstanceId && mandateId) { setSubmitting(true); try { const [roleList, usersRes] = await Promise.all([ fetchInstanceRoles(mandateId, createdInstanceId), api.get(`/api/mandates/${mandateId}/users`), ]); setInstanceRoles(Array.isArray(roleList) ? roleList : []); const data = usersRes.data?.items || usersRes.data || []; setMandateUsers( Array.isArray(data) ? data.map((u: { userId: string; username: string; email?: string }) => ({ id: u.userId, username: u.username, email: u.email, })) : [] ); } catch { setInstanceRoles([]); setMandateUsers([]); } finally { setSubmitting(false); } } setStep(2); }; const handleStep3Complete = async () => { if (!createdInstanceId || !mandateId) { onComplete(); return; } setSubmitting(true); try { for (const { userId, roleIds } of selectedUserRoles) { if (roleIds.length > 0) { await addUserToInstance(mandateId, createdInstanceId, { userId, roleIds }); } } showSuccess('Fertig', 'Feature-Instanz wurde erstellt und Benutzer zugewiesen.'); onComplete(); } catch { showError('Fehler', 'Einige Benutzer konnten nicht zugewiesen werden.'); } finally { setSubmitting(false); } }; const handleAddUserRole = (userId: string, roleIds: string[]) => { setSelectedUserRoles((prev) => { const rest = prev.filter((p) => p.userId !== userId); if (roleIds.length === 0) return rest; return [...rest, { userId, roleIds }]; }); }; const currentStepId = STEPS[step]?.id; return (
e.stopPropagation()}>

{t('featureInstanceWizard.neueFeatureinstanz')}

{STEPS.map((s, i) => (
{i + 1}
))}
{currentStepId === 'create' && (
)} {currentStepId === 'roles' && (

Die Rollen wurden beim Erstellen der Instanz übernommen. Sie können später unter „Benutzer verwalten“ weitere Rollen synchronisieren.

)} {currentStepId === 'users' && (

Optional: Weisen Sie Benutzern Rollen zu. Sie können dies auch später in der Zugriffsverwaltung tun.

{mandateUsers.length === 0 ? (

{t('featureInstanceWizard.keineMandantenbenutzerVorhanden')}

) : (
{mandateUsers.map((u) => { const selected = selectedUserRoles.find((s) => s.userId === u.id); const roleIds = selected?.roleIds ?? []; return (
{u.username}
); })}
)}
)}
); }; export default FeatureInstanceWizard;