/** * Billing Dashboard Page * * Zeigt Guthaben, Statistiken und Transaktionen für den Benutzer. */ import React, { useState, useEffect, useMemo } from 'react'; import { useBilling, type BillingBalance, type UsageReport } from '../../hooks/useBilling'; import { BillingNav } from './BillingNav'; import styles from './Billing.module.css'; // ============================================================================ // BALANCE CARD COMPONENT // ============================================================================ interface BalanceCardProps { balance: BillingBalance; onClick?: () => void; } const BalanceCard: React.FC = ({ balance, onClick }) => { const formatCurrency = (amount: number) => { return new Intl.NumberFormat('de-CH', { style: 'currency', currency: 'CHF' }).format(amount); }; return (

{balance.mandateName}

{formatCurrency(balance.balance)}
{balance.isWarning && (
Niedriges Guthaben
)}
); }; // ============================================================================ // STATISTICS CHART COMPONENT // ============================================================================ interface StatisticsChartProps { statistics: UsageReport | null; loading?: boolean; } const StatisticsChart: React.FC = ({ statistics, loading }) => { const formatCurrency = (amount: number) => { return new Intl.NumberFormat('de-CH', { style: 'currency', currency: 'CHF' }).format(amount); }; if (loading) { return
Lade Statistiken...
; } if (!statistics) { return
Keine Statistiken verfügbar
; } // Calculate max cost for bar scaling const maxProviderCost = Math.max(...Object.values(statistics.costByProvider), 1); return (
Gesamtkosten {formatCurrency(statistics.totalCost)}

Kosten nach Anbieter

{Object.entries(statistics.costByProvider).length === 0 ? (
Keine Daten
) : (
{Object.entries(statistics.costByProvider).map(([provider, cost]) => (
{provider}
{formatCurrency(cost)}
))}
)}

Kosten nach Modell

{Object.entries(statistics.costByModel || {}).length === 0 ? (
Keine Daten
) : (
{Object.entries(statistics.costByModel || {}).map(([model, cost]) => (
{model}
{formatCurrency(cost)}
))}
)}

Kosten nach Feature

{Object.entries(statistics.costByFeature).length === 0 ? (
Keine Daten
) : (
{Object.entries(statistics.costByFeature).map(([feature, cost]) => (
{feature} {formatCurrency(cost)}
))}
)}
); }; // ============================================================================ // MAIN COMPONENT // ============================================================================ export const BillingDashboard: React.FC = () => { const { balances, statistics, loading, loadStatistics } = useBilling(); const [selectedPeriod, setSelectedPeriod] = useState<'month' | 'year'>('month'); const [selectedYear, setSelectedYear] = useState(new Date().getFullYear()); const [selectedMonth, setSelectedMonth] = useState(new Date().getMonth() + 1); // Load statistics when period changes useEffect(() => { if (selectedPeriod === 'month') { loadStatistics('month', selectedYear); } else { loadStatistics('year', selectedYear); } }, [selectedPeriod, selectedYear, loadStatistics]); // Available years (current and last 2 years) const availableYears = useMemo(() => { const current = new Date().getFullYear(); return [current, current - 1, current - 2]; }, []); // Available months const availableMonths = [ { value: 1, label: 'Januar' }, { value: 2, label: 'Februar' }, { value: 3, label: 'März' }, { value: 4, label: 'April' }, { value: 5, label: 'Mai' }, { value: 6, label: 'Juni' }, { value: 7, label: 'Juli' }, { value: 8, label: 'August' }, { value: 9, label: 'September' }, { value: 10, label: 'Oktober' }, { value: 11, label: 'November' }, { value: 12, label: 'Dezember' }, ]; return (

Billing

Übersicht über Guthaben und Nutzung

{/* Balance Cards */}

Guthaben

{loading ? (
Lade Guthaben...
) : balances.length === 0 ? (
Keine Abrechnungskonten vorhanden
) : (
{balances.map((balance) => ( ))}
)}
{/* Statistics */}

Nutzungsstatistik

{selectedPeriod === 'month' && ( )}
); }; export default BillingDashboard;