diff --git a/src/components/auftraege/ProjektkontoListe.jsx b/src/components/auftraege/ProjektkontoListe.jsx index 4b4bd06..73da2f5 100644 --- a/src/components/auftraege/ProjektkontoListe.jsx +++ b/src/components/auftraege/ProjektkontoListe.jsx @@ -1,11 +1,81 @@ +import './projektkonto.css' +import { Card } from '../ui' +import { kontoZeile, ohneProjektZeile, stripeHinweis, KEINE_PROJEKTE_HINWEIS } from '../../lib/projektkontoView' + /** - * Platzhalter von W0: Strang W1 ersetzt diese Datei vollständig (Dateiname, Default-Export und Props bleiben). - * Die fertige Komponente rendert ihren Abschnitt selbst: (ein
; den Abstand zu den - * Nachbarn liefert `.page section + section`). - * - * Props (V8): konten (Projektkonten), ohneProjekt ({ berechnetCents, bezahltCents, anzahl }), auftraegeAktiv, stripeOk, - * onRechnung(projektId) und onAuftrag(projektId); die Kennung ist die des Projekts, `null` die Zeile „Ohne Projekt“. + * Abschnitt „Projekte“ im Kundenreiter „Aufträge und Rechnungen“: je Projekt eine Zeile mit Vereinbart, Berechnet + * (darunter bezahlt), Noch offen und erfasster Zeit, am Ende die feste Zeile „Ohne Projekt“. + * Props: konten (Projektkonten, darf fehlen), ohneProjekt ({ berechnetCents, bezahltCents, anzahl }), auftraegeAktiv, + * stripeOk, onRechnung(projektId) und onAuftrag(projektId). Die Kennung ist die des Projekts, `null` die Zeile „Ohne Projekt“. + * Die Überschrift „Projekte“ rendert die Komponente selbst; die Anzeigelogik steht in lib/projektkontoView.js. */ export default function ProjektkontoListe({ konten, ohneProjekt, auftraegeAktiv, stripeOk, onRechnung, onAuftrag }) { - return null + const liste = Array.isArray(konten) ? konten : [] + const zeilen = [...liste.map((k) => kontoZeile(k, { stripeOk })), ohneProjektZeile(ohneProjekt, { stripeOk })] + const hinweis = stripeHinweis(stripeOk) + + return ( + +
+ {hinweis && ( +

+ {hinweis} +

+ )} + {liste.length === 0 &&

{KEINE_PROJEKTE_HINWEIS}

} + + + + + + + + + + + + + + {zeilen.map((z) => { + const id = z.projektId || null + const fuer = id === null ? 'ohne Projekt' : `für ${z.name}` + return ( + + + + + + + + + ) + })} + +
Projektkonten
ProjektVereinbartBerechnetNoch offenZeit erfasstAktionen
+
{z.name}
+ {z.meta &&
{z.meta}
} +
{z.vereinbart} +
{z.berechnet}
+ {z.bezahlt &&
{z.bezahlt}
} +
+ {z.offen} + +
{z.zeit.stunden}
+ {z.zeit.wert &&
{z.zeit.wert}
} + {z.zeit.abo &&
{z.zeit.abo}
} +
+
+ {auftraegeAktiv && ( + + )} + +
+
+
+
+ ) } diff --git a/src/components/auftraege/projektkonto.css b/src/components/auftraege/projektkonto.css new file mode 100644 index 0000000..94901fd --- /dev/null +++ b/src/components/auftraege/projektkonto.css @@ -0,0 +1,27 @@ +/* Projektliste im Kundenreiter „Aufträge und Rechnungen“. .pk ist der Container der Abfrage unten (in W1 nur hier + container-type; der Rechnungsdialog liegt nie darin). Jede Regel trägt .pk und überstimmt so .table td aus global.css. */ +.pk { container-type: inline-size; } +.pk .pk-hinweis { margin: 0 0 8px; } +.pk .pk-table th, .pk .pk-table td { vertical-align: top; } +.pk .pk-name, .pk .pk-table td .cell-sub { overflow-wrap: anywhere; } +.pk .pk-table .num { font-variant-numeric: tabular-nums; } +.pk .pk-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 4px 14px; } +.pk .pk-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; } +@container (max-width: 860px) { + .pk .pk-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; } + .pk .pk-table, .pk .pk-table tbody { display: block; } + .pk .pk-table tr { + display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 16px; align-items: start; + grid-template-areas: "name name" "vereinbart berechnet" "offen zeit" "actions actions"; + padding: 12px 0; border-bottom: 1px solid var(--line); + } + .pk .pk-table td, .pk .pk-table td:first-child, .pk .pk-table td:last-child { display: block; padding: 0; border: 0; min-width: 0; } + .pk .pk-name { grid-area: name; } + .pk .pk-vereinbart { grid-area: vereinbart; } + .pk .pk-berechnet { grid-area: berechnet; } + .pk .pk-offen { grid-area: offen; } + .pk .pk-zeit { grid-area: zeit; } + .pk .pk-actions-cell { grid-area: actions; } + .pk .pk-actions { justify-content: flex-start; } + .pk .pk-table td[data-label]::before { content: attr(data-label); display: block; font-size: 12px; font-weight: 500; color: var(--text-2); } +}