feat: manage participation page via payload
This commit is contained in:
400
src/collections/Pages/participationFields.ts
Normal file
400
src/collections/Pages/participationFields.ts
Normal file
@@ -0,0 +1,400 @@
|
||||
import type { Field } from 'payload'
|
||||
|
||||
import { participationContent } from '@/spa/participationContent'
|
||||
|
||||
const uploadField = (name: string, label: string, description?: string): Field => ({
|
||||
name,
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
label,
|
||||
admin: description ? { description } : undefined,
|
||||
})
|
||||
|
||||
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 checkbox = (name: string, label: string, defaultValue = false): Field => ({
|
||||
name,
|
||||
type: 'checkbox',
|
||||
label,
|
||||
defaultValue,
|
||||
})
|
||||
|
||||
const sectionAdmin = (description: string) => ({
|
||||
description,
|
||||
initCollapsed: true,
|
||||
})
|
||||
|
||||
const linkGroup = (labelDefault: string, urlDefault: string): Field[] => [
|
||||
text('label', 'Label', labelDefault),
|
||||
text('url', 'URL', urlDefault),
|
||||
]
|
||||
|
||||
const iconOptions = [
|
||||
{ label: 'Alert circle', value: 'alertCircle' },
|
||||
{ label: 'Arrow right', value: 'arrowRight' },
|
||||
{ label: 'Building', value: 'building2' },
|
||||
{ label: 'Check', value: 'check' },
|
||||
{ label: 'Check circle', value: 'checkCircle2' },
|
||||
{ label: 'File text', value: 'fileText' },
|
||||
{ label: 'Map pin', value: 'mapPin' },
|
||||
{ label: 'Search', value: 'search' },
|
||||
{ label: 'Send', value: 'send' },
|
||||
{ label: 'Star', value: 'star' },
|
||||
{ label: 'Trending up', value: 'trendingUp' },
|
||||
{ label: 'Trophy', value: 'trophy' },
|
||||
{ label: 'User', value: 'user' },
|
||||
{ label: 'User check', value: 'userCheck' },
|
||||
{ label: 'User plus', value: 'userPlus' },
|
||||
{ label: 'Users', value: 'users' },
|
||||
]
|
||||
|
||||
const iconField = (defaultValue = 'star', dbName?: string): Field => ({
|
||||
name: 'icon',
|
||||
label: 'Icon',
|
||||
type: 'select',
|
||||
dbName,
|
||||
defaultValue,
|
||||
options: iconOptions,
|
||||
})
|
||||
|
||||
const factFields: Field[] = [text('label', 'Label'), textarea('desc', 'Description')]
|
||||
const ctaGroup = (name: string, label: string, labelDefault: string, urlDefault: string): Field => ({
|
||||
name,
|
||||
label,
|
||||
type: 'group',
|
||||
fields: linkGroup(labelDefault, urlDefault),
|
||||
})
|
||||
|
||||
export const participationFields: Field[] = [
|
||||
{
|
||||
name: 'participation',
|
||||
label: 'Participation page layout sections',
|
||||
type: 'group',
|
||||
admin: {
|
||||
description:
|
||||
'Edit the participation page in the same order it appears on the frontend. The generic Hero and Content tabs are hidden for this SPA-managed route.',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'hero',
|
||||
label: '01 · Hero',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Top image, eyebrow, headline, and intro copy.'),
|
||||
fields: [
|
||||
uploadField('backgroundImage', 'Background image', `Current frontend image: /images/${participationContent.hero.backgroundImageFilename}`),
|
||||
text('imageAlt', 'Image alt text', participationContent.hero.imageAlt),
|
||||
text('eyebrow', 'Eyebrow', participationContent.hero.eyebrow),
|
||||
textarea('heading', 'Headline', participationContent.hero.heading),
|
||||
textarea('description', 'Intro paragraph', participationContent.hero.description),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'process',
|
||||
label: '02 · Weg zur Auszeichnung timeline',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Timeline section rendered directly after the hero.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', participationContent.process.eyebrow),
|
||||
textarea('heading', 'Heading', participationContent.process.heading),
|
||||
textarea('description', 'Intro paragraph', participationContent.process.description),
|
||||
text('scrollHint', 'Desktop scroll hint', participationContent.process.scrollHint),
|
||||
text('progressLabel', 'Desktop progress label', participationContent.process.progressLabel),
|
||||
{
|
||||
name: 'steps',
|
||||
label: 'Process steps',
|
||||
type: 'array',
|
||||
dbName: 'proc_steps',
|
||||
defaultValue: participationContent.process.steps,
|
||||
fields: [text('step', 'Step number'), text('title', 'Title'), textarea('desc', 'Description'), text('date', 'Date'), iconField('fileText')],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'eligibility',
|
||||
label: '03 · Eligibility section',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Cream eligibility section with criteria rows, notes, and CTAs.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', participationContent.eligibility.eyebrow),
|
||||
textarea('heading', 'Heading', participationContent.eligibility.heading),
|
||||
textarea('description', 'Intro paragraph', participationContent.eligibility.description),
|
||||
ctaGroup('primaryCta', 'Primary CTA', participationContent.eligibility.primaryCta.label, participationContent.eligibility.primaryCta.url),
|
||||
ctaGroup('secondaryCta', 'Secondary CTA', participationContent.eligibility.secondaryCta.label, participationContent.eligibility.secondaryCta.url),
|
||||
{
|
||||
name: 'criteria',
|
||||
label: 'Eligibility rows',
|
||||
type: 'array',
|
||||
dbName: 'elig_crit',
|
||||
defaultValue: participationContent.eligibility.criteria,
|
||||
fields: [text('num', 'Number'), text('title', 'Title'), textarea('body', 'Body'), iconField('mapPin')],
|
||||
},
|
||||
{
|
||||
name: 'notes',
|
||||
label: 'Additional notes',
|
||||
type: 'array',
|
||||
dbName: 'elig_notes',
|
||||
defaultValue: participationContent.eligibility.notes,
|
||||
fields: [text('title', 'Title'), textarea('body', 'Body'), iconField('building2')],
|
||||
},
|
||||
text('nudgeText', 'Bottom nudge text', participationContent.eligibility.nudgeText),
|
||||
ctaGroup('nudgeCta', 'Bottom CTA', participationContent.eligibility.nudgeCta.label, participationContent.eligibility.nudgeCta.url),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'evaluation',
|
||||
label: '04 · Criteria / evaluation section',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Navy evaluation section with image, link, and criteria grid.'),
|
||||
fields: [
|
||||
uploadField('image', 'Image', `Current frontend image: /images/${participationContent.evaluation.imageFilename}`),
|
||||
text('imageAlt', 'Image alt text', participationContent.evaluation.imageAlt),
|
||||
text('eyebrow', 'Eyebrow', participationContent.evaluation.eyebrow),
|
||||
textarea('heading', 'Heading', participationContent.evaluation.heading),
|
||||
textarea('body', 'Body copy', participationContent.evaluation.body),
|
||||
ctaGroup('link', 'External criteria link', participationContent.evaluation.link.label, participationContent.evaluation.link.url),
|
||||
{
|
||||
name: 'criteria',
|
||||
label: 'Evaluation criteria',
|
||||
type: 'array',
|
||||
dbName: 'eval_crit',
|
||||
defaultValue: participationContent.evaluation.criteria,
|
||||
fields: factFields,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'applicationWays',
|
||||
label: '05 · Application paths',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Cream section explaining proposal, self-application, and special award paths.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', participationContent.applicationWays.eyebrow),
|
||||
textarea('heading', 'Heading', participationContent.applicationWays.heading),
|
||||
textarea('description', 'Intro paragraph', participationContent.applicationWays.description),
|
||||
text('recommendedLabel', 'Featured card label', participationContent.applicationWays.recommendedLabel),
|
||||
{
|
||||
name: 'institutions',
|
||||
label: 'Proposal institutions',
|
||||
type: 'array',
|
||||
dbName: 'app_inst',
|
||||
defaultValue: participationContent.applicationWays.institutions,
|
||||
fields: [textarea('text', 'Institution')],
|
||||
},
|
||||
{
|
||||
name: 'ways',
|
||||
label: 'Application path cards',
|
||||
type: 'array',
|
||||
dbName: 'app_ways',
|
||||
defaultValue: participationContent.applicationWays.ways,
|
||||
fields: [
|
||||
text('label', 'Path label'),
|
||||
textarea('title', 'Title'),
|
||||
textarea('desc', 'Description'),
|
||||
iconField('send', 'ico'),
|
||||
checkbox('featured', 'Featured card'),
|
||||
{
|
||||
name: 'listType',
|
||||
label: 'Detail list type',
|
||||
type: 'select',
|
||||
dbName: 'lt',
|
||||
defaultValue: 'facts',
|
||||
options: [
|
||||
{ label: 'Use proposal institutions list', value: 'institutions' },
|
||||
{ label: 'Use facts below', value: 'facts' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'facts',
|
||||
label: 'Fact rows',
|
||||
type: 'array',
|
||||
dbName: 'way_facts',
|
||||
fields: factFields,
|
||||
},
|
||||
ctaGroup('cta', 'CTA', 'Zum Formular', '#bewerben'),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'datesBanner',
|
||||
label: '06 · Dates banner',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Gold important-dates banner. Mobile and desktop labels differ slightly in the current design.'),
|
||||
fields: [
|
||||
text('heading', 'Heading', participationContent.datesBanner.heading),
|
||||
textarea('description', 'Desktop description', participationContent.datesBanner.description),
|
||||
{
|
||||
name: 'mobileItems',
|
||||
label: 'Mobile date items',
|
||||
type: 'array',
|
||||
dbName: 'date_mob',
|
||||
defaultValue: participationContent.datesBanner.mobileItems,
|
||||
fields: [text('date', 'Date'), text('label', 'Label')],
|
||||
},
|
||||
{
|
||||
name: 'desktopItems',
|
||||
label: 'Desktop date items',
|
||||
type: 'array',
|
||||
dbName: 'date_desk',
|
||||
defaultValue: participationContent.datesBanner.desktopItems,
|
||||
fields: [text('date', 'Date'), text('label', 'Label')],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'applicationForm',
|
||||
label: '07 · Application form wrapper',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Navy/gold section containing the application form and PDF upload links.'),
|
||||
fields: [
|
||||
uploadField('image', 'Form image', `Current frontend image: /images/${participationContent.applicationForm.imageFilename}`),
|
||||
text('imageAlt', 'Image alt text', participationContent.applicationForm.imageAlt),
|
||||
text('imageCaption', 'Image caption', participationContent.applicationForm.imageCaption),
|
||||
text('eyebrow', 'Eyebrow', participationContent.applicationForm.eyebrow),
|
||||
textarea('heading', 'Heading', participationContent.applicationForm.heading),
|
||||
textarea('description', 'Body copy', participationContent.applicationForm.description),
|
||||
{
|
||||
name: 'facts',
|
||||
label: 'Fact rows',
|
||||
type: 'array',
|
||||
dbName: 'form_facts',
|
||||
defaultValue: participationContent.applicationForm.facts,
|
||||
fields: [text('num', 'Number'), text('label', 'Label'), textarea('desc', 'Description')],
|
||||
},
|
||||
text('formEyebrow', 'Form eyebrow', participationContent.applicationForm.formEyebrow),
|
||||
ctaGroup('uploadCta', 'Top upload CTA', participationContent.applicationForm.uploadCta.label, participationContent.applicationForm.uploadCta.url),
|
||||
textarea('uploadPrompt', 'Bottom upload prompt', participationContent.applicationForm.uploadPrompt),
|
||||
ctaGroup('uploadFooterCta', 'Bottom upload CTA', participationContent.applicationForm.uploadFooterCta.label, participationContent.applicationForm.uploadFooterCta.url),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'form',
|
||||
label: '08 · Application form copy and logic labels',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Text, options, and eligibility thresholds used inside the multi-step application form.'),
|
||||
fields: [
|
||||
text('stepCompleteLabel', 'Completed step label', participationContent.form.stepCompleteLabel),
|
||||
text('backLabel', 'Back button label', participationContent.form.backLabel),
|
||||
text('nextLabel', 'Next button label', participationContent.form.nextLabel),
|
||||
text('submitLabel', 'Submit button label', participationContent.form.submitLabel),
|
||||
text('yesLabel', 'Yes option label', participationContent.form.yesLabel),
|
||||
text('noLabel', 'No option label', participationContent.form.noLabel),
|
||||
text('requiredSuffix', 'Required field suffix', participationContent.form.requiredSuffix),
|
||||
{
|
||||
name: 'validation',
|
||||
label: 'Validation messages',
|
||||
type: 'group',
|
||||
fields: [
|
||||
text('choose', 'Choose message', participationContent.form.validation.choose),
|
||||
text('required', 'Required message', participationContent.form.validation.required),
|
||||
text('invalidEmail', 'Invalid email message', participationContent.form.validation.invalidEmail),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'typeStep',
|
||||
label: 'Step 1 · Submission type',
|
||||
type: 'group',
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', participationContent.form.typeStep.eyebrow),
|
||||
text('heading', 'Heading', participationContent.form.typeStep.heading),
|
||||
text('selfTitle', 'Self-application title', participationContent.form.typeStep.selfTitle),
|
||||
textarea('selfDesc', 'Self-application description', participationContent.form.typeStep.selfDesc),
|
||||
text('nominationTitle', 'Nomination title', participationContent.form.typeStep.nominationTitle),
|
||||
textarea('nominationDesc', 'Nomination description', participationContent.form.typeStep.nominationDesc),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'selfSteps',
|
||||
label: 'Self-application step labels',
|
||||
type: 'array',
|
||||
dbName: 'self_steps',
|
||||
defaultValue: participationContent.form.selfSteps,
|
||||
fields: [text('label', 'Label'), iconField('trophy')],
|
||||
},
|
||||
{
|
||||
name: 'nominationSteps',
|
||||
label: 'Nomination step labels',
|
||||
type: 'array',
|
||||
dbName: 'nom_steps',
|
||||
defaultValue: participationContent.form.nominationSteps,
|
||||
fields: [text('label', 'Label'), iconField('trophy')],
|
||||
},
|
||||
{
|
||||
name: 'employeeOptions',
|
||||
label: 'Employee options',
|
||||
type: 'array',
|
||||
dbName: 'emp_opts',
|
||||
defaultValue: participationContent.form.employeeOptions,
|
||||
fields: [text('value', 'Value'), text('label', 'Label')],
|
||||
},
|
||||
{
|
||||
name: 'eligibility',
|
||||
label: 'Self-application eligibility step',
|
||||
type: 'group',
|
||||
fields: [
|
||||
text('allowedEmployeeValues', 'Allowed employee option values, comma-separated', participationContent.form.eligibility.allowedEmployeeValues),
|
||||
text('requiredBayernValue', 'Required Bavaria answer value', participationContent.form.eligibility.requiredBayernValue),
|
||||
text('eyebrow', 'Eyebrow', participationContent.form.eligibility.eyebrow),
|
||||
text('heading', 'Heading', participationContent.form.eligibility.heading),
|
||||
text('employeesLabel', 'Employees field label', participationContent.form.eligibility.employeesLabel),
|
||||
text('bayernLabel', 'Bavaria field label', participationContent.form.eligibility.bayernLabel),
|
||||
text('ownerLabel', 'Owner field label', participationContent.form.eligibility.ownerLabel),
|
||||
text('ineligibleHeading', 'Ineligible heading', participationContent.form.eligibility.ineligibleHeading),
|
||||
textarea('ineligibleBody', 'Ineligible body', participationContent.form.eligibility.ineligibleBody),
|
||||
text('ineligibleContactPrefix', 'Ineligible contact prefix', participationContent.form.eligibility.ineligibleContactPrefix),
|
||||
text('ineligibleContactEmail', 'Ineligible contact email', participationContent.form.eligibility.ineligibleContactEmail),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'selfContact',
|
||||
label: 'Self-application contact step',
|
||||
type: 'group',
|
||||
fields: Object.entries(participationContent.form.selfContact).map(([name, value]) => text(name, name, value)),
|
||||
},
|
||||
{
|
||||
name: 'selfSummary',
|
||||
label: 'Self-application summary step',
|
||||
type: 'group',
|
||||
fields: Object.entries(participationContent.form.selfSummary).map(([name, value]) => text(name, name, value)),
|
||||
},
|
||||
{
|
||||
name: 'nominationCompany',
|
||||
label: 'Nomination company step',
|
||||
type: 'group',
|
||||
fields: Object.entries(participationContent.form.nominationCompany).map(([name, value]) => text(name, name, value)),
|
||||
},
|
||||
{
|
||||
name: 'nominationContact',
|
||||
label: 'Nomination contact step',
|
||||
type: 'group',
|
||||
fields: Object.entries(participationContent.form.nominationContact).map(([name, value]) => text(name, name, value)),
|
||||
},
|
||||
{
|
||||
name: 'nominationSummary',
|
||||
label: 'Nomination summary step',
|
||||
type: 'group',
|
||||
fields: Object.entries(participationContent.form.nominationSummary).map(([name, value]) => text(name, name, value)),
|
||||
},
|
||||
{
|
||||
name: 'success',
|
||||
label: 'Success state copy',
|
||||
type: 'group',
|
||||
fields: Object.entries(participationContent.form.success).map(([name, value]) => text(name, name, value)),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
Reference in New Issue
Block a user