From b24121e34ff0aec77b62a4a3c26a286994ab4d3b Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 6 Oct 2026 10:20:47 +0000 Subject: [PATCH] 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 --- src/components/customer/AboStatusCard.jsx | 12 +++--- src/components/customer/CustomerViewLog.jsx | 46 +++++++++++---------- src/styles/admin-areas.css | 45 ++++++++++---------- 3 files changed, 52 insertions(+), 51 deletions(-) diff --git a/src/components/customer/AboStatusCard.jsx b/src/components/customer/AboStatusCard.jsx index fb77c42..a4b6328 100644 --- a/src/components/customer/AboStatusCard.jsx +++ b/src/components/customer/AboStatusCard.jsx @@ -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 ( - {error &&
{error}
} - {!abo && !error && } - {abo && !abo.status && kein Abo} + {error &&
{error}
} + {!abo && !error &&
Wird geladen …
} + {abo && !abo.status &&

kein Abo

} {abo && abo.status && ( -
+
Abo
-
+
{productLabelOf(abo.productKey)} {abo.active ? 'aktiv' : abo.status}
diff --git a/src/components/customer/CustomerViewLog.jsx b/src/components/customer/CustomerViewLog.jsx index 58aad33..7c2cac3 100644 --- a/src/components/customer/CustomerViewLog.jsx +++ b/src/components/customer/CustomerViewLog.jsx @@ -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 ( - -
- {error} - -
-
+
+
{error}
+ +
) } - if (!entries) return + if (!entries) return
Wird geladen …
if (entries.length === 0) { - return + return } return ( - -
+ + + + + + + + + {entries.map((e) => ( -
- {formatViewLogTime(e.at)} - {e.staffName || '–'} -
+
+ + + + ))} - - + +
ZeitMitarbeiterAktion
{formatViewLogTime(e.at)}{e.staffName || '–'}
{viewLogLabel(e.action)}
- {e.detail &&
{e.detail}
} - - + {e.detail &&
{e.detail}
} +
) } diff --git a/src/styles/admin-areas.css b/src/styles/admin-areas.css index df598f7..c364184 100644 --- a/src/styles/admin-areas.css +++ b/src/styles/admin-areas.css @@ -1,34 +1,27 @@ -/* Bereiche aus dem frueheren Admin-Panel (Gutschriften, Abo-Angebote, E-Mail-Speicher, Abo-Status). - Zeilen als Raster; unter 720 px untereinander, damit nichts waagerecht scrollt. */ +/* Bereiche aus dem frueheren Admin-Panel (Gutschriften, Abo-Angebote, E-Mail-Speicher). + Zeilen als Raster mit Haarlinien; unter 860 px untereinander, damit nichts waagerecht scrollt. P6 ersetzt sie durch Tabellen. */ .area-rows { display: flex; flex-direction: column; container-type: inline-size; } .area-row { - display: grid; gap: var(--sp-3); align-items: start; padding: 12px 16px; - border-bottom: 1px solid var(--border); overflow-wrap: anywhere; + display: grid; gap: var(--sp-3); align-items: start; padding: 12px 0; + border-bottom: 1px solid var(--line); overflow-wrap: anywhere; } .area-row:last-child { border-bottom: none; } -.area-row.head { color: var(--text-muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; } -.area-row.active { background: var(--accent-soft); } -.area-muted { color: var(--text-muted); font-size: 13px; } +.area-row.head { color: var(--text-2); font-size: 12px; font-weight: 500; } +.area-row.active { background: var(--bg-subtle); } +.area-muted { color: var(--text-2); font-size: 13px; } .area-danger { color: var(--red-fg); font-size: 13px; } .area-warn { color: var(--orange-fg); font-size: 13px; } -.area-summary { padding: 12px 16px; border-radius: var(--r-sm); background: var(--surface-2); margin-bottom: var(--sp-3); } -.area-summary.warn { background: var(--orange-bg); color: var(--orange-fg); } -.area-message { padding: 10px 14px; border-radius: var(--r-sm); background: var(--accent-soft); margin-bottom: var(--sp-3); } -.area-error { padding: 10px 14px; border-radius: var(--r-sm); background: var(--red-bg); color: var(--red-fg); margin: var(--sp-2) 0; } +.area-summary { margin-bottom: 12px; } +.area-summary.warn { color: var(--orange-fg); } +.area-message, .area-error { font-size: 13px; margin: 8px 0; } +.area-message { color: var(--green-fg); } +.area-error { color: var(--red-fg); } .area-kv { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 6px 16px; margin: 0; } -.area-kv dt { color: var(--text-muted); } +.area-kv dt { color: var(--text-2); } .area-kv dd { margin: 0; overflow-wrap: anywhere; } .area-filter { display: inline-flex; gap: 4px; margin-bottom: var(--sp-3); } .area-inline { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; } .storage-row { grid-template-columns: 150px 220px minmax(0, 1fr) 150px 110px; } -@media (max-width: 720px) { - .area-rows .area-row { grid-template-columns: minmax(0, 1fr); } - .area-row.head { display: none; } - .area-kv { grid-template-columns: minmax(0, 1fr); } - .area-kv dt { margin-top: 6px; } -} -.area-rows a { color: var(--text); text-decoration: none; } -.area-rows a:hover { color: var(--accent); text-decoration: underline; } .credit-row { grid-template-columns: 130px minmax(0, 1fr) minmax(0, 1fr) 110px 100px 150px 100px; } .credit-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-5); } .credit-cols h4 { margin: var(--sp-4) 0 var(--sp-2); font-size: 14px; } @@ -37,11 +30,17 @@ .credit-history { margin-bottom: 8px; } .credit-manual { display: flex; flex-direction: column; gap: 6px; } .credit-calc { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-2); } -.credit-calc label, .credit-field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--text-muted); margin-bottom: var(--sp-2); } +.credit-calc label, .credit-field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--text-2); margin-bottom: var(--sp-2); } +.offer-row { grid-template-columns: 130px 200px minmax(0, 1fr) 110px 210px; } @media (max-width: 900px) { .credit-cols { grid-template-columns: minmax(0, 1fr); } } @media (max-width: 720px) { .credit-calc { grid-template-columns: minmax(0, 1fr); } } -.credit-cols a { color: var(--accent); } -.offer-row { grid-template-columns: 130px 200px minmax(0, 1fr) 110px 210px; } +/* Responsive: hinter allen Spaltenregeln, damit bei gleicher Spezifitaet die spaetere Regel gewinnt (ohne Vorrangmarker) */ +@media (max-width: 860px) { + .area-rows .area-row { grid-template-columns: minmax(0, 1fr); } + .area-row.head { display: none; } + .area-kv { grid-template-columns: minmax(0, 1fr); } + .area-kv dt { margin-top: 6px; } +} /* Nach verfuegbarer Breite stapeln (nicht nach Fensterbreite): mit ausgeklappter Sidebar sind Tablet quer oder ein halbes Laptop-Fenster sonst zu schmal fuer die Spalten */ @container (max-width: 960px) {