From ef0745e59df8a4bdf8535191b88dc0b4032bfec7 Mon Sep 17 00:00:00 2001 From: Majd Ibrahim <“3021285@stud.hs-mannheim.de”> Date: Thu, 24 Sep 2026 16:36:53 +0000 Subject: [PATCH] US2.1: Datenstruktur, Komponenten-Aufbau, Styling, Testing --- .../angebote/angebotsuebersicht.html | 11 ++++ src/components/angebote/angebotsuebersicht.js | 58 +++++++++++++++++++ src/shared/packages.js | 44 ++++++++++++++ src/tests/angebotsuebersicht.test.js | 36 ++++++++++++ src/tests/packages.test.js | 19 ++++++ 5 files changed, 168 insertions(+) create mode 100644 src/components/angebote/angebotsuebersicht.html create mode 100644 src/components/angebote/angebotsuebersicht.js create mode 100644 src/shared/packages.js create mode 100644 src/tests/angebotsuebersicht.test.js create mode 100644 src/tests/packages.test.js diff --git a/src/components/angebote/angebotsuebersicht.html b/src/components/angebote/angebotsuebersicht.html new file mode 100644 index 0000000..58bbf85 --- /dev/null +++ b/src/components/angebote/angebotsuebersicht.html @@ -0,0 +1,11 @@ +
+
+ +

Unsere Ernährungs-Pakete

+
+ + +
+ +
+
diff --git a/src/components/angebote/angebotsuebersicht.js b/src/components/angebote/angebotsuebersicht.js new file mode 100644 index 0000000..01a7e7e --- /dev/null +++ b/src/components/angebote/angebotsuebersicht.js @@ -0,0 +1,58 @@ +import { packages } from "../../shared/packages.js"; + +export function renderAngebotsuebersicht() { + // Wir suchen den Container, der in der angebotsuebersicht.html definiert wurde + const container = document.getElementById("packages-container"); + + // Sicherheitscheck: Wenn der Container nicht da ist, brechen wir ab + if (!container) { + console.warn("Container für Angebotsübersicht nicht gefunden."); + return; + } + + // Container leeren (falls die Funktion mehrfach aufgerufen wird) + container.innerHTML = ""; + + // Durch jedes Paket iterieren und das HTML generieren + packages.forEach((pkg) => { + // Highlight-Badge nur anzeigen, wenn es eins gibt + const highlightHtml = pkg.highlight + ? `${pkg.highlight}` + : ""; + + const cardHtml = ` +
+ +
+ ${pkg.type} + ${highlightHtml} +
+ +

${pkg.title}

+

${pkg.description}

+ +
+
+
Fokus
+
${pkg.fokus}
+
+
+
Anamnese
+
${pkg.anamnese}
+
+
+
Begleitung
+
${pkg.begleitung}
+
+
+ + + ${pkg.buttonText} + +
+ `; + + // Das generierte HTML dem Container hinzufügen + container.innerHTML += cardHtml; + }); +} diff --git a/src/shared/packages.js b/src/shared/packages.js new file mode 100644 index 0000000..76dac1a --- /dev/null +++ b/src/shared/packages.js @@ -0,0 +1,44 @@ +export const packages = [ + { + id: "ernaehrung-starter", + type: "STARTER", + title: "Für den sicheren Einstieg in die Sporternährung", + description: + "Für Menschen 50+, die mit Triathlon beginnen und ihre Ernährung an die neue Belastung anpassen möchten.", + fokus: "Grundlagen der Makronährstoffe, Hydration im Training und Gewichtsmanagement.", + anamnese: + "Zu Beginn gehört eine ausführliche gemeinsame Anamnese dazu, damit deine Essgewohnheiten und Ziele sauber eingeordnet werden.", + begleitung: + "Ein individueller Basis-Ernährungsplan und regelmäßige Check-ins im ersten Monat.", + buttonText: "Starter-Paket ansehen", + highlight: null, + }, + { + id: "ernaehrung-standard", + type: "STANDARD", + title: "Für Best Ager mit ersten Erfahrungen und klaren Zielen", + description: + "Für Athletinnen und Athleten, die ihre Ernährung für die Kurzdistanz und im Alltag gezielt weiterentwickeln wollen.", + fokus: "Carb-Loading, Pacing-Strategien für den Magen und Timing der Nahrungsaufnahme.", + anamnese: + "Auch hier startet das Coaching mit einer ausführlichen gemeinsamen Anamnese, damit Trainingsrealität, Erfahrung und Verträglichkeit präzise erfasst werden.", + begleitung: + "Monatliche Anpassung des Plans und enger Austausch bei Magen-Darm-Herausforderungen.", + buttonText: "Standard-Paket ansehen", + highlight: "BESONDERS PASSEND", + }, + { + id: "ernaehrung-premium", + type: "PREMIUM", + title: "Für maximale Individualität mit klarem Fokus", + description: + "Für Menschen, die sich eine besonders enge Coaching-Beziehung und laufende Anpassung ihrer Ernährung wünschen.", + fokus: "Individuelle Stoffwechselanalyse, Mikronährstoff-Optimierung und Raceday-Nutrition.", + anamnese: + "Wie in allen Paketen ist eine ausführliche gemeinsame Anamnese enthalten, damit Betreuung, Regeneration und Zielbild von Beginn an abgestimmt werden.", + begleitung: + "Wöchentliche Anpassungen, direkte Feedback-Schleifen und passgenaue Einkaufslisten.", + buttonText: "Premium-Paket ansehen", + highlight: null, + }, +]; diff --git a/src/tests/angebotsuebersicht.test.js b/src/tests/angebotsuebersicht.test.js new file mode 100644 index 0000000..08dfee6 --- /dev/null +++ b/src/tests/angebotsuebersicht.test.js @@ -0,0 +1,36 @@ +export async function renderAngebotsuebersicht() { + const container = document.getElementById("packages-container"); + if (!container) return; + + try { + // 1. Daten vom Backend des Kollegen abfragen + const response = await fetch("/api/angebote"); // Die genaue URL musst du den Kollegen fragen + const backendPackages = await response.json(); + + container.innerHTML = ""; + + // 2. Mit den echten Daten die Karten generieren + backendPackages.forEach((pkg) => { + const highlightHtml = pkg.highlight + ? `${pkg.highlight}` + : ""; + + const cardHtml = ` +
+
+ ${pkg.type} + ${highlightHtml} +
+

${pkg.title}

+

${pkg.description}

+ + ${pkg.buttonText} +
+ `; + container.innerHTML += cardHtml; + }); + } catch (error) { + console.error("Fehler beim Laden der Angebote vom Backend:", error); + container.innerHTML = "

Angebote konnten nicht geladen werden.

"; + } +} diff --git a/src/tests/packages.test.js b/src/tests/packages.test.js new file mode 100644 index 0000000..d957691 --- /dev/null +++ b/src/tests/packages.test.js @@ -0,0 +1,19 @@ +import { packages } from "../shared/packages.js"; + +describe("Angebots-Daten (packages.js)", () => { + test("sollte ein Array mit Angeboten exportieren", () => { + expect(Array.isArray(nutritionPackages)).toBe(true); + expect(nutritionPackages.length).toBeGreaterThan(0); + }); + + test("jedes Paket muss eine ID und einen Titel für das Routing besitzen", () => { + nutritionPackages.forEach((pkg) => { + expect(pkg).toHaveProperty("id"); + expect(pkg).toHaveProperty("title"); + expect(pkg).toHaveProperty("buttonText"); + // Prüft, ob die ID das korrekte Format für die URLs hat + expect(typeof pkg.id).toBe("string"); + expect(pkg.id.length).toBeGreaterThan(0); + }); + }); +});