Initial commit: ANOUMA website with Payload CMS, WebRTC meetings, and booking system
- Next.js 16 App Router site with the ANOUMA design system - Payload CMS (PostgreSQL) for offers, events, posts and page content - WebRTC video-call system with custom signaling server - SMTP email reminders and booking-request notifications - Customer accounts, calendar-based availability, and booking workflow
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import type { GlobalConfig } from "payload";
|
||||
import { isAdmin } from "@/access";
|
||||
|
||||
export const About: GlobalConfig = {
|
||||
slug: "about",
|
||||
label: "Über mich",
|
||||
admin: {
|
||||
description: "Inhalt der Seite „Über mich“.",
|
||||
group: "Seiteninhalte",
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
update: isAdmin,
|
||||
},
|
||||
fields: [
|
||||
{ name: "eyebrow", type: "text", label: "Kicker" },
|
||||
{ name: "title", type: "text", label: "Überschrift", required: true },
|
||||
{ name: "portrait", type: "upload", relationTo: "media", label: "Portraitbild" },
|
||||
{ name: "body", type: "richText", label: "Haupttext", required: true },
|
||||
{
|
||||
type: "collapsible",
|
||||
label: "Abschließendes Zitat",
|
||||
fields: [
|
||||
{ name: "closingLead", type: "text", label: "Einleitung" },
|
||||
{ name: "closingHighlight", type: "text", label: "Hervorgehobenes Zitat" },
|
||||
{ name: "closingParagraph", type: "textarea", label: "Abschlusstext" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { GlobalConfig } from "payload";
|
||||
import { isAdmin } from "@/access";
|
||||
|
||||
export const AktuellesIntro: GlobalConfig = {
|
||||
slug: "aktuelles-intro",
|
||||
label: "Aktuelles (Einleitung)",
|
||||
admin: {
|
||||
description: "Kopftext der Aktuelles-Seite. Die Beiträge selbst werden in der Sammlung „Beiträge“ gepflegt.",
|
||||
group: "Seiteninhalte",
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
update: isAdmin,
|
||||
},
|
||||
fields: [
|
||||
{ name: "eyebrow", type: "text", label: "Kicker" },
|
||||
{ name: "title", type: "text", label: "Überschrift", required: true },
|
||||
{ name: "lead", type: "textarea", label: "Einleitungstext" },
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { GlobalConfig } from "payload";
|
||||
import { isAdmin } from "@/access";
|
||||
|
||||
export const AngeboteIntro: GlobalConfig = {
|
||||
slug: "angebote-intro",
|
||||
label: "Angebote (Einleitung)",
|
||||
admin: {
|
||||
description: "Kopftext der Angebote-Übersichtsseite. Die Angebote selbst werden in der Sammlung „Angebote“ gepflegt.",
|
||||
group: "Seiteninhalte",
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
update: isAdmin,
|
||||
},
|
||||
fields: [
|
||||
{ name: "eyebrow", type: "text", label: "Kicker" },
|
||||
{ name: "title", type: "text", label: "Überschrift", required: true },
|
||||
{ name: "lead", type: "textarea", label: "Einleitungstext" },
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { GlobalConfig } from "payload";
|
||||
import { isAdmin } from "@/access";
|
||||
|
||||
export const Booking: GlobalConfig = {
|
||||
slug: "booking",
|
||||
label: "Termin buchen",
|
||||
admin: {
|
||||
description: "Inhalt der Seite „Termin buchen“.",
|
||||
group: "Seiteninhalte",
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
update: isAdmin,
|
||||
},
|
||||
fields: [
|
||||
{ name: "eyebrow", type: "text", label: "Kicker" },
|
||||
{ name: "title", type: "text", label: "Überschrift", required: true },
|
||||
{ name: "lead", type: "textarea", label: "Einleitungstext" },
|
||||
{
|
||||
name: "steps",
|
||||
type: "array",
|
||||
label: "Ablaufschritte",
|
||||
minRows: 1,
|
||||
maxRows: 6,
|
||||
fields: [
|
||||
{ name: "title", type: "text", label: "Titel", required: true },
|
||||
{ name: "text", type: "textarea", label: "Beschreibung", required: true },
|
||||
],
|
||||
},
|
||||
{ name: "formNote", type: "textarea", label: "Hinweis unter dem Formular" },
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { GlobalConfig } from "payload";
|
||||
import { isAdmin } from "@/access";
|
||||
|
||||
export const BookingSettings: GlobalConfig = {
|
||||
slug: "booking-settings",
|
||||
label: "Buchungseinstellungen",
|
||||
admin: {
|
||||
description: "Adresse für Vor-Ort-Termine (wird für den Maps-Link verwendet).",
|
||||
group: "Seiteninhalte",
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
update: isAdmin,
|
||||
},
|
||||
fields: [
|
||||
{ name: "locationName", type: "text", label: "Name des Ortes", defaultValue: "Anouma" },
|
||||
{ name: "street", type: "text", label: "Straße und Hausnummer" },
|
||||
{ name: "postalCode", type: "text", label: "PLZ" },
|
||||
{ name: "city", type: "text", label: "Ort" },
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { GlobalConfig } from "payload";
|
||||
import { isAdmin } from "@/access";
|
||||
|
||||
export const Contact: GlobalConfig = {
|
||||
slug: "contact",
|
||||
label: "Kontakt",
|
||||
admin: {
|
||||
description: "Inhalt und Kontaktdaten der Kontakt-Seite.",
|
||||
group: "Seiteninhalte",
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
update: isAdmin,
|
||||
},
|
||||
fields: [
|
||||
{ name: "eyebrow", type: "text", label: "Kicker" },
|
||||
{ name: "title", type: "text", label: "Überschrift", required: true },
|
||||
{ name: "lead", type: "textarea", label: "Einleitungstext" },
|
||||
{
|
||||
type: "row",
|
||||
fields: [
|
||||
{ name: "email", type: "email", label: "E-Mail", required: true, admin: { width: "34%" } },
|
||||
{ name: "phone", type: "text", label: "Telefon", admin: { width: "33%" } },
|
||||
{ name: "region", type: "text", label: "Region / Ort", admin: { width: "33%" } },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
import type { GlobalConfig } from "payload";
|
||||
import { isAdmin } from "@/access";
|
||||
|
||||
export const Home: GlobalConfig = {
|
||||
slug: "home",
|
||||
label: "Startseite",
|
||||
admin: {
|
||||
description: "Bearbeitbare Texte der Startseite (Hero, Über-mich-Teaser, Philosophie, CTA).",
|
||||
group: "Seiteninhalte",
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
update: isAdmin,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
type: "tabs",
|
||||
tabs: [
|
||||
{
|
||||
label: "Hero",
|
||||
fields: [
|
||||
{
|
||||
name: "heroEyebrow",
|
||||
type: "text",
|
||||
label: "Kicker (kleiner Text über der Überschrift)",
|
||||
},
|
||||
{ name: "heroTitle", type: "text", label: "Überschrift", required: true },
|
||||
{ name: "heroHighlight", type: "textarea", label: "Hervorgehobener Satz" },
|
||||
{ name: "heroSupporting", type: "textarea", label: "Ergänzender Text" },
|
||||
{ name: "heroImage", type: "upload", relationTo: "media", label: "Bild" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Über mich (Teaser)",
|
||||
fields: [
|
||||
{ name: "aboutEyebrow", type: "text", label: "Kicker" },
|
||||
{ name: "aboutTitle", type: "text", label: "Überschrift" },
|
||||
{ name: "aboutText", type: "richText", label: "Text" },
|
||||
{ name: "aboutImage", type: "upload", relationTo: "media", label: "Bild" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Philosophie",
|
||||
fields: [
|
||||
{ name: "valuesEyebrow", type: "text", label: "Kicker" },
|
||||
{ name: "valuesTitle", type: "text", label: "Überschrift" },
|
||||
{
|
||||
name: "values",
|
||||
type: "array",
|
||||
label: "Werte",
|
||||
minRows: 1,
|
||||
maxRows: 6,
|
||||
fields: [
|
||||
{ name: "title", type: "text", label: "Titel", required: true },
|
||||
{ name: "quote", type: "textarea", label: "Zitat", required: true },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Aufruf am Ende (CTA)",
|
||||
fields: [
|
||||
{ name: "ctaTitle", type: "text", label: "Überschrift" },
|
||||
{ name: "ctaLead", type: "textarea", label: "Text" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
import type { GlobalConfig } from "payload";
|
||||
import { isAdmin } from "@/access";
|
||||
|
||||
export const MeetingSettings: GlobalConfig = {
|
||||
slug: "meeting-settings",
|
||||
label: "Video-Termin-Einstellungen",
|
||||
admin: {
|
||||
description: "Zentrale Zeitfenster für alle Online-Termine.",
|
||||
group: "Seiteninhalte",
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
update: isAdmin,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "participantJoinWindowMinutes",
|
||||
type: "number",
|
||||
label: "Teilnehmer dürfen beitreten (Minuten vor Beginn)",
|
||||
required: true,
|
||||
defaultValue: 30,
|
||||
min: 0,
|
||||
},
|
||||
{
|
||||
name: "hostJoinWindowMinutes",
|
||||
type: "number",
|
||||
label: "Host darf beitreten (Minuten vor Beginn)",
|
||||
required: true,
|
||||
defaultValue: 60,
|
||||
min: 0,
|
||||
},
|
||||
{
|
||||
name: "meetingCloseAfterMinutes",
|
||||
type: "number",
|
||||
label: "Meeting bleibt offen bis (Minuten nach Ende)",
|
||||
required: true,
|
||||
defaultValue: 30,
|
||||
min: 0,
|
||||
},
|
||||
],
|
||||
};
|
||||
Reference in New Issue
Block a user