ui-nyla/src/pages/views/trustee/TrusteeDashboardView.tsx
2026-02-21 00:56:50 +01:00

131 lines
5 KiB
TypeScript

/**
* TrusteeDashboardView
*
* Overview dashboard for a Trustee instance.
* Shows statistics about positions, documents, and accounting sync status.
*/
import React, { useState, useEffect } from 'react';
import { useCurrentInstance } from '../../../hooks/useCurrentInstance';
import { useTrusteePositions, useTrusteeDocuments } from '../../../hooks/useTrustee';
import { useApiRequest } from '../../../hooks/useApi';
import { fetchAccountingConfig, fetchSyncStatus, type AccountingConfig, type AccountingSyncStatus } from '../../../api/trusteeApi';
import styles from './TrusteeViews.module.css';
export const TrusteeDashboardView: React.FC = () => {
const { instance, instanceId } = useCurrentInstance();
const { items: positions, loading: posLoading } = useTrusteePositions();
const { items: documents, loading: docsLoading } = useTrusteeDocuments();
const { request } = useApiRequest();
const [accountingConfig, setAccountingConfig] = useState<AccountingConfig | null>(null);
const [syncItems, setSyncItems] = useState<AccountingSyncStatus[]>([]);
const [accountingLoading, setAccountingLoading] = useState(true);
useEffect(() => {
if (!instanceId) return;
const loadAccountingData = async () => {
setAccountingLoading(true);
try {
const [config, syncData] = await Promise.all([
fetchAccountingConfig(request, instanceId),
fetchSyncStatus(request, instanceId),
]);
setAccountingConfig(config);
setSyncItems(syncData?.items || []);
} catch {
// Accounting not configured is fine
} finally {
setAccountingLoading(false);
}
};
loadAccountingData();
}, [instanceId, request]);
const isLoading = posLoading || docsLoading || accountingLoading;
const syncedCount = syncItems.filter(s => s.syncStatus === 'synced').length;
const syncErrorCount = syncItems.filter(s => s.syncStatus === 'error').length;
return (
<div className={styles.dashboardView}>
<div className={styles.statsGrid}>
<div className={styles.statCard}>
<div className={styles.statIcon}>📊</div>
<div className={styles.statContent}>
<div className={styles.statValue}>
{isLoading ? '...' : positions.length}
</div>
<div className={styles.statLabel}>Positionen</div>
</div>
</div>
<div className={styles.statCard}>
<div className={styles.statIcon}>📄</div>
<div className={styles.statContent}>
<div className={styles.statValue}>
{isLoading ? '...' : documents.length}
</div>
<div className={styles.statLabel}>Dokumente</div>
</div>
</div>
<div className={styles.statCard}>
<div className={styles.statIcon}>
{accountingConfig?.configured ? '✓' : '○'}
</div>
<div className={styles.statContent}>
<div className={styles.statValueSmall}>
{isLoading ? '...' : (
accountingConfig?.configured
? <>{syncedCount} synced{syncErrorCount > 0 && <span style={{ color: 'var(--error-color, #dc2626)' }}> / {syncErrorCount} errors</span>}</>
: 'Not configured'
)}
</div>
<div className={styles.statLabel}>Buchhaltung</div>
</div>
</div>
<div className={styles.statCard}>
<div className={styles.statIcon}>👤</div>
<div className={styles.statContent}>
<div className={styles.statValueSmall}>
{instance?.userRoles?.length ? (
instance.userRoles.map((role: string, idx: number) => (
<div key={idx}>{role}</div>
))
) : '-'}
</div>
<div className={styles.statLabel}>
{(instance?.userRoles?.length || 0) === 1 ? 'Deine Rolle' : 'Deine Rollen'}
</div>
</div>
</div>
</div>
<div className={styles.infoSection}>
<h3>Instanz-Details</h3>
<div className={styles.infoGrid}>
<div className={styles.infoItem}>
<span className={styles.infoLabel}>Instanz:</span>
<span className={styles.infoValue}>{instance?.instanceLabel}</span>
</div>
<div className={styles.infoItem}>
<span className={styles.infoLabel}>Mandant:</span>
<span className={styles.infoValue}>{instance?.mandateName}</span>
</div>
{accountingConfig?.configured && (
<div className={styles.infoItem}>
<span className={styles.infoLabel}>Buchhaltungssystem:</span>
<span className={styles.infoValue}>
{accountingConfig.displayLabel || accountingConfig.connectorType}
{accountingConfig.lastSyncStatus && ` (${accountingConfig.lastSyncStatus})`}
</span>
</div>
)}
</div>
</div>
</div>
);
};
export default TrusteeDashboardView;