feat: implement newsletter subscription feature with new forms and database structure

- Added new newsletter subscription functionality to the participation page.
- Created a new `NewsletterForm` component to handle user subscriptions.
- Introduced `NewsletterSubscriptions` collection to manage subscriptions in the database.
- Developed migration script to set up necessary database tables and fields for the newsletter feature.
- Refactored participation content to remove deprecated newsletter phase data and integrate new structure.
- Updated the `Participation` page to utilize the new newsletter form and handle different application phases.
This commit is contained in:
syntaxbullet
2026-07-13 13:37:03 +02:00
parent 64049baef0
commit bd2e99ca91
20 changed files with 1033 additions and 566 deletions

View File

@@ -0,0 +1,78 @@
import type { Field, GlobalConfig } from 'payload'
import { authenticated } from '@/access/authenticated'
import { defaultNewsletterFormData, type NewsletterInterestCopy } from '@/spa/newsletterForm'
const text = (name: string, label: string, defaultValue: string): Field => ({
name,
type: 'text',
label,
defaultValue,
})
const textarea = (name: string, label: string, defaultValue: string): Field => ({
name,
type: 'textarea',
label,
defaultValue,
})
const variantFields = (defaults: NewsletterInterestCopy, benefitsDbName: string): Field[] => [
text('eyebrow', 'Linke Eyebrow', defaults.eyebrow),
textarea('heading', 'Linke Überschrift', defaults.heading),
textarea('body', 'Linker Beschreibungstext', defaults.body),
{
name: 'benefits',
label: 'Vorteile',
type: 'array',
dbName: benefitsDbName,
defaultValue: defaults.benefits,
fields: [text('num', 'Nummer', ''), text('label', 'Titel', ''), text('desc', 'Beschreibung', '')],
},
text('formEyebrow', 'Formular-Eyebrow', defaults.formEyebrow),
text('formTitle', 'Formular-Überschrift', defaults.formTitle),
textarea('formBody', 'Formular-Beschreibung', defaults.formBody),
text('emailLabel', 'E-Mail-Feldbezeichnung', defaults.emailLabel),
text('emailPlaceholder', 'E-Mail-Platzhalter', defaults.emailPlaceholder),
text('submitLabel', 'Button-Beschriftung', defaults.submitLabel),
textarea('privacy', 'Datenschutz-Hinweis', defaults.privacy),
text('validationRequired', 'Fehler: E-Mail fehlt', defaults.validationRequired),
text('validationInvalid', 'Fehler: E-Mail ungültig', defaults.validationInvalid),
textarea('submissionError', 'Fehler: Speichern fehlgeschlagen', defaults.submissionError),
text('successHeading', 'Erfolgsüberschrift', defaults.successHeading),
textarea('successBody', 'Erfolgstext', defaults.successBody),
text('footnote', 'Fußzeile normal', defaults.footnote),
text('footnoteStrong', 'Fußzeile hervorgehoben', defaults.footnoteStrong),
]
export const NewsletterForm: GlobalConfig = {
slug: 'newsletter-form',
label: 'Newsletter-Formular',
access: {
read: () => true,
update: authenticated,
},
admin: {
group: 'Formulare',
},
fields: [
{
name: 'evaluation',
label: 'Phase 02 · Jury / Auswertung',
type: 'group',
admin: {
description: 'Gemeinsamer Newsletter-Inhalt für Startseite und Teilnahme-Seite während der Auswertungsphase.',
},
fields: variantFields(defaultNewsletterFormData.evaluation, 'newsletter_eval_bens'),
},
{
name: 'completed',
label: 'Phase 03 · Preisverleihung abgeschlossen',
type: 'group',
admin: {
description: 'Gemeinsamer Newsletter-Inhalt für Startseite und Teilnahme-Seite nach Abschluss des Preisjahrgangs.',
},
fields: variantFields(defaultNewsletterFormData.completed, 'newsletter_done_bens'),
},
],
}