import React, { useMemo, useState } from 'react'; import { Badge, BudgetBar, Card, EmptyState, ErrorBox, Spinner, inputClass } from '../ui/controls'; import { Icon } from '../ui/Icon'; import { BILLABLE, CountUp, Legend, NON_BILLABLE, StackedBars } from '../ui/charts'; import { ReportTable } from './ReportTable'; import { ExportMenu } from './ExportMenu'; import { ReportKpi, ReportRow } from './ProjectReport'; import { useAuth } from '../../lib/auth'; import { customersApi, qs, reportsApi, type CustomerReport as CustomerReportData } from '../../lib/api'; import { useLoader } from '../../lib/hooks'; import { MONTHS, colorFor, formatEuro, formatHours, formatNumber, todayIso } from '../../lib/format'; import { useRouter } from '../../lib/router'; import { TYPE_TONE } from '../projects/Projects'; import { PROJECT_TYPE_LABELS } from '../../types'; export const CustomerReport: React.FC<{ id: number | null }> = ({ id }) => { const { navigate } = useRouter(); const customers = useLoader(() => customersApi.list(), []); const report = useLoader(() => (id ? reportsApi.customer(id) : Promise.resolve(null)), [id]); return (
{!id ? ( ) : report.error ? ( ) : !report.data ? ( ) : ( )}
); }; const Body: React.FC<{ data: CustomerReportData }> = ({ data }) => { const { settings } = useAuth(); const { navigate } = useRouter(); const [tab, setTab] = useState<'projects' | 'team' | 'tasks'>('projects'); const [months, setMonths] = useState(12); const c = data.customer; const t = data.totals; const color = colorFor(c.id, c.color); const month = todayIso().slice(0, 7); const series = useMemo(() => data.series.slice(-months), [data.series, months]); const exportOptions = [ { label: 'PDF – Stundennachweis (Monat)', hint: 'Vorlage für den Kunden, alle Berater', path: `/exports/timesheet${qs({ month, format: 'pdf', user_id: 'all', customer_id: c.id })}`, filename: `${c.short_name}-${month}.pdf` }, { label: 'Excel – Stundennachweis mit Beträgen', hint: 'Für die Rechnungsstellung', path: `/exports/timesheet${qs({ month, format: 'xlsx', user_id: 'all', customer_id: c.id, amounts: 1 })}`, filename: `${c.short_name}-${month}.xlsx` }, { label: 'PDF – Projekte (Jahr)', path: `/exports/report${qs({ from: `${month.slice(0, 4)}-01-01`, to: todayIso(), customer_id: c.id, group: 'projects', format: 'pdf', include_fixed: 1 })}`, filename: `${c.short_name}-projekte.pdf` }, { label: 'CSV – alle Buchungen (Jahr)', path: `/exports/report${qs({ from: `${month.slice(0, 4)}-01-01`, to: todayIso(), customer_id: c.id, group: 'detail', format: 'csv', include_fixed: 1 })}`, filename: `${c.short_name}.csv` }, ]; return (
{c.short_name.slice(0, 2)}

{c.name}

{data.projects.length} Projekte · {data.team.length} Mitarbeiter {c.contact_person && ` · Ansprechpartner: ${c.contact_person}`}

formatNumber(v, 2)} className="text-3xl font-extrabold text-ink-900" /> formatEuro(v, 2)} className="text-3xl font-extrabold text-ink-900" /> formatEuro(v, 2)} className="text-3xl font-extrabold text-ink-900" /> s + p.project.pots.filter((x) => x.status === 'active').length, 0)}`} /> formatEuro(v, 0)} className="text-3xl font-extrabold text-ink-900" />

Stunden je Monat

{series.length ? ( ({ key: m.month, label: `${MONTHS[Number(m.month.slice(5)) - 1].slice(0, 3)} ${m.month.slice(2, 4)}`, a: m.billable_minutes, b: m.minutes - m.billable_minutes }))} format={(v) => `${formatHours(v, 1)} h`} axisFormat={(v) => formatNumber(v / 60, 0)} height={220} /> ) : (

Noch keine Buchungen.

)}
{( [ ['projects', 'Projekte'], ['team', 'Team'], ['tasks', 'Tasks'], ] as const ).map(([key, label]) => ( ))}
{tab === 'team' && } {tab === 'tasks' && } {tab === 'projects' && (
{data.projects.length === 0 &&

Keine Projekte.

} {data.projects.map(({ project: p, totals, pots }, i) => ( ))}
)}
); };