Neu: Kundenrezensionen mit Herzen in Lila-Babyblau, ueberall im Shop integriert
Neue HeartRating-Komponente (Herzen statt Sterne, Lila-Babyblau-Verlauf wie der Rest der Markenoptik) + komplettes Rezensions-System: - Produktkarten: Bewertungszeile (Herzen + Anzahl) unter dem Titel, nur wenn Bewertungen vorhanden sind. - Produktseite: volle "Kundenrezensionen"-Sektion mit Durchschnitt und einzelnen Rezensionen (Name, Herzen, Datum, Text) bzw. "Noch keine Bewertungen"-Hinweis. - Shop-Filter: neuer "Mindestbewertung"-Filter im Filter-Sidebar + neue Sortierung "Beste Bewertung". - Startseite: "Was unsere Kund:innen sagen"-Sektion mit Gesamtbewertung und den 3 neuesten Rezensionen - erscheint automatisch, sobald die erste echte Bewertung existiert. - Adminbereich: neues Feld "Bewertungen" pro Produkt (Name/Herzen/Text/Datum), mit deutlichem Hinweis, dass hier nur echte Kundenrueckmeldungen eingetragen werden duerfen - erfundene Bewertungen sind in Deutschland/der EU gesetzlich verboten (UWG). Deshalb bewusst OHNE Beispiel-Bewertungen im Code: alle Bereiche starten leer und blenden sich automatisch ein, sobald VanVan die erste echte Rezension eintraegt. Mit temporaeren Testdaten end-to-end durchgetestet (Herzen-Darstellung, Rezensions-Section, Filter, Startseiten-Sektion) und vor dem Commit wieder aus den echten Produktdaten entfernt. Gilt fuer alle 4 Sprachen. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
1add9a42a1
commit
b384938b92
@@ -11,6 +11,18 @@ export type Badge = "neu" | "bestseller" | "sale" | "handgemacht";
|
||||
|
||||
type LocalizedText = Record<Locale, string>;
|
||||
|
||||
// Eine einzelne Kundenrezension zu einem Produkt — von VanVan im Adminbereich gepflegt (echte
|
||||
// Kunden-Rückmeldungen, KEINE automatisch erzeugten/erfundenen Bewertungen: Fake-Bewertungen sind
|
||||
// in Deutschland/der EU seit der Omnibus-Richtlinie ausdrücklich verboten). Deshalb startet jedes
|
||||
// Produkt ohne Bewertungen — die Anzeige blendet sich überall automatisch ein, sobald die erste
|
||||
// echte Rezension eingetragen wird, und bleibt sonst dezent (kein "0 Bewertungen"-Ballast).
|
||||
export interface Bewertung {
|
||||
name: string;
|
||||
bewertung: number; // 1–5 (Herzen statt Sterne, siehe HeartRating.astro)
|
||||
text?: LocalizedText;
|
||||
datum?: string; // ISO-Datum, z.B. "2026-08-03"
|
||||
}
|
||||
|
||||
export interface Product {
|
||||
slug: string;
|
||||
name: LocalizedText;
|
||||
@@ -47,6 +59,7 @@ export interface Product {
|
||||
bis?: string; // ISO-Datum, z.B. "2026-12-31" — Rabatt gilt nur bis einschließlich diesem Tag
|
||||
mengenrabatt?: { abMenge: number; prozent: number }[];
|
||||
};
|
||||
bewertungen?: Bewertung[];
|
||||
}
|
||||
|
||||
const modules = import.meta.glob("/src/content/products/*.json", { eager: true }) as Record<
|
||||
@@ -73,3 +86,32 @@ export function productsByUnterkategorie(kategorie: string, unterkategorie: stri
|
||||
export function saleProducts(): Product[] {
|
||||
return products.filter((p) => p.badges.includes("sale") || p.preisAlt);
|
||||
}
|
||||
|
||||
// Rezensions-Helfer — überall genutzt, wo eine Herzen-Bewertung angezeigt wird (Produktkarte,
|
||||
// Produktseite, Shop-Filter/Sortierung, Startseiten-Kundenstimmen), damit die Rechenlogik nur an
|
||||
// einer Stelle steht.
|
||||
export function durchschnittsbewertung(product: Product): number | null {
|
||||
const b = product.bewertungen;
|
||||
if (!b || b.length === 0) return null;
|
||||
return b.reduce((sum, r) => sum + r.bewertung, 0) / b.length;
|
||||
}
|
||||
|
||||
export function anzahlBewertungen(product: Product): number {
|
||||
return product.bewertungen?.length ?? 0;
|
||||
}
|
||||
|
||||
// Alle Rezensionen über alle Produkte hinweg, neueste zuerst — Grundlage für die
|
||||
// Kundenstimmen-Sektion auf der Startseite.
|
||||
export function alleBewertungen(): (Bewertung & { produktSlug: string; produktName: LocalizedText })[] {
|
||||
return products
|
||||
.flatMap((p) => (p.bewertungen ?? []).map((b) => ({ ...b, produktSlug: p.slug, produktName: p.name })))
|
||||
.sort((a, b) => (b.datum ?? "").localeCompare(a.datum ?? ""));
|
||||
}
|
||||
|
||||
// Gesamt-Durchschnitt über alle Produkte hinweg — für die Kundenstimmen-Sektion auf der
|
||||
// Startseite (erscheint erst automatisch, sobald mindestens eine echte Bewertung existiert).
|
||||
export function gesamtDurchschnitt(): number | null {
|
||||
const alle = alleBewertungen();
|
||||
if (alle.length === 0) return null;
|
||||
return alle.reduce((sum, r) => sum + r.bewertung, 0) / alle.length;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user