US2.1: Datenstruktur, Komponenten-Aufbau, Styling, Testing

majds
Majd Ibrahim 2026-09-24 16:36:53 +00:00
parent 5851668bd8
commit ef0745e59d
5 changed files with 168 additions and 0 deletions

View File

@ -0,0 +1,11 @@
<section class="packages-section" id="angebotsuebersicht-section">
<div class="packages-header">
<!-- Hier könnte noch eine Überschrift hin, falls gewünscht -->
<h2>Unsere Ernährungs-Pakete</h2>
</div>
<!-- Das ist der Container, den unser JS mit den Karten füllt -->
<div class="packages-container" id="packages-container">
<!-- Karten werden hier dynamisch von angebotsuebersicht.js injiziert -->
</div>
</section>

View File

@ -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
? `<span class="package-highlight">${pkg.highlight}</span>`
: "";
const cardHtml = `
<div class="package-card">
<div class="package-type-container">
<span class="package-type">${pkg.type}</span>
${highlightHtml}
</div>
<h3 class="package-title">${pkg.title}</h3>
<p class="package-desc">${pkg.description}</p>
<div class="package-details-box">
<div class="detail-item">
<div class="detail-title">Fokus</div>
<div class="detail-text">${pkg.fokus}</div>
</div>
<div class="detail-item">
<div class="detail-title">Anamnese</div>
<div class="detail-text">${pkg.anamnese}</div>
</div>
<div class="detail-item">
<div class="detail-title">Begleitung</div>
<div class="detail-text">${pkg.begleitung}</div>
</div>
</div>
<!-- HIER ist der wichtige Link für deinen Kollegen: -->
<a href="buchung.html?id=${pkg.id}" class="package-btn">${pkg.buttonText}</a>
</div>
`;
// Das generierte HTML dem Container hinzufügen
container.innerHTML += cardHtml;
});
}

View File

@ -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,
},
];

View File

@ -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
? `<span class="package-highlight">${pkg.highlight}</span>`
: "";
const cardHtml = `
<div class="package-card">
<div class="package-type-container">
<span class="package-type">${pkg.type}</span>
${highlightHtml}
</div>
<h3 class="package-title">${pkg.title}</h3>
<p class="package-desc">${pkg.description}</p>
<!-- ... Rest des HTMLs wie gehabt ... -->
<a href="buchung.html?id=${pkg.id}" class="package-btn">${pkg.buttonText}</a>
</div>
`;
container.innerHTML += cardHtml;
});
} catch (error) {
console.error("Fehler beim Laden der Angebote vom Backend:", error);
container.innerHTML = "<p>Angebote konnten nicht geladen werden.</p>";
}
}

View File

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