Design P6: reine Helfer fuer Gutschrift-, Angebots- und Speicherzeilen mit Tests

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-06 14:36:10 +00:00
1 parent 910fa0ff30
commit b81e53eef5
6 files changed
+146 -2

No files matched your search

+11
View File
@@ -10,6 +10,17 @@ export const CREDIT_STATUS = {
}
export const creditStatus = (status) => CREDIT_STATUS[status] || { tone: 'muted', label: status }
/** Knopf der Listenzeile: offene und rueckgefragte Antraege werden geprueft, alle anderen nur angesehen */
export const creditActionLabel = (status) => (['offen', 'rueckfrage'].includes(status) ? 'Prüfen' : 'Ansehen')
/** Zweite Zeile unter dem Status: bei genehmigten Antraegen Betrag und Buchungsstand, sonst leer */
export const creditStatusNote = (r) =>
(r.status === 'genehmigt' ? `${formatCents(r.amountCents)}${r.appliedAt ? '' : ' · nicht gebucht'}` : '')
/** Zeichen und Ton einer Zeile der automatischen Pruefung (unbekannt: "i" in gedaempftem Ton) */
export const checkGlyph = (status) => (status === 'ok' ? '✓' : status === 'warn' ? '!' : 'i')
export const checkTone = (status) => (status === 'ok' || status === 'warn' || status === 'info' ? status : 'muted')
const HISTORY_LABELS = {
eingereicht: 'Antrag eingereicht',
rueckfrage: 'Rückfrage an den Kunden',
+19 -1
View File
@@ -1,4 +1,4 @@
import { berlinYmd, fmtBerlin, fmtDate, fmtYmd, formatCents, PRODUCT_LABEL } from './format'
import { berlinYmd, fmtBerlin, fmtDate, fmtDateTime, fmtYmd, formatCents, PRODUCT_LABEL } from './format'
// Abo-Angebote: Texte, Rabattende und Formularpruefung wortgleich aus dem frueheren Admin-Panel des Portals.
// "today" ist der Kalendertag in Deutschland (YYYY-MM-DD) und fuer Tests injizierbar.
@@ -11,6 +11,24 @@ export const OFFER_STATUS = {
}
export const offerStatus = (status) => OFFER_STATUS[status] || { tone: 'muted', label: status }
/** Listenfilter: "all" zeigt alles, sonst nur offene und aktive Angebote; ohne Liste leer, die Eingabe bleibt unveraendert */
export const filterOffers = (offers, filter) =>
(offers || []).filter((o) => filter === 'all' || ['offen', 'aktiv'].includes(o.status))
/** Aktionen der Zeile: Beschriftung des E-Mail-Knopfs ('' = kein Knopf) und ob Zurueckziehen moeglich ist */
export const offerRowActions = (o) => ({
sendLabel: o.mailSendable ? (o.notifiedAt ? 'Erneut senden' : 'E-Mail senden') : '',
canWithdraw: ['offen', 'abgelaufen'].includes(o.status),
})
/** Mail-Zeile unter dem Status (Reihenfolge: gesendet, nicht verschickt, ohne Adresse), sonst null */
export function offerMailLine(o) {
if (o.notifiedAt) return { tone: 'muted', text: `E-Mail gesendet ${fmtDateTime(o.notifiedAt)}` }
if (o.mailSendable) return { tone: 'warn', text: 'E-Mail nicht verschickt' }
if (o.status === 'offen' && !o.customerEmail) return { tone: 'warn', text: 'Keine E-Mail-Adresse hinterlegt' }
return null
}
const todayBerlin = () => berlinYmd(new Date())
export function offerPreviewText(price, months, regular, running) {
+7 -1
View File
@@ -1,4 +1,4 @@
import { fmtDate } from './format'
import { fmtDate, fmtDateTime } from './format'
// E-Mail-Speicher (Zusatzspeicher-Aufgaben in konsoleH): Texte wortgleich aus dem frueheren Admin-Panel des Portals.
@@ -35,5 +35,11 @@ export const orderedKind = (t) => (t.toUnits > t.fromUnits ? 'Bestellung (Plus)'
export const isOverdue = (t, now = Date.now()) => Boolean(t.dueAt && new Date(t.dueAt).getTime() <= now)
/** Faelligkeitsspalte: Einrichten sofort, Verringern zum Periodenende (ueberfaellig = warn); sub in gedaempft, wenn subMuted */
export function storageDue(t, now = Date.now()) {
if (t.kind === 'einrichten') return { tone: 'warn', label: 'jetzt einrichten', sub: `bestellt ${fmtDateTime(t.createdAt)}`, subMuted: true }
return { tone: isOverdue(t, now) ? 'warn' : 'muted', label: 'zum Periodenende', sub: fmtDate(t.dueAt), subMuted: false }
}
export const failedText = (f) =>
`${storageLabel(f.fromUnits)} → ${storageLabel(f.toUnits)} – Stripe hat die Änderung abgelehnt, nichts berechnet, keine Aufgabe.${f.error ? ` Fehler: ${f.error}` : ''}`