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:
co-authored by
Claude Sonnet 5
parent
d27a858d8f
commit
6f10e41386
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user