/* Seite KI-Schulungen (ki-schulungen.html). Lädt dieselben gemeinsamen Skripte wie alle Seiten plus
diese Datei und meldet ihre Komponente über window.SAWORA_SEITEN an (siehe app.jsx).
Aufbau: Kopf, klebende Ankerleiste, dann acht Abschnitte von „Was lernt mein Team?“ bis zur Anfrage.
Verdichtet, damit die lange Seite schnell erfassbar bleibt: Nutzen als Zeilenliste, Module als
Akkordeon, Formate als Vergleichstabelle, Fragen als Liste mit Antwortbereich, Anfrage zweispaltig.
Bewusst ohne Preis-, Dauer-, Zertifikats-, Förder- oder Ergebnisversprechen: Preise, Termine und
Umfang klärt das Erstgespräch. Angebunden an die vorhandenen Bausteine (components.jsx: PageHero,
SectionHead, Lernpfad; funnel.jsx: Field) — keine eigene Routing- oder Designlogik. */
// Auswahlfeld im Stil von Field (funnel.jsx); jede Auswahl hat „Noch offen“ als Vorgabe
function SchulungAuswahl({ id, label, value, onChange, optionen }) {
return (
);
}
// Mehrzeiliges Feld im Stil von Field (funnel.jsx); maxLength hält den Freitext knapp
function SchulungText({ id, label, value, onChange, error, hint, placeholder, maxLength = 1200, rows = 5 }) {
const errId = id + "-fehler";
return (
);
}
/* ---------------- Inhalte der Seite ---------------- */
// Ankerleiste: Nummern und Namen der acht Abschnitte, damit die lange Seite springbar bleibt
const SCHULUNG_NAV = [
["01", "Warum", "warum"],
["02", "Für wen", "fuer-wen"],
["03", "Inhalte", "inhalte"],
["04", "Formate", "formate"],
["05", "Kurse", "kurse"],
["06", "Ablauf", "ablauf"],
["07", "Ergebnis", "ergebnis"],
["08", "Fragen", "fragen"],
["09", "Buchung", "anfrage"],
];
const SCHULUNG_NUTZEN = [
{ Icon: BookOpen, titel: "Verstehen, was KI leisten kann.", text: "Wir ordnen ein, wofür sich KI-Werkzeuge eignen und wofür nicht — sachlich, ohne Hype und ohne Fachchinesisch." },
{ Icon: Zap, titel: "An eigenen Aufgaben üben.", text: "Wir arbeiten mit typischen Aufgaben aus Ihrem Betrieb, damit das Gelernte direkt im Alltag anwendbar ist." },
{ Icon: ShieldCheck, titel: "Grenzen und Datenrisiken erkennen.", text: "Ihr Team lernt, Ergebnisse zu prüfen, vertrauliche Daten zu schützen und Entscheidungen selbst zu treffen." },
];
const SCHULUNG_ZIELGRUPPEN = [
{ Icon: Users, titel: "Teams, die starten", text: "Wenn KI-Werkzeuge bisher kaum genutzt werden und ein gemeinsamer, verlässlicher Einstieg fehlt." },
{ Icon: TrendingUp, titel: "Führungskräfte", text: "Wenn Sie einschätzen möchten, wo sich KI lohnt, welcher Aufwand entsteht und was Ihr Team dafür braucht." },
{ Icon: Settings, titel: "Mitarbeitende", text: "Wenn bestehende Aufgaben leichter werden sollen — etwa bei Texten, Recherche oder Zusammenfassungen." },
];
// Module als Zeilen: kurz und überprüfbar, Details erst auf Klick
const SCHULUNG_MODULE = [
{ nr: "01", titel: "Grundlagen und Grenzen", text: "Wie KI-Werkzeuge arbeiten, was sie zuverlässig können und wo sie sich irren.",
punkte: ["Was ein Sprachmodell tut — und was nicht", "Typische Fehler erkennen, bevor sie Arbeit kosten"] },
{ nr: "02", titel: "Gute Anweisungen (Prompts)", text: "Wie aus einer vagen Aufgabe eine brauchbare Anweisung wird — und warum Kontext alles ist.",
punkte: ["Rolle, Ziel, Kontext und Format vorgeben", "Eine Anweisung schrittweise verbessern"] },
{ nr: "03", titel: "Recherche, Texte, Zusammenfassungen prüfen", text: "Wie Sie Ergebnisse kontrollieren, Quellen hinterfragen und Fehler früh erkennen.",
punkte: ["Ergebnisse gegen die Quelle prüfen", "Wann ein Ergebnis nicht verwendbar ist"] },
{ nr: "04", titel: "Anwendungsfälle im eigenen Betrieb", text: "Wir sammeln Aufgaben aus Ihrem Alltag und probieren passende Werkzeuge direkt daran aus.",
punkte: ["Aufgaben sammeln und sortieren", "Passende Werkzeuge an Beispielen testen"] },
{ nr: "05", titel: "Daten und Freigaben im Team", text: "Welche Daten genutzt werden dürfen, was im Haus bleibt und welche Regeln Ihr Team braucht.",
punkte: ["Welche Angaben gehören nicht in ein Werkzeug", "Einfache Regeln für den Arbeitsalltag"] },
];
// Eine Anweisung als Anschauung — illustrativ, keine Aussage über Ihr Unternehmen
const SCHULUNG_BEISPIEL = {
schwach: "Schreib eine E-Mail.",
stark: "Schreibe eine kurze E-Mail an einen Bestandskunden: kurzer Dank für den Auftrag, genannter Liefertermin, Bitte um Rückmeldung bis Freitag. Ton: sachlich, höchstens 120 Wörter.",
};
// Formate als Vergleich: gleiche Zeilen, drei Spalten — statt drei unverbundener Karten
const SCHULUNG_FORMAT_SPALTEN = ["Für wen", "Schwerpunkt", "Ablauf im Termin", "Format"];
const SCHULUNG_FORMAT_ZEILEN = [
{
name: "Einstieg",
werte: ["Teams, die starten", "Grundlagen und Grenzen", "Überblick, erste Beispiele, Ihre Fragen", "Online oder vor Ort nach Absprache"],
},
{
name: "Praxis-Workshop im Team",
werte: ["Teams mit konkreten Aufgaben", "Anwendung an eigenen Aufgaben", "Üben an Beispielen aus Ihrem Betrieb", "Online oder vor Ort nach Absprache"],
},
{
name: "Vertiefende Begleitung",
werte: ["Teams mit ersten Erfahrungen", "Ausbau und Regeln im Team", "Aufbauende Termine zu einzelnen Themen", "Online oder vor Ort nach Absprache"],
},
];
const SCHULUNG_ABLAUF = [
{ when: "Schritt 01", title: "Bedarf verstehen", body: "Im kurzen Erstgespräch klären wir, wo Ihr Team steht und welche Aufgaben im Alltag anstehen." },
{ when: "Schritt 02", title: "Inhalte abstimmen", body: "Wir schlagen Module, Format und Umfang vor — abgestimmt auf Ihr Team und Ihre Aufgaben." },
{ when: "Schritt 03", title: "Gemeinsam üben", body: "Im Termin arbeiten wir an Beispielen aus Ihrem Betrieb und halten die Ergebnisse schriftlich fest." },
{ when: "Schritt 04", title: "Nächste Schritte festhalten", body: "Zum Abschluss legen wir fest, welche Aufgaben Ihr Team eigenständig weiterführt." },
];
const SCHULUNG_ERGEBNIS = [
"Ein gemeinsames Verständnis davon, was KI leisten kann — und was nicht.",
"Erste erprobte Anwendungen aus Ihrem eigenen Arbeitsalltag.",
"Klare Regeln für den Umgang mit Daten und Ergebnissen.",
"Eine Liste nächster Schritte, die zu Ihrem Team passt.",
];
// Was wir vor dem Termin klären — hält den Rahmen transparent, ohne feste Pakete zu versprechen
const SCHULUNG_VORAB = [
["Format", "online oder vor Ort"],
["Umfang", "passend zu Ihrem Team"],
["Werkzeuge", "nach Ihrem Bedarf"],
["Daten", "welche genutzt werden dürfen"],
];
const SCHULUNG_FAQ = [
{ q: "Brauchen wir Vorkenntnisse?", a: "Nein. Wir stimmen den Einstieg auf den Kenntnisstand Ihres Teams ab." },
{ q: "Geht es um ein bestimmtes KI-Tool?", a: "Wir wählen die Beispiele nach Ihrem Bedarf. Nennen Sie vorhandene Werkzeuge gern in der Anfrage." },
{ q: "Kann die Schulung auf unsere Branche zugeschnitten werden?", a: "Ja. Im Erstgespräch besprechen wir typische Aufgaben Ihres Teams und passende Übungen." },
{ q: "Online oder vor Ort?", a: "Beides ist nach Absprache möglich. Den passenden Rahmen klären wir mit Ihnen." },
{ q: "Was kostet die Schulung?", a: "Der Preis richtet sich nach Inhalt, Format und Umfang. Sie erhalten nach dem Erstgespräch ein individuelles Angebot." },
{ q: "Wie gehen Sie mit Unternehmensdaten um?", a: "Für erste Übungen genügen Beispieldaten. Welche Werkzeuge und echten Daten verwendet werden dürfen, klären wir vorab gemeinsam." },
];
const SCHULUNG_FORMAT_OPTIONEN = ["Noch offen", "Online", "Vor Ort"];
const SCHULUNG_GRUPPE_OPTIONEN = ["Noch offen", "1–5", "6–20", "21+"];
const SCHULUNG_SCHWERPUNKT_OPTIONEN = ["Noch offen", "Einstieg", "Praxis im Team", "Führung & Einführung"];
/* ---------------- Kurse und Preise (Demo-Daten aus kurse.js) ---------------- */
// Eine Quelle für Seite, Buchung und interne Mail: kurse.js. Fehlt die Datei, bleibt die Sektion leer,
// statt mit erfundenen Kursen zu arbeiten.
const SCHULUNG_KURSE = (typeof window !== "undefined" && Array.isArray(window.SAWORA_KURSE)) ? window.SAWORA_KURSE : [];
const SCHULUNG_TERMIN_OFFEN = (typeof window !== "undefined" && window.SAWORA_KURS_TERMIN_OFFEN) || "Noch offen";
// „1490“ → „1.490 €“
const kursPreis = (n) => Number(n).toLocaleString("de-DE") + " €";
// Kennzahlen aus den vorhandenen Listen abgeleitet – keine erfundenen Zahlen
const SCHULUNG_ZAHLEN = [
[SCHULUNG_KURSE.length, "Kurse zur Auswahl"],
[SCHULUNG_MODULE.length, "Module"],
[SCHULUNG_FORMAT_ZEILEN.length, "Formate"],
];
// Kurse und Preise stehen in kurse.js – die Demo-Daten sind dort als Platzhalter gekennzeichnet
const kursNach = (name) => SCHULUNG_KURSE.find((k) => k.name === name) || null;
const kursTermine = (kurs) => [SCHULUNG_TERMIN_OFFEN, ...((kurs && kurs.terme) || []), "Individueller Termin"];
/* ---------------- Bausteine ---------------- */
// Abschnitts-Hülle mit Abstand für die klebende Ankerleiste
function SchulungAbschnitt({ id, index, eyebrow, title, lead, aside, children, className = "" }) {
const ref = useReveal();
return (
{children}
);
}
// Klebende Ankerleiste (Mobbin: klebende Abschnittsleiste auf langen Seiten — Grammarly, Canva, Steep).
// Der Abschnitt im Blickfeld wird hervorgehoben, damit beim Scrollen erkennbar bleibt, wo man ist.
function SchulungAnker() {
const [aktiv, setAktiv] = useState(SCHULUNG_NAV[0][2]);
const listeRef = useRef(null);
useEffect(() => {
if (!("IntersectionObserver" in window)) return;
const ziele = SCHULUNG_NAV.map((eintrag) => document.getElementById(eintrag[2])).filter(Boolean);
if (!ziele.length) return;
// Schmaler Streifen in der Bildmitte: so ist fast immer genau ein Abschnitt aktiv
const io = new IntersectionObserver((eintraege) => {
const sichtbar = eintraege.filter((e) => e.isIntersecting).sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
if (sichtbar) setAktiv(sichtbar.target.id);
}, { rootMargin: "-45% 0px -50% 0px", threshold: 0 });
ziele.forEach((z) => io.observe(z));
return () => io.disconnect();
}, []);
// Aktiven Eintrag in der waagerecht scrollenden Leiste sichtbar halten
useEffect(() => {
const el = listeRef.current && listeRef.current.querySelector(".is-active");
if (el && el.scrollIntoView) el.scrollIntoView({ block: "nearest", inline: "center" });
}, [aktiv]);
return (
);
}
/* ---------------- 01 Warum diese Schulung ---------------- */
function WarumSchulung() {
return (
KI verstehen. Im Arbeitsalltag sinnvoll einsetzen.>}
lead="Die Schulung führt von den Grundlagen zu direkt anwendbaren Arbeitsweisen — an Aufgaben, die es bei Ihnen wirklich gibt."
>
{SCHULUNG_NUTZEN.map((n, i) => (
{n.titel}
{n.text}
))}
);
}
/* ---------------- 02 Für wen ---------------- */
function ZielgruppenSection() {
return (
Für Teams, die KI nutzbar machen wollen.>}
lead="Am meisten bringt die Schulung, wenn mehrere Personen aus Ihrem Team dabei sind. Sie richtet sich an kleine und mittlere Unternehmen."
>
{SCHULUNG_ZIELGRUPPEN.map((z, i) => (
{z.titel}
{z.text}
))}
);
}
/* ---------------- 03 Inhalte (Akkordeon je Modul) ---------------- */
function InhalteSection() {
const [offen, setOffen] = useState(0);
return (
Fünf Module, die wir auf Ihr Team zuschneiden.>}
lead="Die Auswahl ist ein Gesprächsanlass, kein fester Lehrplan: Wir stimmen die Schwerpunkte vorab gemeinsam ab. Ein Modul öffnet die Details."
>
{/* Beispiel: derselbe Auftrag, zweimal formuliert */}
Beispiel
Warum eine Anweisung mehr Kontext braucht — derselbe Auftrag, zweimal formuliert.
Zu vage
{SCHULUNG_BEISPIEL.schwach}
Besser
{SCHULUNG_BEISPIEL.stark}
);
}
/* ---------------- 04 Formate (Vergleichstabelle) ---------------- */
function FormateSection() {
return (
Drei mögliche Formate.>}
lead="Umfang und Inhalte passen wir an Ihr Team an. Welche Form zu Ihnen passt, klären wir im Erstgespräch."
>
Format
{SCHULUNG_FORMAT_SPALTEN.map((s) =>
{s}
)}
{SCHULUNG_FORMAT_ZEILEN.map((z) => (
{z.name}
{z.werte.map((w, i) =>
{w}
)}
))}
Online oder vor Ort nach AbspracheIndividuelles Angebot nach einem kurzen Erstgespräch
);
}
/* ---------------- 05 Kurse & Preise (Demo-Daten aus kurse.js) ---------------- */
function KursSection({ kurs, onKurs }) {
if (!SCHULUNG_KURSE.length) return null;
return (
Kurse mit festen Preisen und Terminen.>}
lead="Wählen Sie einen Kurs – die Buchung unten übernimmt ihn automatisch. Passt keiner, stimmen wir Umfang und Inhalt individuell ab."
aside={Demo-Daten}
>
Alle Preise netto, zzgl. MwSt.Kurse, Termine und Preise sind Demo-Daten und noch nicht final
);
}
/* ---------------- 06 Ablauf ---------------- */
function AblaufSection() {
return (
Vom Bedarf zu den nächsten Schritten.>}
lead="Vier Etappen — vom ersten Gespräch bis zu den Aufgaben, die Ihr Team eigenständig weiterführt."
>
{SCHULUNG_ABLAUF.map((s, i) => (
{s.when}
{s.title}
{String(i + 1).padStart(2, "0")}
{s.body}
))}
);
}
/* ---------------- 06 Erwartetes Ergebnis ---------------- */
function ErgebnisSection() {
return (
Was am Ende dasteht.>}
lead="Nach der Schulung kennt Ihr Team geeignete Einsatzfälle, kann erste Aufgaben eigenständig ausprobieren und weiß, wann menschliche Prüfung nötig ist."
>
{SCHULUNG_ERGEBNIS.map((t) => (
{t}
))}
Vorab geklärt
{SCHULUNG_VORAB.map(([k, v]) => (
{k}
{v}
))}
So kennen Sie den Rahmen, bevor Sie zusagen.
);
}
/* ---------------- 07 Häufige Fragen (Liste + Antwortbereich) ---------------- */
function FragenSection() {
const [aktiv, setAktiv] = useState(0);
const [offen, setOffen] = useState(0);
const tabsRef = useRef([]);
const n = SCHULUNG_FAQ.length;
const eintrag = SCHULUNG_FAQ[aktiv];
const onKeyDown = (e) => {
let next = null;
if (e.key === "ArrowDown" || e.key === "ArrowRight") next = (aktiv + 1) % n;
if (e.key === "ArrowUp" || e.key === "ArrowLeft") next = (aktiv - 1 + n) % n;
if (e.key === "Home") next = 0;
if (e.key === "End") next = n - 1;
if (next === null) return;
e.preventDefault();
setAktiv(next);
tabsRef.current[next] && tabsRef.current[next].focus();
};
return (
Häufige Fragen, ehrlich beantwortet.>}
lead="Kurz und konkret. Fehlt Ihre Frage, schreiben Sie sie gern in die Anfrage."
>
);
}
/* ---------------- 09 Buchung (Kurs, Termin, Kontaktdaten) ---------------- */
const SCHULUNG_LEER = {
name: "", company: "", email: "", phone: "",
trainingFormat: SCHULUNG_FORMAT_OPTIONEN[0],
participants: SCHULUNG_GRUPPE_OPTIONEN[0],
trainingFocus: SCHULUNG_SCHWERPUNKT_OPTIONEN[0],
message: "", datenschutz: false,
};
// Wie contactErrors in funnel.jsx; bei der Schulung ist Telefon freiwillig und die Datenschutz-Bestätigung Pflicht
function schulungErrors(d) {
const e = {};
if (!d.name.trim()) e.name = "Bitte geben Sie Ihren Namen an.";
if (!d.company.trim()) e.company = "Bitte geben Sie Ihre Firma an.";
if (!d.email.trim() || !/^\S+@\S+\.\S+$/.test(d.email)) e.email = "Bitte eine gültige E-Mail-Adresse angeben, z. B. max@firma.de.";
if (d.phone.trim() && d.phone.replace(/\D/g, "").length < 6) e.phone = "Bitte eine gültige Telefonnummer angeben (mind. 6 Ziffern) — oder das Feld leer lassen.";
if (!d.datenschutz) e.datenschutz = "Bitte bestätigen Sie den Hinweis zum Datenschutz.";
return e;
}
// Was nach dem Absenden passiert — keine automatische Buchung, keine erfundene Bestätigung
const SCHULUNG_DANACH = [
["Innerhalb von 24 Stunden", "Wir melden uns per E-Mail oder Telefon bei Ihnen."],
["Kurzes Erstgespräch", "Wir klären Bedarf, Format und Umfang — ohne Verkaufsdruck."],
["Ihr Angebot", "Sie erhalten ein individuelles Angebot mit den abgestimmten Inhalten."],
];
function AnfrageSection({ kurs, onKurs }) {
const zweistufig = SCHULUNG_KURSE.length > 0;
const [schritt, setSchritt] = useState(zweistufig ? 1 : 2);
const [termin, setTermin] = useState(SCHULUNG_TERMIN_OFFEN);
const [werte, setWerte] = useState(SCHULUNG_LEER);
const [fehler, setFehler] = useState({});
const [sending, setSending] = useState(false);
const [sendError, setSendError] = useState("");
const [gesendet, setGesendet] = useState(false);
const dankRef = useRef(null);
const schrittRef = useRef(null);
const id = "ki-schulungen";
const kursDaten = kursNach(kurs);
const termine = kursTermine(kursDaten);
const schritt1Fertig = !!kurs;
useEffect(() => { if (gesendet && dankRef.current) dankRef.current.focus(); }, [gesendet]);
// Passt der gewählte Termin nicht mehr zum Kurs (etwa nach „Kurs buchen“ im Abschnitt „Kurse“),
// fällt er auf „Noch offen“ zurück.
useEffect(() => { if (zweistufig && termine.indexOf(termin) === -1) setTermin(SCHULUNG_TERMIN_OFFEN); }, [kurs]);
// Nach dem Schrittwechsel den Fokus auf die Überschrift setzen (Tastatur und Screenreader)
useEffect(() => { if (schrittRef.current) schrittRef.current.focus({ preventScroll: true }); }, [schritt]);
const upd = (k, v) => {
setWerte((w) => ({ ...w, [k]: v }));
if (fehler[k]) setFehler((f) => ({ ...f, [k]: undefined }));
};
const senden = async (e) => {
e.preventDefault();
const f = schulungErrors(werte);
setFehler(f);
const erstes = ["name", "company", "email", "phone", "datenschutz"].find((k) => f[k]);
if (erstes) {
const el = document.getElementById(id + "-" + erstes);
if (el) el.focus();
return;
}
setSending(true);
setSendError("");
// Erfolg nur anzeigen, wenn die Anfrage wirklich angekommen ist – sonst ginge sie still verloren
let meldung = "Verbindungsfehler — bitte versuchen Sie es erneut.";
try {
const res = await fetch("/api-contact.php", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ...werte, type: "KI-Schulungen", kurs, termin, datenschutz: werte.datenschutz ? "ja" : "" }),
});
if (res.ok) { setSending(false); setGesendet(true); return; }
meldung = (await res.json().catch(() => ({}))).error || "Die Anfrage konnte nicht gesendet werden.";
} catch (err) {
console.error("Schulungsanfrage Fehler:", err);
}
setSendError(meldung);
setSending(false);
};
return (
Kurs buchen.>}
lead="Kurs und Termin wählen, Kontaktdaten ergänzen — wir bestätigen den Termin per E-Mail. Im Formular wird nichts bezahlt."
>
{!gesendet ? (
) : (
Vielen Dank!
Ihre Buchungsanfrage ist angekommen. Wir bestätigen den Termin innerhalb von 24 Stunden per E-Mail.
)}
);
}
/* ---------------- Seite ---------------- */
function KiSchulungenPage() {
// Gewählter Kurs: die Kurskarten setzen ihn, die Buchung übernimmt ihn
const [kurs, setKurs] = useState(SCHULUNG_KURSE.length ? SCHULUNG_KURSE[0].name : "");
const kursWaehlen = (k) => {
setKurs(k.name);
scrollToId("anfrage");
};
return (
KI-Schulungen, die im Arbeitsalltag ankommen.>}
lead="Wir zeigen Ihrem Team, wie es KI-Werkzeuge sinnvoll nutzt: von den Grundlagen bis zu konkreten Aufgaben aus Ihrem Unternehmen."
actions={<>
Kurs buchen }>Kurse ansehen
>}
facts={[[SCHULUNG_KURSE.length + " Kurse zur Auswahl", "primary"], ["Online oder vor Ort nach Absprache", "primary"], ["Antwort in unter 24 h", "secondary"]]}
/>
);
}
// app.jsx wählt die Seite über window.SAWORA_SEITEN (siehe App()); so bleibt eine Routinglogik
window.SAWORA_SEITEN = Object.assign(window.SAWORA_SEITEN || {}, { "ki-schulungen": KiSchulungenPage });