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 @@
+
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}
+
+
+
+
+
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);
+ });
+ });
+});