From 6f10e41386b8a9b231736e4a8d924495db47918f Mon Sep 17 00:00:00 2001 From: qcigano Date: Mon, 3 Aug 2026 04:17:04 +0200 Subject: [PATCH] =?UTF-8?q?Kundenrezensionen=20jetzt=20vollst=C3=A4ndig=20?= =?UTF-8?q?durch=20Kund:innen=20selbst,=20nicht=20mehr=20=C3=BCber=20Admin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bisher musste VanVan Bewertungen manuell im CMS eintragen. Jetzt können angemeldete Kund:innen Rezensionen direkt auf der Produktseite abgeben (inkl. Herzen-Sternebewertung und Text). Die Durchschnittsbewertung wird automatisch berechnet und überall live eingebunden: Produktkarten (shop-weit), Produktdetailseite, Shop-Filter/Sortierung nach Bewertung und die Kundenstimmen-Sektion auf der Startseite. Neu dazu: ein Kontobereich fürs Login (Demo-Login per E-Mail), Profilfoto- Upload, wählbarer Benutzername, und ein Header-Kontomenü, das nur bei Anmeldung erscheint. Jede Bestellung im Konto-Dashboard hat einen "Rezension schreiben"-Link, der direkt zur Produktseite führt und dort per Bestellnummer verknüpft wird; im Profil ist dann sofort sichtbar, welche Bestellungen schon bewertet wurden. Technisch als reines Frontend/localStorage-System umgesetzt (kein Backend in dieser Phase), analog zum bestehenden Warenkorb-Muster. Admin-CMS-Feld für manuelle Bewertungen entfernt, da Rezensionen jetzt ausschließlich von Kund:innen kommen (auch aus rechtlichen Gründen: keine Fake-Bewertungen). Co-Authored-By: Claude Sonnet 5 --- public/admin/config.yml | 25 +--- src/components/ProductCard.astro | 55 +++++++- src/i18n/ui.ts | 76 ++++++++--- src/layouts/Layout.astro | 84 +++++++++++- src/pages/ch/index.astro | 95 ++++++++++--- src/pages/ch/konto/angemeldet.astro | 170 +++++++++++++++++++---- src/pages/ch/konto/index.astro | 28 +++- src/pages/ch/produkt/[slug].astro | 200 +++++++++++++++++++++++++--- src/pages/ch/shop/index.astro | 17 ++- src/pages/en/index.astro | 95 ++++++++++--- src/pages/en/konto/angemeldet.astro | 170 +++++++++++++++++++---- src/pages/en/konto/index.astro | 28 +++- src/pages/en/produkt/[slug].astro | 200 +++++++++++++++++++++++++--- src/pages/en/shop/index.astro | 17 ++- src/pages/fr/index.astro | 95 ++++++++++--- src/pages/fr/konto/angemeldet.astro | 170 +++++++++++++++++++---- src/pages/fr/konto/index.astro | 28 +++- src/pages/fr/produkt/[slug].astro | 200 +++++++++++++++++++++++++--- src/pages/fr/shop/index.astro | 17 ++- src/pages/index.astro | 114 ++++++++++++---- src/pages/konto/angemeldet.astro | 170 +++++++++++++++++++---- src/pages/konto/index.astro | 30 +++-- src/pages/produkt/[slug].astro | 181 ++++++++++++++++++++++--- src/pages/shop/index.astro | 20 ++- src/scripts/account.ts | 83 ++++++++++++ src/scripts/hearts.ts | 63 +++++++++ src/scripts/reviews.ts | 96 +++++++++++++ src/styles/global.css | 145 +++++++++++++++++++- 28 files changed, 2338 insertions(+), 334 deletions(-) create mode 100644 src/scripts/account.ts create mode 100644 src/scripts/hearts.ts create mode 100644 src/scripts/reviews.ts diff --git a/public/admin/config.yml b/public/admin/config.yml index 243aed1..e634d86 100644 --- a/public/admin/config.yml +++ b/public/admin/config.yml @@ -134,25 +134,12 @@ collections: - { label: Lieferumfang, name: lieferumfang, widget: string, required: false } - { label: Pflegehinweise, name: pflegehinweise, widget: string, required: false } - { label: Lieferzeit, name: lieferzeit, widget: string, required: false } - - label: "🩵 Kundenrezensionen" - name: bewertungen - widget: list - required: false - summary: "{{fields.name}} — {{fields.bewertung}}/5" - hint: "WICHTIG: Hier nur echte Rückmeldungen deiner Kund:innen eintragen (z.B. per E-Mail/Nachricht erhalten) — erfundene Bewertungen sind in Deutschland und der EU gesetzlich verboten (Gesetz gegen unlauteren Wettbewerb). Ohne Eintrag hier bleibt der Bewertungsbereich beim Produkt einfach leer, das ist völlig normal für neue Produkte." - fields: - - { label: "Name (z.B. Vorname + Initiale des Nachnamens)", name: name, widget: string } - - { label: "Bewertung (1-5 Herzen)", name: bewertung, widget: number, value_type: int, min: 1, max: 5 } - - label: "Text der Bewertung (optional)" - name: text - widget: object - required: false - fields: - - { label: Deutsch, name: de, widget: text, required: false } - - { label: Englisch, name: en, widget: text, required: false } - - { label: "Schweizerdeutsch", name: ch, widget: text, required: false } - - { label: Französisch, name: fr, widget: text, required: false } - - { label: "Datum (optional)", name: datum, widget: datetime, format: "YYYY-MM-DD", date_format: "YYYY-MM-DD", time_format: false, required: false } + # Kein "Bewertungen"-Feld mehr hier: Kund:innen schreiben ihre Rezensionen jetzt direkt auf + # der Produktseite selbst (Herzen + Text), die Durchschnittsbewertung wird automatisch + # berechnet und überall auf der Seite live angezeigt (Produktkarten, Filter, Startseite). + # VanVan muss dafür nichts mehr im Adminbereich eintragen. Das Datenfeld "bewertungen" bleibt + # im Hintergrund als technische Grundlage bestehen (src/data/products.ts), ist hier aber + # bewusst nicht mehr als Formularfeld sichtbar. - label: "Interner Code (URL) — nach Veröffentlichung nicht mehr ändern!" name: slug widget: string diff --git a/src/components/ProductCard.astro b/src/components/ProductCard.astro index 092ad28..7494b37 100644 --- a/src/components/ProductCard.astro +++ b/src/components/ProductCard.astro @@ -26,7 +26,7 @@ const badgeLabel: Record = { const name = product.name[lang]; const desc = product.beschreibung[lang]; --- - +
{product.bilder && product.bilder.length > 0 ? ( <> @@ -59,9 +59,23 @@ const desc = product.beschreibung[lang];

{name}

- {bewertungSchnitt !== null && ( - - )} + {/* Immer gerendert (auch ohne Server-Bewertungen), aber standardmäßig versteckt — ein + gemeinsames Skript (siehe unten) blendet die Zeile automatisch ein, sobald auf diesem + Gerät lokal gespeicherte Kundenrezensionen für dieses Produkt dazukommen (siehe + scripts/reviews.ts), egal auf welcher Seite die Karte gerade angezeigt wird. */} + + {bewertungSchnitt !== null && ( + + )} +

{desc.slice(0, 78)}{desc.length > 78 ? "…" : ""}

{product.preisAlt && {formatPrice(product.preisAlt, lang)}} @@ -146,6 +160,39 @@ const desc = product.beschreibung[lang]; }, true); + +