US2.1: Datenstruktur, Komponenten-Aufbau, Styling, Testing
parent
5851668bd8
commit
ef0745e59d
|
|
@ -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>
|
||||||
|
|
@ -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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
@ -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>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue