fixes admin panel

This commit is contained in:
ValueOn AG 2026-02-20 23:20:20 +01:00
parent d4b2cb1dd6
commit d45dab587f
2 changed files with 26 additions and 56 deletions

View file

@ -1,4 +1,4 @@
/**
/**
* AdminInvitationWizardPage
*
* 5-step wizard for batch user invitations:
@ -13,7 +13,6 @@ import React, { useState, useEffect } from 'react';
import { useInvitations, type InvitationCreate } from '../../hooks/useInvitations';
import { useUserMandates, type Mandate, type Role } from '../../hooks/useUserMandates';
import { useFeatureAccess, type FeatureInstance, type FeatureInstanceRole } from '../../hooks/useFeatureAccess';
import { useToast } from '../../contexts/ToastContext';
import styles from './Admin.module.css';
// =============================================================================
@ -79,7 +78,6 @@ export const AdminInvitationWizardPage: React.FC = () => {
const { createInvitation } = useInvitations();
const { fetchMandates, fetchRoles } = useUserMandates();
const { fetchInstances, fetchInstanceRoles } = useFeatureAccess();
const { showError: showToastError } = useToast();
const [step, setStep] = useState(1);
const [isLoading, setIsLoading] = useState(false);

View file

@ -1,4 +1,4 @@
/**
/**
* AdminMandateWizardPage (v4.0 - poweron port)
*
* 4-step wizard for mandate management:
@ -35,7 +35,7 @@ interface RoleOption {
}
export const AdminMandateWizardPage: React.FC = () => {
const { showSuccess, showError } = useToast();
const { showSuccess } = useToast();
const {
fetchMandateUsers,
@ -66,7 +66,7 @@ export const AdminMandateWizardPage: React.FC = () => {
const [mandates, setMandates] = useState<Mandate[]>([]);
const [selectedMandate, setSelectedMandate] = useState<Record<string, any> | null>(null);
const [isCreatingMandate, setIsCreatingMandate] = useState(false);
const [mandateForm, setMandateForm] = useState({ name: '', maxInstances: 1, quotaNamesPerYear: 100 });
const [mandateForm, setMandateForm] = useState({ name: '' });
// Step 2: Mandate Users
const [mandateUsers, setMandateUsers] = useState<MandateUser[]>([]);
@ -205,8 +205,6 @@ export const AdminMandateWizardPage: React.FC = () => {
try {
const response = await api.post('/api/mandates/', {
name: mandateForm.name,
maxInstances: mandateForm.maxInstances,
quotaNamesPerYear: mandateForm.quotaNamesPerYear,
enabled: true,
});
setSelectedMandate(response.data);
@ -232,10 +230,10 @@ export const AdminMandateWizardPage: React.FC = () => {
if (result.success) {
setIsAddingMandateUser(false);
setAddMandateUserForm({ userId: '', roleIds: [] });
showSuccess('Hinzugefügt', 'Benutzer zum Mandanten hinzugefügt');
showSuccess('Hinzugefügt', 'Benutzer zum Mandanten hinzugefügt');
await loadMandateUsers();
} else {
setError(result.error || 'Fehler beim Hinzufügen');
setError(result.error || 'Fehler beim Hinzufügen');
}
} finally {
setIsLoading(false);
@ -280,10 +278,10 @@ export const AdminMandateWizardPage: React.FC = () => {
if (!selectedMandate) return;
const result = await deleteInstance(selectedMandate.id, instanceId);
if (result.success) {
showSuccess('Gelöscht', 'Instance gelöscht');
showSuccess('Gelöscht', 'Instance gelöscht');
await loadInstances();
} else {
setError(result.error || 'Fehler beim Löschen');
setError(result.error || 'Fehler beim Löschen');
}
};
@ -299,10 +297,10 @@ export const AdminMandateWizardPage: React.FC = () => {
if (result.success) {
setIsAddingInstanceUser(false);
setAddInstanceUserForm({ userId: '', roleIds: [] });
showSuccess('Hinzugefügt', 'Benutzer zur Feature-Instanz hinzugefügt');
showSuccess('Hinzugefügt', 'Benutzer zur Feature-Instanz hinzugefügt');
await loadInstanceUsers();
} else {
setError(result.error || 'Fehler beim Hinzufügen');
setError(result.error || 'Fehler beim Hinzufügen');
}
} finally {
setIsLoading(false);
@ -409,7 +407,7 @@ export const AdminMandateWizardPage: React.FC = () => {
value={formValue.userId}
onChange={e => setFormValue(p => ({ ...p, userId: e.target.value }))}
>
<option value="">-- Benutzer wählen --</option>
<option value="">-- Benutzer wählen --</option>
{availableUsers.map(u => {
const uid = u.userId || u.id || '';
const name = getUserDisplayName(u as any);
@ -447,7 +445,7 @@ export const AdminMandateWizardPage: React.FC = () => {
)}
<div style={{ display: 'flex', gap: '8px' }}>
<button className={styles.primaryButton} onClick={onSubmit} disabled={isLoading || !formValue.userId}>
{isLoading ? 'Hinzufügen...' : 'Hinzufügen'}
{isLoading ? 'Hinzufügen...' : 'Hinzufügen'}
</button>
<button className={styles.secondaryButton} onClick={onCancel}>
Abbrechen
@ -514,7 +512,7 @@ export const AdminMandateWizardPage: React.FC = () => {
<div className={styles.pageHeader}>
<div>
<h1 className={styles.pageTitle}>Mandanten-Verwaltung</h1>
<p className={styles.pageSubtitle}>Schritt-für-Schritt Wizard zur Mandanten-Konfiguration</p>
<p className={styles.pageSubtitle}>Schritt-für-Schritt Wizard zur Mandanten-Konfiguration</p>
</div>
</div>
@ -534,7 +532,7 @@ export const AdminMandateWizardPage: React.FC = () => {
{/* ═══ STEP 1: MANDATE ═══ */}
{step === 1 && (
<div style={cardStyle}>
<h3 style={{ fontSize: '15px', fontWeight: 600, marginBottom: '16px', marginTop: 0 }}>Mandant auswählen oder erstellen</h3>
<h3 style={{ fontSize: '15px', fontWeight: 600, marginBottom: '16px', marginTop: 0 }}>Mandant auswählen oder erstellen</h3>
{!isCreatingMandate ? (
<>
@ -555,9 +553,6 @@ export const AdminMandateWizardPage: React.FC = () => {
>
<div>
<div style={{ fontWeight: 600, fontSize: '14px' }}>{getMandateName(m)}</div>
<div style={{ fontSize: '12px', color: 'var(--text-secondary)' }}>
Max. {(m as any).maxInstances || '?'} Instances | Quota: {(m as any).quotaNamesPerYear || '?'} Namen/Jahr
</div>
</div>
{selectedMandate?.id === m.id && <span style={{ color: 'var(--primary-color)', fontWeight: 700, fontSize: '16px' }}>{'\u2713'}</span>}
</button>
@ -578,29 +573,6 @@ export const AdminMandateWizardPage: React.FC = () => {
placeholder="z.B. Swiss Trust AG"
/>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }}>
<div className={styles.formGroup}>
<label className={styles.formLabel}>Max. Instances</label>
<input
className={styles.formInput}
type="number"
min={1}
value={mandateForm.maxInstances}
onChange={e => setMandateForm(p => ({ ...p, maxInstances: parseInt(e.target.value) || 1 }))}
/>
<span style={{ fontSize: '11px', color: 'var(--text-secondary)' }}>1 = Einzelkunde, &gt;1 = Service Provider</span>
</div>
<div className={styles.formGroup}>
<label className={styles.formLabel}>Kontingent (Namen/Jahr)</label>
<input
className={styles.formInput}
type="number"
min={0}
value={mandateForm.quotaNamesPerYear}
onChange={e => setMandateForm(p => ({ ...p, quotaNamesPerYear: parseInt(e.target.value) || 0 }))}
/>
</div>
</div>
<div style={{ display: 'flex', gap: '8px' }}>
<button className={styles.primaryButton} onClick={handleCreateMandate} disabled={isLoading}>
{isLoading ? 'Erstellen...' : 'Mandant erstellen'}
@ -631,11 +603,11 @@ export const AdminMandateWizardPage: React.FC = () => {
onClick={() => setIsAddingMandateUser(true)}
disabled={availableUsersForMandate.length === 0}
>
+ Benutzer hinzufügen
+ Benutzer hinzufügen
</button>
</div>
<p style={{ fontSize: '12px', color: 'var(--text-secondary)', marginBottom: '16px' }}>
Alle Systembenutzer kÃnnen dem Mandanten zugewiesen werden.
Alle Systembenutzer können dem Mandanten zugewiesen werden.
</p>
{isAddingMandateUser && renderAddUserForm(
@ -652,7 +624,7 @@ export const AdminMandateWizardPage: React.FC = () => {
</div>
<div style={{ marginTop: '24px', display: 'flex', justifyContent: 'space-between' }}>
<button className={styles.secondaryButton} onClick={() => setStep(1)}>&larr; Zurück</button>
<button className={styles.secondaryButton} onClick={() => setStep(1)}>&larr; Zurück</button>
<button className={styles.primaryButton} onClick={() => setStep(3)}>
Weiter &rarr;
</button>
@ -665,10 +637,10 @@ export const AdminMandateWizardPage: React.FC = () => {
<div style={cardStyle}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
<h3 style={{ fontSize: '15px', fontWeight: 600, margin: 0 }}>
Feature-Instances für &laquo;{getMandateName(selectedMandate)}&raquo;
Feature-Instances für &laquo;{getMandateName(selectedMandate)}&raquo;
</h3>
<span style={{ fontSize: '12px', color: 'var(--text-secondary)' }}>
{instances.length} / {(selectedMandate as any).maxInstances || '?'} Instances
{instances.length} Instances
</span>
</div>
@ -716,7 +688,7 @@ export const AdminMandateWizardPage: React.FC = () => {
}}
onClick={() => handleDeleteInstance(inst.id)}
>
LÃschen
Löschen
</button>
</div>
</div>
@ -737,7 +709,7 @@ export const AdminMandateWizardPage: React.FC = () => {
value={selectedFeatureCode}
onChange={e => setSelectedFeatureCode(e.target.value)}
>
<option value="">-- Feature wählen --</option>
<option value="">-- Feature wählen --</option>
{features.map(f => (
<option key={f.code} value={f.code}>{getFeatureLabel(f.code)}</option>
))}
@ -770,7 +742,7 @@ export const AdminMandateWizardPage: React.FC = () => {
)}
<div style={{ marginTop: '24px', display: 'flex', justifyContent: 'space-between' }}>
<button className={styles.secondaryButton} onClick={() => setStep(2)}>&larr; Zurück</button>
<button className={styles.secondaryButton} onClick={() => setStep(2)}>&larr; Zurück</button>
<button
className={styles.primaryButton}
onClick={() => { if (instances.length > 0) { setSelectedInstance(instances[0]); setStep(4); } }}
@ -787,7 +759,7 @@ export const AdminMandateWizardPage: React.FC = () => {
<div style={cardStyle}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
<h3 style={{ fontSize: '15px', fontWeight: 600, margin: 0 }}>
Feature-Benutzer für &laquo;{selectedInstance.label}&raquo;
Feature-Benutzer für &laquo;{selectedInstance.label}&raquo;
</h3>
<button
className={styles.primaryButton}
@ -795,11 +767,11 @@ export const AdminMandateWizardPage: React.FC = () => {
onClick={() => setIsAddingInstanceUser(true)}
disabled={availableUsersForInstance.length === 0 || instanceRoles.length === 0}
>
+ Benutzer hinzufügen
+ Benutzer hinzufügen
</button>
</div>
<p style={{ fontSize: '12px', color: 'var(--text-secondary)', marginBottom: '16px' }}>
Mandant: {getMandateName(selectedMandate)} | Mitglieder des Mandanten kÃnnen der Feature-Instanz zugewiesen werden.
Mandant: {getMandateName(selectedMandate)} | Mitglieder des Mandanten können der Feature-Instanz zugewiesen werden.
</p>
{isAddingInstanceUser && renderAddUserForm(
@ -819,7 +791,7 @@ export const AdminMandateWizardPage: React.FC = () => {
</div>
<div style={{ marginTop: '24px', display: 'flex', justifyContent: 'space-between' }}>
<button className={styles.secondaryButton} onClick={() => setStep(3)}>&larr; Zurück</button>
<button className={styles.secondaryButton} onClick={() => setStep(3)}>&larr; Zurück</button>
<button className={styles.primaryButton} onClick={() => {
showSuccess('Fertig', 'Konfiguration abgeschlossen!');
setSelectedInstance(null);