Kundenrezensionen jetzt vollständig durch Kund:innen selbst, nicht mehr über Admin

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 <[email protected]>
This commit is contained in:
qcigano
2026-08-03 04:17:04 +02:00
co-authored by Claude Sonnet 5
parent d27a858d8f
commit 6f10e41386
28 changed files with 2338 additions and 334 deletions
+16 -1
View File
@@ -3,7 +3,7 @@ import Layout from "../../../layouts/Layout.astro";
import ProductCard from "../../../components/ProductCard.astro";
import HeartRating from "../../../components/HeartRating.astro";
import { categories, subcategoryChipLabel } from "../../../data/categories";
import { products, durchschnittsbewertung } from "../../../data/products";
import { products, durchschnittsbewertung, anzahlBewertungen } from "../../../data/products";
import type { Locale } from "../../../i18n/config";
import { useTranslations } from "../../../i18n/ui";
@@ -97,6 +97,7 @@ const t = useTranslations(lang);
{products.map((p) => (
<div
class="product-slot"
data-slug={p.slug}
data-kategorie={p.kategorie}
data-unterkategorie={p.unterkategorie ?? ""}
data-preis={p.preis}
@@ -104,6 +105,7 @@ const t = useTranslations(lang);
data-neu={p.badges.includes("neu") ? 1 : 0}
data-bestseller={p.badges.includes("bestseller") ? 1 : 0}
data-bewertung={durchschnittsbewertung(p) ?? 0}
data-basis-anzahl={anzahlBewertungen(p)}
>
<ProductCard product={p} lang={lang} />
</div>
@@ -117,6 +119,8 @@ const t = useTranslations(lang);
</Layout>
<script define:vars={{ productSingular: t.shop.productSingular, productPlural: t.shop.productPlural, unitFirst: lang === "en" }}>
import { lokaleBewertungenFuer } from "../../../scripts/reviews";
const grid = document.getElementById("product-grid");
const slots = Array.from(grid.querySelectorAll(".product-slot"));
const kategorieSel = document.getElementById("f-kategorie");
@@ -235,5 +239,16 @@ const t = useTranslations(lang);
const preset = params.get("kategorie");
if (preset) dropdowns.forEach((d) => d.select(preset));
slots.forEach((slot) => {
const slug = slot.dataset.slug;
if (!slug) return;
const lokale = lokaleBewertungenFuer(slug);
if (lokale.length === 0) return;
const basisSchnitt = Number(slot.dataset.bewertung || 0);
const basisAnzahl = Number(slot.dataset.basisAnzahl || 0);
const summe = basisSchnitt * basisAnzahl + lokale.reduce((s, r) => s + r.bewertung, 0);
slot.dataset.bewertung = String(summe / (basisAnzahl + lokale.length));
});
apply();
</script>