Abo-Status und Protokoll ohne Karten und Icons, neuer Grundstil fuer admin-areas.css

Protokoll als Tabelle (Zeit, Mitarbeiter, Aktion) statt Liste mit festen Mindestbreiten, damit bei 390 px nichts mitten im Wort bricht. Abo-Status als dl.kv, Fehler als .msg.err. admin-areas.css: Haarlinien statt Kaesten, Kopfzeilen ohne Grossbuchstaben, Links ohne eigene Regel, Responsive-Bloecke am Dateiende.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-06 14:33:02 +00:00
1 parent 8c34e932c1
commit b24121e34f
3 files changed
+52 -51

No files matched your search

+5 -7
View File
@@ -1,10 +1,8 @@
import { useEffect, useState } from 'react'
import { FaSpinner } from 'react-icons/fa6'
import { Card, Badge } from '../ui'
import { getCustomerAboStatus } from '../../lib/teamApi'
import { fmtDate, productLabelOf } from '../../lib/format'
import { storageLabel } from '../../lib/storageFormat'
import '../../styles/admin-areas.css'
// Abo-Status eines Kunden (Reiter "Abo & Angebote"): Appwrite-Spiegel des Stripe-Abos, fuer alle Mitarbeiter
export default function AboStatusCard({ customerId }) {
@@ -23,13 +21,13 @@ export default function AboStatusCard({ customerId }) {
return (
<Card title="Abo">
{error && <div className="area-error">{error}</div>}
{!abo && !error && <FaSpinner className="spinner" />}
{abo && !abo.status && <span className="area-muted">kein Abo</span>}
{error && <div className="msg err" role="alert">{error}</div>}
{!abo && !error && <div className="loading">Wird geladen …</div>}
{abo && !abo.status && <p className="muted">kein Abo</p>}
{abo && abo.status && (
<dl className="area-kv">
<dl className="kv">
<dt>Abo</dt>
<dd className="area-inline">
<dd className="flex items-center gap-2 wrap">
{productLabelOf(abo.productKey)}
<Badge tone={abo.active ? 'ok' : 'danger'}>{abo.active ? 'aktiv' : abo.status}</Badge>
</dd>
+25 -21
View File
@@ -1,6 +1,5 @@
import { useCallback, useEffect, useState } from 'react'
import { FaSpinner, FaRotateRight } from 'react-icons/fa6'
import { Card, Button, EmptyState } from '../ui'
import { Button, EmptyState } from '../ui'
import { getCustomerViewLog } from '../../lib/teamApi'
import { formatViewLogTime, viewLogLabel } from '../../lib/viewLog'
@@ -24,33 +23,38 @@ export default function CustomerViewLog({ customerId }) {
if (error) {
return (
<Card>
<div className="flex items-center gap-2 wrap">
<span className="muted">{error}</span>
<Button variant="ghost" onClick={load}><FaRotateRight /> Erneut versuchen</Button>
</div>
</Card>
<div className="flex items-center gap-2 wrap">
<div className="msg err" role="alert">{error}</div>
<Button onClick={load}>Erneut versuchen</Button>
</div>
)
}
if (!entries) return <Card><FaSpinner className="spinner" /></Card>
if (!entries) return <div className="loading">Wird geladen …</div>
if (entries.length === 0) {
return <Card><EmptyState title="Noch keine Einträge" hint="Hier steht, wer die Kundenansicht geöffnet oder darin etwas geändert hat." /></Card>
return <EmptyState title="Noch keine Einträge" hint="Hier steht, wer die Kundenansicht geöffnet oder darin etwas geändert hat." />
}
return (
<Card pad={false}>
<div className="list">
<table className="table">
<thead>
<tr>
<th>Zeit</th>
<th>Mitarbeiter</th>
<th>Aktion</th>
</tr>
</thead>
<tbody>
{entries.map((e) => (
<div key={e.id} className="list-row">
<span className="mono muted list-row-text" style={{ minWidth: 130 }}>{formatViewLogTime(e.at)}</span>
<span className="list-row-text" style={{ minWidth: 120, fontWeight: 600 }}>{e.staffName || '–'}</span>
<div className="grow list-row-text">
<tr key={e.id}>
<td className="nowrap num">{formatViewLogTime(e.at)}</td>
<td>{e.staffName || '–'}</td>
<td>
<div>{viewLogLabel(e.action)}</div>
{e.detail && <div className="muted">{e.detail}</div>}
</div>
</div>
{e.detail && <div className="cell-sub">{e.detail}</div>}
</td>
</tr>
))}
</div>
</Card>
</tbody>
</table>
)
}