Initial commit: FL-Akademie LMS mit Docker, Admin, Portal und Dokumentation.
Made-with: Cursor
This commit is contained in:
148
app/admin/courses/[id]/edit/page.tsx
Normal file
148
app/admin/courses/[id]/edit/page.tsx
Normal file
@@ -0,0 +1,148 @@
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import {
|
||||
createLessonAction,
|
||||
createModuleAction,
|
||||
updateCourseAction,
|
||||
} from "@/app/admin/courses/actions";
|
||||
|
||||
type Props = { params: Promise<{ id: string }> };
|
||||
|
||||
export default async function AdminEditCoursePage({ params }: Props) {
|
||||
const { id } = await params;
|
||||
const course = await prisma.course.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
modules: {
|
||||
orderBy: { sortOrder: "asc" },
|
||||
include: { lessons: { orderBy: { sortOrder: "asc" } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!course) notFound();
|
||||
|
||||
const priceEuros = (course.priceCents / 100).toFixed(2);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p className="muted">
|
||||
<Link href="/admin/courses">← Alle Kurse</Link> ·{" "}
|
||||
<Link href={`/kurse/${course.slug}`}>Öffentliche Kursseite</Link>
|
||||
</p>
|
||||
<h1 className="page-title">Kurs bearbeiten</h1>
|
||||
<p className="muted subtitle">{course.title}</p>
|
||||
|
||||
<form action={updateCourseAction.bind(null, course.id)} className="panel form" style={{ maxWidth: 820 }}>
|
||||
<h2 style={{ marginTop: 0 }}>Stammdaten</h2>
|
||||
<label>
|
||||
Titel
|
||||
<input name="title" defaultValue={course.title} required />
|
||||
</label>
|
||||
<label>
|
||||
Slug
|
||||
<input name="slug" defaultValue={course.slug} required />
|
||||
</label>
|
||||
<label>
|
||||
Beschreibung
|
||||
<textarea name="description" defaultValue={course.description} />
|
||||
</label>
|
||||
<label>
|
||||
Anzeige-Autor
|
||||
<input name="authorName" defaultValue={course.authorName} required />
|
||||
</label>
|
||||
<label>
|
||||
Preis (EUR)
|
||||
<input name="priceEuros" type="number" step="0.01" min="0" defaultValue={priceEuros} />
|
||||
</label>
|
||||
<label>
|
||||
Abrechnungsintervall
|
||||
<select name="billingInterval" defaultValue={course.billingInterval}>
|
||||
<option value="NONE">Einmal / kein Abo</option>
|
||||
<option value="MONTH">Monatlich</option>
|
||||
<option value="QUARTER">Vierteljährlich</option>
|
||||
<option value="YEAR">Jährlich</option>
|
||||
</select>
|
||||
</label>
|
||||
<label className="stack" style={{ alignItems: "center" }}>
|
||||
<span style={{ display: "flex", gap: "0.5rem", alignItems: "center" }}>
|
||||
<input type="checkbox" name="published" defaultChecked={course.published} /> Veröffentlicht
|
||||
</span>
|
||||
</label>
|
||||
<button type="submit" className="btn btn-primary">
|
||||
Speichern
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div className="panel" style={{ marginTop: "1.25rem" }}>
|
||||
<h2 style={{ marginTop: 0 }}>Neues Modul</h2>
|
||||
<form action={createModuleAction.bind(null, course.id)} className="form" style={{ maxWidth: 720 }}>
|
||||
<label>
|
||||
Modultitel
|
||||
<input name="title" required />
|
||||
</label>
|
||||
<button type="submit" className="btn btn-ghost">
|
||||
Modul hinzufügen
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div className="panel" style={{ marginTop: "1.25rem" }}>
|
||||
<h2 style={{ marginTop: 0 }}>Neue Lektion</h2>
|
||||
<form action={createLessonAction.bind(null, course.id)} className="form" style={{ maxWidth: 720 }}>
|
||||
<label>
|
||||
Modul
|
||||
<select name="moduleId" required defaultValue={course.modules[0]?.id ?? ""}>
|
||||
<option value="" disabled>
|
||||
Modul wählen…
|
||||
</option>
|
||||
{course.modules.map((m) => (
|
||||
<option key={m.id} value={m.id}>
|
||||
{m.title}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Lektionstitel
|
||||
<input name="lessonTitle" required />
|
||||
</label>
|
||||
<label>
|
||||
Slug (optional)
|
||||
<input name="lessonSlug" placeholder="wird sonst aus dem Titel erzeugt" />
|
||||
</label>
|
||||
<label>
|
||||
Inhalt (HTML)
|
||||
<textarea name="contentHtml" placeholder="<p>…</p>" />
|
||||
</label>
|
||||
<button type="submit" className="btn btn-ghost">
|
||||
Lektion hinzufügen
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div className="panel" style={{ marginTop: "1.25rem" }}>
|
||||
<h2 style={{ marginTop: 0 }}>Kurrikulum</h2>
|
||||
{course.modules.length === 0 ? (
|
||||
<p className="muted">Noch keine Module.</p>
|
||||
) : (
|
||||
<ul className="curriculum">
|
||||
{course.modules.map((m) => (
|
||||
<li key={m.id}>
|
||||
<div className="module-title">{m.title}</div>
|
||||
<ul className="curriculum">
|
||||
{m.lessons.map((l) => (
|
||||
<li key={l.id}>
|
||||
<Link href={`/kurse/${course.slug}/lektionen/${l.slug}`}>{l.title}</Link>{" "}
|
||||
<span className="muted">({l.slug})</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user