ui-nyla/src/pages/Dashboard.tsx
2026-02-09 23:45:05 +01:00

149 lines
4.9 KiB
TypeScript

/**
* Dashboard Page
*
* System-Übersicht für den User.
* Zeigt alle verfügbaren Feature-Instanzen als Karten an.
* Daten kommen vom Backend via GET /api/navigation.
*/
import React from 'react';
import { Link } from 'react-router-dom';
import useNavigation from '../hooks/useNavigation';
import type { NavigationMandate, MandateFeature, FeatureInstance as NavFeatureInstance } from '../hooks/useNavigation';
import { getPageIcon } from '../config/pageRegistry';
import { FaArrowRight } from 'react-icons/fa';
import styles from './Dashboard.module.css';
// =============================================================================
// INSTANCE CARD
// =============================================================================
interface InstanceCardProps {
instance: NavFeatureInstance;
feature: MandateFeature;
mandateLabel: string;
}
const InstanceCard: React.FC<InstanceCardProps> = ({ instance, feature, mandateLabel }) => {
// Ersten verfügbaren View-Pfad vom Backend nehmen
const targetPath = instance.views.length > 0 ? instance.views[0].uiPath : undefined;
if (!targetPath) return null;
return (
<Link to={targetPath} className={styles.instanceCard}>
<div className={styles.cardIcon}>
{getPageIcon(feature.uiComponent)}
</div>
<div className={styles.cardContent}>
<div className={styles.cardHeader}>
<span className={styles.featureLabel}>{feature.uiLabel}</span>
</div>
<h3 className={styles.instanceLabel}>{instance.uiLabel}</h3>
<p className={styles.mandateName}>{mandateLabel}</p>
</div>
<div className={styles.cardArrow}>
<FaArrowRight />
</div>
</Link>
);
};
// =============================================================================
// EMPTY STATE
// =============================================================================
const EmptyState: React.FC = () => (
<div className={styles.emptyState}>
<div className={styles.emptyIcon}>📋</div>
<h2>Willkommen bei PowerOn</h2>
<p>Du hast aktuell Zugriff auf keine Feature-Instanzen.</p>
<p>Kontaktiere einen Administrator, um Zugriff zu erhalten.</p>
</div>
);
// =============================================================================
// DASHBOARD PAGE
// =============================================================================
export const DashboardPage: React.FC = () => {
const { dynamicBlock, loading } = useNavigation();
// Alle Mandate und deren Features/Instanzen aus der Navigation
const mandates: NavigationMandate[] = dynamicBlock?.mandates || [];
// Gesamtzahl Instanzen und Mandate berechnen
let totalInstances = 0;
const totalMandates = mandates.length;
mandates.forEach(m => m.features.forEach(f => {
totalInstances += f.instances.length;
}));
if (loading) {
return (
<div className={styles.dashboard}>
<header className={styles.header}>
<h1>Übersicht</h1>
<p className={styles.subtitle}>Lade...</p>
</header>
</div>
);
}
if (totalInstances === 0) {
return <EmptyState />;
}
// Gruppiere Instanzen nach Feature (über alle Mandate)
const featureGroups: { feature: MandateFeature; instances: { instance: NavFeatureInstance; mandateLabel: string }[] }[] = [];
const featureMap = new Map<string, typeof featureGroups[0]>();
for (const mandate of mandates) {
for (const feature of mandate.features) {
const key = feature.uiComponent;
let group = featureMap.get(key);
if (!group) {
group = { feature, instances: [] };
featureMap.set(key, group);
featureGroups.push(group);
}
for (const instance of feature.instances) {
group.instances.push({ instance, mandateLabel: mandate.uiLabel });
}
}
}
return (
<div className={styles.dashboard}>
<header className={styles.header}>
<h1>Übersicht</h1>
<p className={styles.subtitle}>
Du hast Zugriff auf {totalInstances} Feature-Instanz{totalInstances !== 1 ? 'en' : ''} in {totalMandates} Mandant{totalMandates !== 1 ? 'en' : ''}.
</p>
</header>
<main className={styles.content}>
{featureGroups.map(({ feature, instances }) => (
<section key={feature.uiComponent} className={styles.featureSection}>
<h2 className={styles.sectionTitle}>
{getPageIcon(feature.uiComponent)}
<span>{feature.uiLabel}</span>
</h2>
<div className={styles.instanceGrid}>
{instances.map(({ instance, mandateLabel }) => (
<InstanceCard
key={instance.id}
instance={instance}
feature={feature}
mandateLabel={mandateLabel}
/>
))}
</div>
</section>
))}
</main>
</div>
);
};
export default DashboardPage;