diff --git a/src/components/offers/OfferList.jsx b/src/components/offers/OfferList.jsx index 9154d57..4b6ea5d 100644 --- a/src/components/offers/OfferList.jsx +++ b/src/components/offers/OfferList.jsx @@ -1,12 +1,10 @@ import { useEffect, useState } from 'react' -import { FaSpinner } from 'react-icons/fa6' -import { Card, Badge, Button } from '../ui' +import { Badge, Button, EmptyState, Tabs } from '../ui' import { listOffers, notifyOffer, withdrawOffer } from '../../lib/teamApi' -import { discountLine, offerStatus } from '../../lib/offerFormat' +import { discountLine, filterOffers, offerMailLine, offerRowActions, offerStatus } from '../../lib/offerFormat' import { fmtDate, fmtDateTime, formatCents, productLabelOf } from '../../lib/format' -import '../../styles/admin-areas.css' -// Liste der Abo-Angebote (Filter "Offen & aktiv"/"Alle") wie im frueheren Admin-Panel; optional nur ein Kunde +// Liste der Abo-Angebote (Reiter "Offen & aktiv"/"Alle") als Tabelle; optional nur ein Kunde export default function OfferList({ customerId, reloadKey, onMessage, onChanged }) { const [filter, setFilter] = useState('open') const [offers, setOffers] = useState(null) @@ -51,69 +49,75 @@ export default function OfferList({ customerId, reloadKey, onMessage, onChanged } } - const shown = (offers || []).filter((o) => filter === 'all' || ['offen', 'aktiv'].includes(o.status)) + const shown = filterOffers(offers, filter) return (
| Angelegt | +Kunde | +Angebot | +Gültig bis | +Status | +
|---|---|---|---|---|
|
+ {fmtDateTime(o.createdAt)}
+ {o.ref}{o.createdBy ? ` · ${o.createdBy.replace(/\s*<.*>$/, '')}` : ''}
+ |
+
+ {o.customerName}
+ {o.customerEmail && {o.customerEmail} }
+ {o.customerCode && Kd.-Nr. {o.customerCode} }
+ |
+
+ {productLabelOf(o.productKey)}
+ {o.text}
+ Ersparnis {formatCents(o.savingsCents)}{o.note ? ` · „${o.note}“` : ''}
+ {discount && {discount} }
+ {o.internalNote && intern: {o.internalNote} }
+ |
+ {o.scope === 'laufend' ? laufendes Abo : fmtDate(o.validUntil)} | +
{sub}>} - Stripe:{' '} - {o.stripeCouponUrl ? Coupon : '–'} - {o.stripeSubscriptionUrl && <> · Abo>} - {o.notifiedAt - ? <> E-Mail gesendet {fmtDateTime(o.notifiedAt)}> - : o.mailSendable - ? <> E-Mail nicht verschickt> - : o.status === 'offen' && !o.customerEmail ? <> Keine E-Mail-Adresse hinterlegt> : null} - {(['offen', 'abgelaufen'].includes(o.status) || o.mailSendable) && ( - - {o.mailSendable && ( - + {sub && {sub} }
+
+ {mail && {mail.tone === 'warn' ? {mail.text} : mail.text} }
+ {(sendLabel || canWithdraw) && (
+
+ {sendLabel && (
+
)}
- {['offen', 'abgelaufen'].includes(o.status) && (
-
- )}
-
+ {canWithdraw && }
+
)}
-
-
+ |
+
{message}
} +Ein Angebot legt sofort einen einmal einlösbaren Coupon in Stripe an. Ohne laufendes Abo wird er beim Abschluss angewendet (und schaltet die Bestellung für diesen Kunden frei), bei laufendem Abo gilt er ab der nächsten Abbuchung. Nach den Angebotsmonaten gilt automatisch wieder der reguläre Preis.
+Ein Angebot legt sofort einen einmal einlösbaren Coupon in Stripe an. Ohne laufendes Abo wird er beim Abschluss angewendet (und schaltet die Bestellung für diesen Kunden frei), bei laufendem Abo gilt er ab der nächsten Abbuchung. Nach den Angebotsmonaten gilt automatisch wieder der reguläre Preis.