feat: add PartnerLogoMark component for dynamic partner logo rendering
This commit is contained in:
@@ -45,11 +45,12 @@ const phaseFields: Field[] = [
|
||||
|
||||
export const ApplicationPhase: GlobalConfig = {
|
||||
slug: 'application-phase',
|
||||
label: 'Bewerbungsphase',
|
||||
access: {
|
||||
read: () => true,
|
||||
},
|
||||
admin: {
|
||||
group: 'Site Settings',
|
||||
group: 'Website',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
||||
@@ -25,10 +25,12 @@ const socialFields = [
|
||||
|
||||
export const Footer: GlobalConfig = {
|
||||
slug: 'footer',
|
||||
label: 'Fußbereich',
|
||||
access: {
|
||||
read: () => true,
|
||||
},
|
||||
admin: {
|
||||
group: 'Website',
|
||||
livePreview: {
|
||||
url: () => '/',
|
||||
},
|
||||
|
||||
@@ -5,7 +5,6 @@ import React from 'react'
|
||||
import type { Header as HeaderType } from '@/payload-types'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { SearchIcon } from 'lucide-react'
|
||||
|
||||
export const HeaderNav: React.FC<{ data: HeaderType }> = ({ data }) => {
|
||||
const navItems = data?.navItems || []
|
||||
@@ -15,10 +14,6 @@ export const HeaderNav: React.FC<{ data: HeaderType }> = ({ data }) => {
|
||||
{navItems.map((item, i) => {
|
||||
return <Link key={i} href={item.path || '/'}>{item.label}</Link>
|
||||
})}
|
||||
<Link href="/search">
|
||||
<span className="sr-only">Search</span>
|
||||
<SearchIcon className="w-5 text-primary" />
|
||||
</Link>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,10 +25,12 @@ const socialFields = [
|
||||
|
||||
export const Header: GlobalConfig = {
|
||||
slug: 'header',
|
||||
label: 'Kopfbereich',
|
||||
access: {
|
||||
read: () => true,
|
||||
},
|
||||
admin: {
|
||||
group: 'Website',
|
||||
livePreview: {
|
||||
url: () => '/',
|
||||
},
|
||||
|
||||
@@ -4,11 +4,12 @@ import { defaultSiteSettings } from '@/spa/siteSettings'
|
||||
|
||||
export const SiteSettings: GlobalConfig = {
|
||||
slug: 'site-settings',
|
||||
label: 'Website-Einstellungen',
|
||||
access: {
|
||||
read: () => true,
|
||||
},
|
||||
admin: {
|
||||
group: 'Site Settings',
|
||||
group: 'Website',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
||||
@@ -31,17 +31,6 @@ const getPagesSitemap = unstable_cache(
|
||||
|
||||
const dateFallback = new Date().toISOString()
|
||||
|
||||
const defaultSitemap = [
|
||||
{
|
||||
loc: `${SITE_URL}/search`,
|
||||
lastmod: dateFallback,
|
||||
},
|
||||
{
|
||||
loc: `${SITE_URL}/posts`,
|
||||
lastmod: dateFallback,
|
||||
},
|
||||
]
|
||||
|
||||
const sitemap = results.docs
|
||||
? results.docs
|
||||
.filter((page) => Boolean(page?.slug))
|
||||
@@ -53,7 +42,7 @@ const getPagesSitemap = unstable_cache(
|
||||
})
|
||||
: []
|
||||
|
||||
return [...defaultSitemap, ...sitemap]
|
||||
return sitemap
|
||||
},
|
||||
['pages-sitemap'],
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ import { notFound } from 'next/navigation'
|
||||
import NextApp from '@/spa/NextApp'
|
||||
import { normalizeApplicationPhaseData, type SpaApplicationPhaseData } from '@/spa/applicationPhase'
|
||||
import { normalizeFooterData, normalizeHeaderData } from '@/spa/cmsNavigation'
|
||||
import type { CmsRouteDoc } from '@/spa/cmsRoute'
|
||||
import type { CmsRouteCollection, CmsRouteDoc } from '@/spa/cmsRoute'
|
||||
import { normalizeSiteSettings, type SpaSiteSettingsData } from '@/spa/siteSettings'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
@@ -16,7 +16,7 @@ type Args = {
|
||||
params: Promise<{ slug?: string[] }>
|
||||
}
|
||||
|
||||
type RouteCollection = 'pages' | 'posts' | 'events' | 'preistraeger'
|
||||
type RouteCollection = Exclude<CmsRouteCollection, 'partners'>
|
||||
|
||||
function routeTarget(pathname: string): { collection: RouteCollection; slug: string } {
|
||||
const parts = pathname.split('/').filter(Boolean)
|
||||
@@ -57,7 +57,7 @@ async function findRouteDoc(payload: Awaited<ReturnType<typeof getPayload>>, pat
|
||||
return doc ? { collection: target.collection, doc } : undefined
|
||||
}
|
||||
|
||||
async function findList(payload: Awaited<ReturnType<typeof getPayload>>, collection: RouteCollection, draft: boolean) {
|
||||
async function findList(payload: Awaited<ReturnType<typeof getPayload>>, collection: CmsRouteCollection, draft: boolean) {
|
||||
const result = await payload.find({
|
||||
collection,
|
||||
depth: 1,
|
||||
@@ -65,25 +65,33 @@ async function findList(payload: Awaited<ReturnType<typeof getPayload>>, collect
|
||||
overrideAccess: draft,
|
||||
limit: 300,
|
||||
pagination: false,
|
||||
...(collection === 'partners' ? { sort: 'sortOrder' } : {}),
|
||||
})
|
||||
|
||||
return result.docs
|
||||
}
|
||||
|
||||
async function findHomePage(payload: Awaited<ReturnType<typeof getPayload>>, draft: boolean) {
|
||||
async function findSupportPages(payload: Awaited<ReturnType<typeof getPayload>>, draft: boolean) {
|
||||
const result = await payload.find({
|
||||
collection: 'pages',
|
||||
depth: 1,
|
||||
draft,
|
||||
overrideAccess: draft,
|
||||
limit: 1,
|
||||
limit: 10,
|
||||
pagination: false,
|
||||
where: {
|
||||
or: [{ spaPath: { equals: '/' } }, { slug: { equals: 'startseite' } }, { slug: { equals: 'home' } }],
|
||||
or: [
|
||||
{ spaPath: { equals: '/' } },
|
||||
{ slug: { equals: 'startseite' } },
|
||||
{ slug: { equals: 'home' } },
|
||||
{ spaPath: { equals: '/netzwerk' } },
|
||||
{ slug: { equals: 'netzwerk' } },
|
||||
{ slug: { equals: 'network' } },
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
return result.docs[0]
|
||||
return result.docs
|
||||
}
|
||||
|
||||
export default async function Page({ params }: Args) {
|
||||
@@ -91,16 +99,17 @@ export default async function Page({ params }: Args) {
|
||||
const pathname = `/${slug.join('/')}`.replace(/\/$/, '') || '/'
|
||||
const payload = await getPayload({ config: configPromise })
|
||||
const { isEnabled: draft } = await draftMode()
|
||||
const [header, footer, siteSettings, applicationPhase, route, homePage, preistraeger, events, posts] = await Promise.all([
|
||||
const [header, footer, siteSettings, applicationPhase, route, supportPages, preistraeger, events, posts, partners] = await Promise.all([
|
||||
payload.findGlobal({ slug: 'header', depth: 1 }).catch(() => undefined),
|
||||
payload.findGlobal({ slug: 'footer', depth: 1 }).catch(() => undefined),
|
||||
payload.findGlobal({ slug: 'site-settings', depth: 1 }).catch(() => undefined),
|
||||
payload.findGlobal({ slug: 'application-phase', depth: 0 }).catch(() => undefined),
|
||||
findRouteDoc(payload, pathname, draft),
|
||||
findHomePage(payload, draft).catch(() => undefined),
|
||||
findSupportPages(payload, draft).catch(() => []),
|
||||
findList(payload, 'preistraeger', draft).catch(() => []),
|
||||
findList(payload, 'events', draft).catch(() => []),
|
||||
findList(payload, 'posts', draft).catch(() => []),
|
||||
findList(payload, 'partners', draft).catch(() => []),
|
||||
])
|
||||
|
||||
if (!route) notFound()
|
||||
@@ -116,10 +125,11 @@ export default async function Page({ params }: Args) {
|
||||
collection: route.collection,
|
||||
doc: route.doc as unknown as CmsRouteDoc,
|
||||
lists: {
|
||||
pages: homePage ? [homePage as unknown as CmsRouteDoc] : [],
|
||||
pages: supportPages as unknown as CmsRouteDoc[],
|
||||
preistraeger: preistraeger as unknown as CmsRouteDoc[],
|
||||
events: events as unknown as CmsRouteDoc[],
|
||||
posts: posts as unknown as CmsRouteDoc[],
|
||||
partners: partners as unknown as CmsRouteDoc[],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -19,8 +19,6 @@ import { HorizontalRuleFeatureClient as HorizontalRuleFeatureClient_e70f5e05f09f
|
||||
import { BlocksFeatureClient as BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { FolderTableCell as FolderTableCell_f9c02e79a4aed9a3924487c0cd4cafb1 } from '@payloadcms/next/rsc'
|
||||
import { FolderField as FolderField_f9c02e79a4aed9a3924487c0cd4cafb1 } from '@payloadcms/next/rsc'
|
||||
import { LinkToDoc as LinkToDoc_aead06e4cbf6b2620c5c51c9ab283634 } from '@payloadcms/plugin-search/client'
|
||||
import { ReindexButton as ReindexButton_aead06e4cbf6b2620c5c51c9ab283634 } from '@payloadcms/plugin-search/client'
|
||||
import { FolderTypeField as FolderTypeField_2b8867833a34864a02ddf429b0728a40 } from '@payloadcms/next/client'
|
||||
import { RowLabel as RowLabel_ec255a65fa6fa8d1faeb09cf35284224 } from '@/Header/RowLabel'
|
||||
import { RowLabel as RowLabel_1f6ff6ff633e3695d348f4f3c58f1466 } from '@/Footer/RowLabel'
|
||||
@@ -51,8 +49,6 @@ export const importMap = {
|
||||
"@payloadcms/richtext-lexical/client#BlocksFeatureClient": BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/next/rsc#FolderTableCell": FolderTableCell_f9c02e79a4aed9a3924487c0cd4cafb1,
|
||||
"@payloadcms/next/rsc#FolderField": FolderField_f9c02e79a4aed9a3924487c0cd4cafb1,
|
||||
"@payloadcms/plugin-search/client#LinkToDoc": LinkToDoc_aead06e4cbf6b2620c5c51c9ab283634,
|
||||
"@payloadcms/plugin-search/client#ReindexButton": ReindexButton_aead06e4cbf6b2620c5c51c9ab283634,
|
||||
"@payloadcms/next/client#FolderTypeField": FolderTypeField_2b8867833a34864a02ddf429b0728a40,
|
||||
"@/Header/RowLabel#RowLabel": RowLabel_ec255a65fa6fa8d1faeb09cf35284224,
|
||||
"@/Footer/RowLabel#RowLabel": RowLabel_1f6ff6ff633e3695d348f4f3c58f1466,
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
import type { Post, ArchiveBlock as ArchiveBlockProps } from '@/payload-types'
|
||||
|
||||
import configPromise from '@payload-config'
|
||||
import { getPayload } from 'payload'
|
||||
import React from 'react'
|
||||
import RichText from '@/components/RichText'
|
||||
|
||||
import { CollectionArchive } from '@/components/CollectionArchive'
|
||||
|
||||
export const ArchiveBlock: React.FC<
|
||||
ArchiveBlockProps & {
|
||||
id?: string
|
||||
}
|
||||
> = async (props) => {
|
||||
const { id, categories, introContent, limit: limitFromProps, populateBy, selectedDocs } = props
|
||||
|
||||
const limit = limitFromProps || 3
|
||||
|
||||
let posts: Post[] = []
|
||||
|
||||
if (populateBy === 'collection') {
|
||||
const payload = await getPayload({ config: configPromise })
|
||||
|
||||
const flattenedCategories = categories?.map((category) => {
|
||||
if (typeof category === 'object') return category.id
|
||||
else return category
|
||||
})
|
||||
|
||||
const fetchedPosts = await payload.find({
|
||||
collection: 'posts',
|
||||
depth: 1,
|
||||
limit,
|
||||
...(flattenedCategories && flattenedCategories.length > 0
|
||||
? {
|
||||
where: {
|
||||
categories: {
|
||||
in: flattenedCategories,
|
||||
},
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
})
|
||||
|
||||
posts = fetchedPosts.docs
|
||||
} else {
|
||||
if (selectedDocs?.length) {
|
||||
const filteredSelectedPosts = selectedDocs.map((post) => {
|
||||
if (typeof post.value === 'object') return post.value
|
||||
}) as Post[]
|
||||
|
||||
posts = filteredSelectedPosts
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="my-16" id={`block-${id}`}>
|
||||
{introContent && (
|
||||
<div className="container mb-16">
|
||||
<RichText className="ms-0 max-w-[48rem]" data={introContent} enableGutter={false} />
|
||||
</div>
|
||||
)}
|
||||
<CollectionArchive posts={posts} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
import type { Block } from 'payload'
|
||||
|
||||
import {
|
||||
FixedToolbarFeature,
|
||||
HeadingFeature,
|
||||
InlineToolbarFeature,
|
||||
lexicalEditor,
|
||||
} from '@payloadcms/richtext-lexical'
|
||||
|
||||
export const Archive: Block = {
|
||||
slug: 'archive',
|
||||
interfaceName: 'ArchiveBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'introContent',
|
||||
type: 'richText',
|
||||
editor: lexicalEditor({
|
||||
features: ({ rootFeatures }) => {
|
||||
return [
|
||||
...rootFeatures,
|
||||
HeadingFeature({ enabledHeadingSizes: ['h1', 'h2', 'h3', 'h4'] }),
|
||||
FixedToolbarFeature(),
|
||||
InlineToolbarFeature(),
|
||||
]
|
||||
},
|
||||
}),
|
||||
label: 'Intro Content',
|
||||
},
|
||||
{
|
||||
name: 'populateBy',
|
||||
type: 'select',
|
||||
defaultValue: 'collection',
|
||||
options: [
|
||||
{
|
||||
label: 'Collection',
|
||||
value: 'collection',
|
||||
},
|
||||
{
|
||||
label: 'Individual Selection',
|
||||
value: 'selection',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'relationTo',
|
||||
type: 'select',
|
||||
admin: {
|
||||
condition: (_, siblingData) => siblingData.populateBy === 'collection',
|
||||
},
|
||||
defaultValue: 'posts',
|
||||
label: 'Collections To Show',
|
||||
options: [
|
||||
{
|
||||
label: 'Posts',
|
||||
value: 'posts',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'categories',
|
||||
type: 'relationship',
|
||||
admin: {
|
||||
condition: (_, siblingData) => siblingData.populateBy === 'collection',
|
||||
},
|
||||
hasMany: true,
|
||||
label: 'Categories To Show',
|
||||
relationTo: 'categories',
|
||||
},
|
||||
{
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
admin: {
|
||||
condition: (_, siblingData) => siblingData.populateBy === 'collection',
|
||||
step: 1,
|
||||
},
|
||||
defaultValue: 10,
|
||||
label: 'Limit',
|
||||
},
|
||||
{
|
||||
name: 'selectedDocs',
|
||||
type: 'relationship',
|
||||
admin: {
|
||||
condition: (_, siblingData) => siblingData.populateBy === 'selection',
|
||||
},
|
||||
hasMany: true,
|
||||
label: 'Selection',
|
||||
relationTo: ['posts'],
|
||||
},
|
||||
],
|
||||
labels: {
|
||||
plural: 'Archives',
|
||||
singular: 'Archive',
|
||||
},
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import type { CheckboxField } from '@payloadcms/plugin-form-builder/types'
|
||||
import type { FieldErrorsImpl, FieldValues, UseFormRegister } from 'react-hook-form'
|
||||
|
||||
import { useFormContext } from 'react-hook-form'
|
||||
|
||||
import { Checkbox as CheckboxUi } from '@/components/ui/checkbox'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import React from 'react'
|
||||
|
||||
import { Error } from '../Error'
|
||||
import { Width } from '../Width'
|
||||
|
||||
export const Checkbox: React.FC<
|
||||
CheckboxField & {
|
||||
errors: Partial<FieldErrorsImpl>
|
||||
register: UseFormRegister<FieldValues>
|
||||
}
|
||||
> = ({ name, defaultValue, errors, label, register, required, width }) => {
|
||||
const props = register(name, { required: required })
|
||||
const { setValue } = useFormContext()
|
||||
|
||||
return (
|
||||
<Width width={width}>
|
||||
<div className="flex items-center gap-2">
|
||||
<CheckboxUi
|
||||
defaultChecked={defaultValue}
|
||||
id={name}
|
||||
{...props}
|
||||
onCheckedChange={(checked) => {
|
||||
setValue(props.name, checked)
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor={name}>
|
||||
{required && (
|
||||
<span className="required">
|
||||
* <span className="sr-only">(required)</span>
|
||||
</span>
|
||||
)}
|
||||
{label}
|
||||
</Label>
|
||||
</div>
|
||||
{errors[name] && <Error name={name} />}
|
||||
</Width>
|
||||
)
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
'use client'
|
||||
import type { FormFieldBlock, Form as FormType } from '@payloadcms/plugin-form-builder/types'
|
||||
|
||||
import { useRouter } from 'next/navigation'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { useForm, FormProvider } from 'react-hook-form'
|
||||
import RichText from '@/components/RichText'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import type { DefaultTypedEditorState } from '@payloadcms/richtext-lexical'
|
||||
|
||||
import { fields } from './fields'
|
||||
import { getClientSideURL } from '@/utilities/getURL'
|
||||
|
||||
export type FormBlockType = {
|
||||
blockName?: string
|
||||
blockType?: 'formBlock'
|
||||
enableIntro: boolean
|
||||
form: FormType
|
||||
introContent?: DefaultTypedEditorState
|
||||
}
|
||||
|
||||
export const FormBlock: React.FC<
|
||||
{
|
||||
id?: string
|
||||
} & FormBlockType
|
||||
> = (props) => {
|
||||
const {
|
||||
enableIntro,
|
||||
form: formFromProps,
|
||||
form: { id: formID, confirmationMessage, confirmationType, redirect, submitButtonLabel } = {},
|
||||
introContent,
|
||||
} = props
|
||||
|
||||
const formMethods = useForm({
|
||||
defaultValues: formFromProps.fields,
|
||||
})
|
||||
const {
|
||||
control,
|
||||
formState: { errors },
|
||||
handleSubmit,
|
||||
register,
|
||||
} = formMethods
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [hasSubmitted, setHasSubmitted] = useState<boolean>()
|
||||
const [error, setError] = useState<{ message: string; status?: string } | undefined>()
|
||||
const router = useRouter()
|
||||
|
||||
const onSubmit = useCallback(
|
||||
(data: FormFieldBlock[]) => {
|
||||
let loadingTimerID: ReturnType<typeof setTimeout>
|
||||
const submitForm = async () => {
|
||||
setError(undefined)
|
||||
|
||||
const dataToSend = Object.entries(data).map(([name, value]) => ({
|
||||
field: name,
|
||||
value,
|
||||
}))
|
||||
|
||||
// delay loading indicator by 1s
|
||||
loadingTimerID = setTimeout(() => {
|
||||
setIsLoading(true)
|
||||
}, 1000)
|
||||
|
||||
try {
|
||||
const req = await fetch(`${getClientSideURL()}/api/form-submissions`, {
|
||||
body: JSON.stringify({
|
||||
form: formID,
|
||||
submissionData: dataToSend,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'POST',
|
||||
})
|
||||
|
||||
const res = await req.json()
|
||||
|
||||
clearTimeout(loadingTimerID)
|
||||
|
||||
if (req.status >= 400) {
|
||||
setIsLoading(false)
|
||||
|
||||
setError({
|
||||
message: res.errors?.[0]?.message || 'Internal Server Error',
|
||||
status: res.status,
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
setIsLoading(false)
|
||||
setHasSubmitted(true)
|
||||
|
||||
if (confirmationType === 'redirect' && redirect) {
|
||||
const { url } = redirect
|
||||
|
||||
const redirectUrl = url
|
||||
|
||||
if (redirectUrl) router.push(redirectUrl)
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(err)
|
||||
setIsLoading(false)
|
||||
setError({
|
||||
message: 'Something went wrong.',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
void submitForm()
|
||||
},
|
||||
[router, formID, redirect, confirmationType],
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="container lg:max-w-[48rem]">
|
||||
{enableIntro && introContent && !hasSubmitted && (
|
||||
<RichText className="mb-8 lg:mb-12" data={introContent} enableGutter={false} />
|
||||
)}
|
||||
<div className="p-4 lg:p-6 border border-border rounded-[0.8rem]">
|
||||
<FormProvider {...formMethods}>
|
||||
{!isLoading && hasSubmitted && confirmationType === 'message' && (
|
||||
<RichText data={confirmationMessage} />
|
||||
)}
|
||||
{isLoading && !hasSubmitted && <p>Loading, please wait...</p>}
|
||||
{error && <div>{`${error.status || '500'}: ${error.message || ''}`}</div>}
|
||||
{!hasSubmitted && (
|
||||
<form id={formID} onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="mb-4 last:mb-0">
|
||||
{formFromProps &&
|
||||
formFromProps.fields &&
|
||||
formFromProps.fields?.map((field, index) => {
|
||||
const Field = fields?.[
|
||||
field.blockType as keyof typeof fields
|
||||
] as React.ComponentType<Record<string, unknown>> | undefined
|
||||
if (Field) {
|
||||
return (
|
||||
<div className="mb-6 last:mb-0" key={index}>
|
||||
<Field
|
||||
form={formFromProps}
|
||||
{...field}
|
||||
{...formMethods}
|
||||
control={control}
|
||||
errors={errors}
|
||||
register={register}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return null
|
||||
})}
|
||||
</div>
|
||||
|
||||
<Button form={formID} type="submit" variant="default">
|
||||
{submitButtonLabel}
|
||||
</Button>
|
||||
</form>
|
||||
)}
|
||||
</FormProvider>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
import type { CountryField } from '@payloadcms/plugin-form-builder/types'
|
||||
import type { Control, FieldErrorsImpl } from 'react-hook-form'
|
||||
|
||||
import { Label } from '@/components/ui/label'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import React from 'react'
|
||||
import { Controller } from 'react-hook-form'
|
||||
|
||||
import { Error } from '../Error'
|
||||
import { Width } from '../Width'
|
||||
import { countryOptions } from './options'
|
||||
|
||||
export const Country: React.FC<
|
||||
CountryField & {
|
||||
control: Control
|
||||
errors: Partial<FieldErrorsImpl>
|
||||
}
|
||||
> = ({ name, control, errors, label, required, width }) => {
|
||||
return (
|
||||
<Width width={width}>
|
||||
<Label className="" htmlFor={name}>
|
||||
{label}
|
||||
|
||||
{required && (
|
||||
<span className="required">
|
||||
* <span className="sr-only">(required)</span>
|
||||
</span>
|
||||
)}
|
||||
</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name={name}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
const controlledValue = countryOptions.find((t) => t.value === value)
|
||||
|
||||
return (
|
||||
<Select onValueChange={(val) => onChange(val)} value={controlledValue?.value}>
|
||||
<SelectTrigger className="w-full" id={name}>
|
||||
<SelectValue placeholder={label} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{countryOptions.map(({ label, value }) => {
|
||||
return (
|
||||
<SelectItem key={value} value={value}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
)
|
||||
})}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)
|
||||
}}
|
||||
rules={{ required }}
|
||||
/>
|
||||
{errors[name] && <Error name={name} />}
|
||||
</Width>
|
||||
)
|
||||
}
|
||||
@@ -1,982 +0,0 @@
|
||||
export const countryOptions = [
|
||||
{
|
||||
label: 'Afghanistan',
|
||||
value: 'AF',
|
||||
},
|
||||
{
|
||||
label: 'Åland Islands',
|
||||
value: 'AX',
|
||||
},
|
||||
{
|
||||
label: 'Albania',
|
||||
value: 'AL',
|
||||
},
|
||||
{
|
||||
label: 'Algeria',
|
||||
value: 'DZ',
|
||||
},
|
||||
{
|
||||
label: 'American Samoa',
|
||||
value: 'AS',
|
||||
},
|
||||
{
|
||||
label: 'Andorra',
|
||||
value: 'AD',
|
||||
},
|
||||
{
|
||||
label: 'Angola',
|
||||
value: 'AO',
|
||||
},
|
||||
{
|
||||
label: 'Anguilla',
|
||||
value: 'AI',
|
||||
},
|
||||
{
|
||||
label: 'Antarctica',
|
||||
value: 'AQ',
|
||||
},
|
||||
{
|
||||
label: 'Antigua and Barbuda',
|
||||
value: 'AG',
|
||||
},
|
||||
{
|
||||
label: 'Argentina',
|
||||
value: 'AR',
|
||||
},
|
||||
{
|
||||
label: 'Armenia',
|
||||
value: 'AM',
|
||||
},
|
||||
{
|
||||
label: 'Aruba',
|
||||
value: 'AW',
|
||||
},
|
||||
{
|
||||
label: 'Australia',
|
||||
value: 'AU',
|
||||
},
|
||||
{
|
||||
label: 'Austria',
|
||||
value: 'AT',
|
||||
},
|
||||
{
|
||||
label: 'Azerbaijan',
|
||||
value: 'AZ',
|
||||
},
|
||||
{
|
||||
label: 'Bahamas',
|
||||
value: 'BS',
|
||||
},
|
||||
{
|
||||
label: 'Bahrain',
|
||||
value: 'BH',
|
||||
},
|
||||
{
|
||||
label: 'Bangladesh',
|
||||
value: 'BD',
|
||||
},
|
||||
{
|
||||
label: 'Barbados',
|
||||
value: 'BB',
|
||||
},
|
||||
{
|
||||
label: 'Belarus',
|
||||
value: 'BY',
|
||||
},
|
||||
{
|
||||
label: 'Belgium',
|
||||
value: 'BE',
|
||||
},
|
||||
{
|
||||
label: 'Belize',
|
||||
value: 'BZ',
|
||||
},
|
||||
{
|
||||
label: 'Benin',
|
||||
value: 'BJ',
|
||||
},
|
||||
{
|
||||
label: 'Bermuda',
|
||||
value: 'BM',
|
||||
},
|
||||
{
|
||||
label: 'Bhutan',
|
||||
value: 'BT',
|
||||
},
|
||||
{
|
||||
label: 'Bolivia',
|
||||
value: 'BO',
|
||||
},
|
||||
{
|
||||
label: 'Bosnia and Herzegovina',
|
||||
value: 'BA',
|
||||
},
|
||||
{
|
||||
label: 'Botswana',
|
||||
value: 'BW',
|
||||
},
|
||||
{
|
||||
label: 'Bouvet Island',
|
||||
value: 'BV',
|
||||
},
|
||||
{
|
||||
label: 'Brazil',
|
||||
value: 'BR',
|
||||
},
|
||||
{
|
||||
label: 'British Indian Ocean Territory',
|
||||
value: 'IO',
|
||||
},
|
||||
{
|
||||
label: 'Brunei Darussalam',
|
||||
value: 'BN',
|
||||
},
|
||||
{
|
||||
label: 'Bulgaria',
|
||||
value: 'BG',
|
||||
},
|
||||
{
|
||||
label: 'Burkina Faso',
|
||||
value: 'BF',
|
||||
},
|
||||
{
|
||||
label: 'Burundi',
|
||||
value: 'BI',
|
||||
},
|
||||
{
|
||||
label: 'Cambodia',
|
||||
value: 'KH',
|
||||
},
|
||||
{
|
||||
label: 'Cameroon',
|
||||
value: 'CM',
|
||||
},
|
||||
{
|
||||
label: 'Canada',
|
||||
value: 'CA',
|
||||
},
|
||||
{
|
||||
label: 'Cape Verde',
|
||||
value: 'CV',
|
||||
},
|
||||
{
|
||||
label: 'Cayman Islands',
|
||||
value: 'KY',
|
||||
},
|
||||
{
|
||||
label: 'Central African Republic',
|
||||
value: 'CF',
|
||||
},
|
||||
{
|
||||
label: 'Chad',
|
||||
value: 'TD',
|
||||
},
|
||||
{
|
||||
label: 'Chile',
|
||||
value: 'CL',
|
||||
},
|
||||
{
|
||||
label: 'China',
|
||||
value: 'CN',
|
||||
},
|
||||
{
|
||||
label: 'Christmas Island',
|
||||
value: 'CX',
|
||||
},
|
||||
{
|
||||
label: 'Cocos (Keeling) Islands',
|
||||
value: 'CC',
|
||||
},
|
||||
{
|
||||
label: 'Colombia',
|
||||
value: 'CO',
|
||||
},
|
||||
{
|
||||
label: 'Comoros',
|
||||
value: 'KM',
|
||||
},
|
||||
{
|
||||
label: 'Congo',
|
||||
value: 'CG',
|
||||
},
|
||||
{
|
||||
label: 'Congo, The Democratic Republic of the',
|
||||
value: 'CD',
|
||||
},
|
||||
{
|
||||
label: 'Cook Islands',
|
||||
value: 'CK',
|
||||
},
|
||||
{
|
||||
label: 'Costa Rica',
|
||||
value: 'CR',
|
||||
},
|
||||
{
|
||||
label: "Cote D'Ivoire",
|
||||
value: 'CI',
|
||||
},
|
||||
{
|
||||
label: 'Croatia',
|
||||
value: 'HR',
|
||||
},
|
||||
{
|
||||
label: 'Cuba',
|
||||
value: 'CU',
|
||||
},
|
||||
{
|
||||
label: 'Cyprus',
|
||||
value: 'CY',
|
||||
},
|
||||
{
|
||||
label: 'Czech Republic',
|
||||
value: 'CZ',
|
||||
},
|
||||
{
|
||||
label: 'Denmark',
|
||||
value: 'DK',
|
||||
},
|
||||
{
|
||||
label: 'Djibouti',
|
||||
value: 'DJ',
|
||||
},
|
||||
{
|
||||
label: 'Dominica',
|
||||
value: 'DM',
|
||||
},
|
||||
{
|
||||
label: 'Dominican Republic',
|
||||
value: 'DO',
|
||||
},
|
||||
{
|
||||
label: 'Ecuador',
|
||||
value: 'EC',
|
||||
},
|
||||
{
|
||||
label: 'Egypt',
|
||||
value: 'EG',
|
||||
},
|
||||
{
|
||||
label: 'El Salvador',
|
||||
value: 'SV',
|
||||
},
|
||||
{
|
||||
label: 'Equatorial Guinea',
|
||||
value: 'GQ',
|
||||
},
|
||||
{
|
||||
label: 'Eritrea',
|
||||
value: 'ER',
|
||||
},
|
||||
{
|
||||
label: 'Estonia',
|
||||
value: 'EE',
|
||||
},
|
||||
{
|
||||
label: 'Ethiopia',
|
||||
value: 'ET',
|
||||
},
|
||||
{
|
||||
label: 'Falkland Islands (Malvinas)',
|
||||
value: 'FK',
|
||||
},
|
||||
{
|
||||
label: 'Faroe Islands',
|
||||
value: 'FO',
|
||||
},
|
||||
{
|
||||
label: 'Fiji',
|
||||
value: 'FJ',
|
||||
},
|
||||
{
|
||||
label: 'Finland',
|
||||
value: 'FI',
|
||||
},
|
||||
{
|
||||
label: 'France',
|
||||
value: 'FR',
|
||||
},
|
||||
{
|
||||
label: 'French Guiana',
|
||||
value: 'GF',
|
||||
},
|
||||
{
|
||||
label: 'French Polynesia',
|
||||
value: 'PF',
|
||||
},
|
||||
{
|
||||
label: 'French Southern Territories',
|
||||
value: 'TF',
|
||||
},
|
||||
{
|
||||
label: 'Gabon',
|
||||
value: 'GA',
|
||||
},
|
||||
{
|
||||
label: 'Gambia',
|
||||
value: 'GM',
|
||||
},
|
||||
{
|
||||
label: 'Georgia',
|
||||
value: 'GE',
|
||||
},
|
||||
{
|
||||
label: 'Germany',
|
||||
value: 'DE',
|
||||
},
|
||||
{
|
||||
label: 'Ghana',
|
||||
value: 'GH',
|
||||
},
|
||||
{
|
||||
label: 'Gibraltar',
|
||||
value: 'GI',
|
||||
},
|
||||
{
|
||||
label: 'Greece',
|
||||
value: 'GR',
|
||||
},
|
||||
{
|
||||
label: 'Greenland',
|
||||
value: 'GL',
|
||||
},
|
||||
{
|
||||
label: 'Grenada',
|
||||
value: 'GD',
|
||||
},
|
||||
{
|
||||
label: 'Guadeloupe',
|
||||
value: 'GP',
|
||||
},
|
||||
{
|
||||
label: 'Guam',
|
||||
value: 'GU',
|
||||
},
|
||||
{
|
||||
label: 'Guatemala',
|
||||
value: 'GT',
|
||||
},
|
||||
{
|
||||
label: 'Guernsey',
|
||||
value: 'GG',
|
||||
},
|
||||
{
|
||||
label: 'Guinea',
|
||||
value: 'GN',
|
||||
},
|
||||
{
|
||||
label: 'Guinea-Bissau',
|
||||
value: 'GW',
|
||||
},
|
||||
{
|
||||
label: 'Guyana',
|
||||
value: 'GY',
|
||||
},
|
||||
{
|
||||
label: 'Haiti',
|
||||
value: 'HT',
|
||||
},
|
||||
{
|
||||
label: 'Heard Island and Mcdonald Islands',
|
||||
value: 'HM',
|
||||
},
|
||||
{
|
||||
label: 'Holy See (Vatican City State)',
|
||||
value: 'VA',
|
||||
},
|
||||
{
|
||||
label: 'Honduras',
|
||||
value: 'HN',
|
||||
},
|
||||
{
|
||||
label: 'Hong Kong',
|
||||
value: 'HK',
|
||||
},
|
||||
{
|
||||
label: 'Hungary',
|
||||
value: 'HU',
|
||||
},
|
||||
{
|
||||
label: 'Iceland',
|
||||
value: 'IS',
|
||||
},
|
||||
{
|
||||
label: 'India',
|
||||
value: 'IN',
|
||||
},
|
||||
{
|
||||
label: 'Indonesia',
|
||||
value: 'ID',
|
||||
},
|
||||
{
|
||||
label: 'Iran, Islamic Republic Of',
|
||||
value: 'IR',
|
||||
},
|
||||
{
|
||||
label: 'Iraq',
|
||||
value: 'IQ',
|
||||
},
|
||||
{
|
||||
label: 'Ireland',
|
||||
value: 'IE',
|
||||
},
|
||||
{
|
||||
label: 'Isle of Man',
|
||||
value: 'IM',
|
||||
},
|
||||
{
|
||||
label: 'Israel',
|
||||
value: 'IL',
|
||||
},
|
||||
{
|
||||
label: 'Italy',
|
||||
value: 'IT',
|
||||
},
|
||||
{
|
||||
label: 'Jamaica',
|
||||
value: 'JM',
|
||||
},
|
||||
{
|
||||
label: 'Japan',
|
||||
value: 'JP',
|
||||
},
|
||||
{
|
||||
label: 'Jersey',
|
||||
value: 'JE',
|
||||
},
|
||||
{
|
||||
label: 'Jordan',
|
||||
value: 'JO',
|
||||
},
|
||||
{
|
||||
label: 'Kazakhstan',
|
||||
value: 'KZ',
|
||||
},
|
||||
{
|
||||
label: 'Kenya',
|
||||
value: 'KE',
|
||||
},
|
||||
{
|
||||
label: 'Kiribati',
|
||||
value: 'KI',
|
||||
},
|
||||
{
|
||||
label: "Democratic People's Republic of Korea",
|
||||
value: 'KP',
|
||||
},
|
||||
{
|
||||
label: 'Korea, Republic of',
|
||||
value: 'KR',
|
||||
},
|
||||
{
|
||||
label: 'Kosovo',
|
||||
value: 'XK',
|
||||
},
|
||||
{
|
||||
label: 'Kuwait',
|
||||
value: 'KW',
|
||||
},
|
||||
{
|
||||
label: 'Kyrgyzstan',
|
||||
value: 'KG',
|
||||
},
|
||||
{
|
||||
label: "Lao People's Democratic Republic",
|
||||
value: 'LA',
|
||||
},
|
||||
{
|
||||
label: 'Latvia',
|
||||
value: 'LV',
|
||||
},
|
||||
{
|
||||
label: 'Lebanon',
|
||||
value: 'LB',
|
||||
},
|
||||
{
|
||||
label: 'Lesotho',
|
||||
value: 'LS',
|
||||
},
|
||||
{
|
||||
label: 'Liberia',
|
||||
value: 'LR',
|
||||
},
|
||||
{
|
||||
label: 'Libyan Arab Jamahiriya',
|
||||
value: 'LY',
|
||||
},
|
||||
{
|
||||
label: 'Liechtenstein',
|
||||
value: 'LI',
|
||||
},
|
||||
{
|
||||
label: 'Lithuania',
|
||||
value: 'LT',
|
||||
},
|
||||
{
|
||||
label: 'Luxembourg',
|
||||
value: 'LU',
|
||||
},
|
||||
{
|
||||
label: 'Macao',
|
||||
value: 'MO',
|
||||
},
|
||||
{
|
||||
label: 'Macedonia, The Former Yugoslav Republic of',
|
||||
value: 'MK',
|
||||
},
|
||||
{
|
||||
label: 'Madagascar',
|
||||
value: 'MG',
|
||||
},
|
||||
{
|
||||
label: 'Malawi',
|
||||
value: 'MW',
|
||||
},
|
||||
{
|
||||
label: 'Malaysia',
|
||||
value: 'MY',
|
||||
},
|
||||
{
|
||||
label: 'Maldives',
|
||||
value: 'MV',
|
||||
},
|
||||
{
|
||||
label: 'Mali',
|
||||
value: 'ML',
|
||||
},
|
||||
{
|
||||
label: 'Malta',
|
||||
value: 'MT',
|
||||
},
|
||||
{
|
||||
label: 'Marshall Islands',
|
||||
value: 'MH',
|
||||
},
|
||||
{
|
||||
label: 'Martinique',
|
||||
value: 'MQ',
|
||||
},
|
||||
{
|
||||
label: 'Mauritania',
|
||||
value: 'MR',
|
||||
},
|
||||
{
|
||||
label: 'Mauritius',
|
||||
value: 'MU',
|
||||
},
|
||||
{
|
||||
label: 'Mayotte',
|
||||
value: 'YT',
|
||||
},
|
||||
{
|
||||
label: 'Mexico',
|
||||
value: 'MX',
|
||||
},
|
||||
{
|
||||
label: 'Micronesia, Federated States of',
|
||||
value: 'FM',
|
||||
},
|
||||
{
|
||||
label: 'Moldova, Republic of',
|
||||
value: 'MD',
|
||||
},
|
||||
{
|
||||
label: 'Monaco',
|
||||
value: 'MC',
|
||||
},
|
||||
{
|
||||
label: 'Mongolia',
|
||||
value: 'MN',
|
||||
},
|
||||
{
|
||||
label: 'Montenegro',
|
||||
value: 'ME',
|
||||
},
|
||||
{
|
||||
label: 'Montserrat',
|
||||
value: 'MS',
|
||||
},
|
||||
{
|
||||
label: 'Morocco',
|
||||
value: 'MA',
|
||||
},
|
||||
{
|
||||
label: 'Mozambique',
|
||||
value: 'MZ',
|
||||
},
|
||||
{
|
||||
label: 'Myanmar',
|
||||
value: 'MM',
|
||||
},
|
||||
{
|
||||
label: 'Namibia',
|
||||
value: 'NA',
|
||||
},
|
||||
{
|
||||
label: 'Nauru',
|
||||
value: 'NR',
|
||||
},
|
||||
{
|
||||
label: 'Nepal',
|
||||
value: 'NP',
|
||||
},
|
||||
{
|
||||
label: 'Netherlands',
|
||||
value: 'NL',
|
||||
},
|
||||
{
|
||||
label: 'Netherlands Antilles',
|
||||
value: 'AN',
|
||||
},
|
||||
{
|
||||
label: 'New Caledonia',
|
||||
value: 'NC',
|
||||
},
|
||||
{
|
||||
label: 'New Zealand',
|
||||
value: 'NZ',
|
||||
},
|
||||
{
|
||||
label: 'Nicaragua',
|
||||
value: 'NI',
|
||||
},
|
||||
{
|
||||
label: 'Niger',
|
||||
value: 'NE',
|
||||
},
|
||||
{
|
||||
label: 'Nigeria',
|
||||
value: 'NG',
|
||||
},
|
||||
{
|
||||
label: 'Niue',
|
||||
value: 'NU',
|
||||
},
|
||||
{
|
||||
label: 'Norfolk Island',
|
||||
value: 'NF',
|
||||
},
|
||||
{
|
||||
label: 'Northern Mariana Islands',
|
||||
value: 'MP',
|
||||
},
|
||||
{
|
||||
label: 'Norway',
|
||||
value: 'NO',
|
||||
},
|
||||
{
|
||||
label: 'Oman',
|
||||
value: 'OM',
|
||||
},
|
||||
{
|
||||
label: 'Pakistan',
|
||||
value: 'PK',
|
||||
},
|
||||
{
|
||||
label: 'Palau',
|
||||
value: 'PW',
|
||||
},
|
||||
{
|
||||
label: 'Palestinian Territory, Occupied',
|
||||
value: 'PS',
|
||||
},
|
||||
{
|
||||
label: 'Panama',
|
||||
value: 'PA',
|
||||
},
|
||||
{
|
||||
label: 'Papua New Guinea',
|
||||
value: 'PG',
|
||||
},
|
||||
{
|
||||
label: 'Paraguay',
|
||||
value: 'PY',
|
||||
},
|
||||
{
|
||||
label: 'Peru',
|
||||
value: 'PE',
|
||||
},
|
||||
{
|
||||
label: 'Philippines',
|
||||
value: 'PH',
|
||||
},
|
||||
{
|
||||
label: 'Pitcairn',
|
||||
value: 'PN',
|
||||
},
|
||||
{
|
||||
label: 'Poland',
|
||||
value: 'PL',
|
||||
},
|
||||
{
|
||||
label: 'Portugal',
|
||||
value: 'PT',
|
||||
},
|
||||
{
|
||||
label: 'Puerto Rico',
|
||||
value: 'PR',
|
||||
},
|
||||
{
|
||||
label: 'Qatar',
|
||||
value: 'QA',
|
||||
},
|
||||
{
|
||||
label: 'Reunion',
|
||||
value: 'RE',
|
||||
},
|
||||
{
|
||||
label: 'Romania',
|
||||
value: 'RO',
|
||||
},
|
||||
{
|
||||
label: 'Russian Federation',
|
||||
value: 'RU',
|
||||
},
|
||||
{
|
||||
label: 'Rwanda',
|
||||
value: 'RW',
|
||||
},
|
||||
{
|
||||
label: 'Saint Helena',
|
||||
value: 'SH',
|
||||
},
|
||||
{
|
||||
label: 'Saint Kitts and Nevis',
|
||||
value: 'KN',
|
||||
},
|
||||
{
|
||||
label: 'Saint Lucia',
|
||||
value: 'LC',
|
||||
},
|
||||
{
|
||||
label: 'Saint Pierre and Miquelon',
|
||||
value: 'PM',
|
||||
},
|
||||
{
|
||||
label: 'Saint Vincent and the Grenadines',
|
||||
value: 'VC',
|
||||
},
|
||||
{
|
||||
label: 'Samoa',
|
||||
value: 'WS',
|
||||
},
|
||||
{
|
||||
label: 'San Marino',
|
||||
value: 'SM',
|
||||
},
|
||||
{
|
||||
label: 'Sao Tome and Principe',
|
||||
value: 'ST',
|
||||
},
|
||||
{
|
||||
label: 'Saudi Arabia',
|
||||
value: 'SA',
|
||||
},
|
||||
{
|
||||
label: 'Senegal',
|
||||
value: 'SN',
|
||||
},
|
||||
{
|
||||
label: 'Serbia',
|
||||
value: 'RS',
|
||||
},
|
||||
{
|
||||
label: 'Seychelles',
|
||||
value: 'SC',
|
||||
},
|
||||
{
|
||||
label: 'Sierra Leone',
|
||||
value: 'SL',
|
||||
},
|
||||
{
|
||||
label: 'Singapore',
|
||||
value: 'SG',
|
||||
},
|
||||
{
|
||||
label: 'Slovakia',
|
||||
value: 'SK',
|
||||
},
|
||||
{
|
||||
label: 'Slovenia',
|
||||
value: 'SI',
|
||||
},
|
||||
{
|
||||
label: 'Solomon Islands',
|
||||
value: 'SB',
|
||||
},
|
||||
{
|
||||
label: 'Somalia',
|
||||
value: 'SO',
|
||||
},
|
||||
{
|
||||
label: 'South Africa',
|
||||
value: 'ZA',
|
||||
},
|
||||
{
|
||||
label: 'South Georgia and the South Sandwich Islands',
|
||||
value: 'GS',
|
||||
},
|
||||
{
|
||||
label: 'Spain',
|
||||
value: 'ES',
|
||||
},
|
||||
{
|
||||
label: 'Sri Lanka',
|
||||
value: 'LK',
|
||||
},
|
||||
{
|
||||
label: 'Sudan',
|
||||
value: 'SD',
|
||||
},
|
||||
{
|
||||
label: 'Suriname',
|
||||
value: 'SR',
|
||||
},
|
||||
{
|
||||
label: 'Svalbard and Jan Mayen',
|
||||
value: 'SJ',
|
||||
},
|
||||
{
|
||||
label: 'Swaziland',
|
||||
value: 'SZ',
|
||||
},
|
||||
{
|
||||
label: 'Sweden',
|
||||
value: 'SE',
|
||||
},
|
||||
{
|
||||
label: 'Switzerland',
|
||||
value: 'CH',
|
||||
},
|
||||
{
|
||||
label: 'Syrian Arab Republic',
|
||||
value: 'SY',
|
||||
},
|
||||
{
|
||||
label: 'Taiwan',
|
||||
value: 'TW',
|
||||
},
|
||||
{
|
||||
label: 'Tajikistan',
|
||||
value: 'TJ',
|
||||
},
|
||||
{
|
||||
label: 'Tanzania, United Republic of',
|
||||
value: 'TZ',
|
||||
},
|
||||
{
|
||||
label: 'Thailand',
|
||||
value: 'TH',
|
||||
},
|
||||
{
|
||||
label: 'Timor-Leste',
|
||||
value: 'TL',
|
||||
},
|
||||
{
|
||||
label: 'Togo',
|
||||
value: 'TG',
|
||||
},
|
||||
{
|
||||
label: 'Tokelau',
|
||||
value: 'TK',
|
||||
},
|
||||
{
|
||||
label: 'Tonga',
|
||||
value: 'TO',
|
||||
},
|
||||
{
|
||||
label: 'Trinidad and Tobago',
|
||||
value: 'TT',
|
||||
},
|
||||
{
|
||||
label: 'Tunisia',
|
||||
value: 'TN',
|
||||
},
|
||||
{
|
||||
label: 'Turkey',
|
||||
value: 'TR',
|
||||
},
|
||||
{
|
||||
label: 'Turkmenistan',
|
||||
value: 'TM',
|
||||
},
|
||||
{
|
||||
label: 'Turks and Caicos Islands',
|
||||
value: 'TC',
|
||||
},
|
||||
{
|
||||
label: 'Tuvalu',
|
||||
value: 'TV',
|
||||
},
|
||||
{
|
||||
label: 'Uganda',
|
||||
value: 'UG',
|
||||
},
|
||||
{
|
||||
label: 'Ukraine',
|
||||
value: 'UA',
|
||||
},
|
||||
{
|
||||
label: 'United Arab Emirates',
|
||||
value: 'AE',
|
||||
},
|
||||
{
|
||||
label: 'United Kingdom',
|
||||
value: 'GB',
|
||||
},
|
||||
{
|
||||
label: 'United States',
|
||||
value: 'US',
|
||||
},
|
||||
{
|
||||
label: 'United States Minor Outlying Islands',
|
||||
value: 'UM',
|
||||
},
|
||||
{
|
||||
label: 'Uruguay',
|
||||
value: 'UY',
|
||||
},
|
||||
{
|
||||
label: 'Uzbekistan',
|
||||
value: 'UZ',
|
||||
},
|
||||
{
|
||||
label: 'Vanuatu',
|
||||
value: 'VU',
|
||||
},
|
||||
{
|
||||
label: 'Venezuela',
|
||||
value: 'VE',
|
||||
},
|
||||
{
|
||||
label: 'Viet Nam',
|
||||
value: 'VN',
|
||||
},
|
||||
{
|
||||
label: 'Virgin Islands, British',
|
||||
value: 'VG',
|
||||
},
|
||||
{
|
||||
label: 'Virgin Islands, U.S.',
|
||||
value: 'VI',
|
||||
},
|
||||
{
|
||||
label: 'Wallis and Futuna',
|
||||
value: 'WF',
|
||||
},
|
||||
{
|
||||
label: 'Western Sahara',
|
||||
value: 'EH',
|
||||
},
|
||||
{
|
||||
label: 'Yemen',
|
||||
value: 'YE',
|
||||
},
|
||||
{
|
||||
label: 'Zambia',
|
||||
value: 'ZM',
|
||||
},
|
||||
{
|
||||
label: 'Zimbabwe',
|
||||
value: 'ZW',
|
||||
},
|
||||
]
|
||||
@@ -1,38 +0,0 @@
|
||||
import type { EmailField } from '@payloadcms/plugin-form-builder/types'
|
||||
import type { FieldErrorsImpl, FieldValues, UseFormRegister } from 'react-hook-form'
|
||||
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import React from 'react'
|
||||
|
||||
import { Error } from '../Error'
|
||||
import { Width } from '../Width'
|
||||
|
||||
export const Email: React.FC<
|
||||
EmailField & {
|
||||
errors: Partial<FieldErrorsImpl>
|
||||
register: UseFormRegister<FieldValues>
|
||||
}
|
||||
> = ({ name, defaultValue, errors, label, register, required, width }) => {
|
||||
return (
|
||||
<Width width={width}>
|
||||
<Label htmlFor={name}>
|
||||
{label}
|
||||
|
||||
{required && (
|
||||
<span className="required">
|
||||
* <span className="sr-only">(required)</span>
|
||||
</span>
|
||||
)}
|
||||
</Label>
|
||||
<Input
|
||||
defaultValue={defaultValue}
|
||||
id={name}
|
||||
type="text"
|
||||
{...register(name, { pattern: /^\S[^\s@]*@\S+$/, required })}
|
||||
/>
|
||||
|
||||
{errors[name] && <Error name={name} />}
|
||||
</Width>
|
||||
)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import { useFormContext } from 'react-hook-form'
|
||||
|
||||
export const Error = ({ name }: { name: string }) => {
|
||||
const {
|
||||
formState: { errors },
|
||||
} = useFormContext()
|
||||
return (
|
||||
<div className="mt-2 text-red-500 text-sm">
|
||||
{(errors[name]?.message as string) || 'This field is required'}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import RichText from '@/components/RichText'
|
||||
import React from 'react'
|
||||
|
||||
import { Width } from '../Width'
|
||||
import { DefaultTypedEditorState } from '@payloadcms/richtext-lexical'
|
||||
|
||||
export const Message: React.FC<{ message: DefaultTypedEditorState }> = ({ message }) => {
|
||||
return (
|
||||
<Width className="my-12" width="100">
|
||||
{message && <RichText data={message} />}
|
||||
</Width>
|
||||
)
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import type { TextField } from '@payloadcms/plugin-form-builder/types'
|
||||
import type { FieldErrorsImpl, FieldValues, UseFormRegister } from 'react-hook-form'
|
||||
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import React from 'react'
|
||||
|
||||
import { Error } from '../Error'
|
||||
import { Width } from '../Width'
|
||||
export const Number: React.FC<
|
||||
TextField & {
|
||||
errors: Partial<FieldErrorsImpl>
|
||||
register: UseFormRegister<FieldValues>
|
||||
}
|
||||
> = ({ name, defaultValue, errors, label, register, required, width }) => {
|
||||
return (
|
||||
<Width width={width}>
|
||||
<Label htmlFor={name}>
|
||||
{label}
|
||||
|
||||
{required && (
|
||||
<span className="required">
|
||||
* <span className="sr-only">(required)</span>
|
||||
</span>
|
||||
)}
|
||||
</Label>
|
||||
<Input
|
||||
defaultValue={defaultValue}
|
||||
id={name}
|
||||
type="number"
|
||||
{...register(name, { required })}
|
||||
/>
|
||||
{errors[name] && <Error name={name} />}
|
||||
</Width>
|
||||
)
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
import type { SelectField } from '@payloadcms/plugin-form-builder/types'
|
||||
import type { Control, FieldErrorsImpl } from 'react-hook-form'
|
||||
|
||||
import { Label } from '@/components/ui/label'
|
||||
import {
|
||||
Select as SelectComponent,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import React from 'react'
|
||||
import { Controller } from 'react-hook-form'
|
||||
|
||||
import { Error } from '../Error'
|
||||
import { Width } from '../Width'
|
||||
|
||||
export const Select: React.FC<
|
||||
SelectField & {
|
||||
control: Control
|
||||
errors: Partial<FieldErrorsImpl>
|
||||
}
|
||||
> = ({ name, control, errors, label, options, required, width, defaultValue }) => {
|
||||
return (
|
||||
<Width width={width}>
|
||||
<Label htmlFor={name}>
|
||||
{label}
|
||||
{required && (
|
||||
<span className="required">
|
||||
* <span className="sr-only">(required)</span>
|
||||
</span>
|
||||
)}
|
||||
</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue={defaultValue}
|
||||
name={name}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
const controlledValue = options.find((t) => t.value === value)
|
||||
|
||||
return (
|
||||
<SelectComponent onValueChange={(val) => onChange(val)} value={controlledValue?.value}>
|
||||
<SelectTrigger className="w-full" id={name}>
|
||||
<SelectValue placeholder={label} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{options.map(({ label, value }) => {
|
||||
return (
|
||||
<SelectItem key={value} value={value}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
)
|
||||
})}
|
||||
</SelectContent>
|
||||
</SelectComponent>
|
||||
)
|
||||
}}
|
||||
rules={{ required }}
|
||||
/>
|
||||
{errors[name] && <Error name={name} />}
|
||||
</Width>
|
||||
)
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import type { StateField } from '@payloadcms/plugin-form-builder/types'
|
||||
import type { Control, FieldErrorsImpl } from 'react-hook-form'
|
||||
|
||||
import { Label } from '@/components/ui/label'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import React from 'react'
|
||||
import { Controller } from 'react-hook-form'
|
||||
|
||||
import { Error } from '../Error'
|
||||
import { Width } from '../Width'
|
||||
import { stateOptions } from './options'
|
||||
|
||||
export const State: React.FC<
|
||||
StateField & {
|
||||
control: Control
|
||||
errors: Partial<FieldErrorsImpl>
|
||||
}
|
||||
> = ({ name, control, errors, label, required, width }) => {
|
||||
return (
|
||||
<Width width={width}>
|
||||
<Label htmlFor={name}>
|
||||
{label}
|
||||
{required && (
|
||||
<span className="required">
|
||||
* <span className="sr-only">(required)</span>
|
||||
</span>
|
||||
)}
|
||||
</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name={name}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
const controlledValue = stateOptions.find((t) => t.value === value)
|
||||
|
||||
return (
|
||||
<Select onValueChange={(val) => onChange(val)} value={controlledValue?.value}>
|
||||
<SelectTrigger className="w-full" id={name}>
|
||||
<SelectValue placeholder={label} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{stateOptions.map(({ label, value }) => {
|
||||
return (
|
||||
<SelectItem key={value} value={value}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
)
|
||||
})}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)
|
||||
}}
|
||||
rules={{ required }}
|
||||
/>
|
||||
{errors[name] && <Error name={name} />}
|
||||
</Width>
|
||||
)
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
export const stateOptions = [
|
||||
{ label: 'Alabama', value: 'AL' },
|
||||
{ label: 'Alaska', value: 'AK' },
|
||||
{ label: 'Arizona', value: 'AZ' },
|
||||
{ label: 'Arkansas', value: 'AR' },
|
||||
{ label: 'California', value: 'CA' },
|
||||
{ label: 'Colorado', value: 'CO' },
|
||||
{ label: 'Connecticut', value: 'CT' },
|
||||
{ label: 'Delaware', value: 'DE' },
|
||||
{ label: 'Florida', value: 'FL' },
|
||||
{ label: 'Georgia', value: 'GA' },
|
||||
{ label: 'Hawaii', value: 'HI' },
|
||||
{ label: 'Idaho', value: 'ID' },
|
||||
{ label: 'Illinois', value: 'IL' },
|
||||
{ label: 'Indiana', value: 'IN' },
|
||||
{ label: 'Iowa', value: 'IA' },
|
||||
{ label: 'Kansas', value: 'KS' },
|
||||
{ label: 'Kentucky', value: 'KY' },
|
||||
{ label: 'Louisiana', value: 'LA' },
|
||||
{ label: 'Maine', value: 'ME' },
|
||||
{ label: 'Maryland', value: 'MD' },
|
||||
{ label: 'Massachusetts', value: 'MA' },
|
||||
{ label: 'Michigan', value: 'MI' },
|
||||
{ label: 'Minnesota', value: 'MN' },
|
||||
{ label: 'Mississippi', value: 'MS' },
|
||||
{ label: 'Missouri', value: 'MO' },
|
||||
{ label: 'Montana', value: 'MT' },
|
||||
{ label: 'Nebraska', value: 'NE' },
|
||||
{ label: 'Nevada', value: 'NV' },
|
||||
{ label: 'New Hampshire', value: 'NH' },
|
||||
{ label: 'New Jersey', value: 'NJ' },
|
||||
{ label: 'New Mexico', value: 'NM' },
|
||||
{ label: 'New York', value: 'NY' },
|
||||
{ label: 'North Carolina', value: 'NC' },
|
||||
{ label: 'North Dakota', value: 'ND' },
|
||||
{ label: 'Ohio', value: 'OH' },
|
||||
{ label: 'Oklahoma', value: 'OK' },
|
||||
{ label: 'Oregon', value: 'OR' },
|
||||
{ label: 'Pennsylvania', value: 'PA' },
|
||||
{ label: 'Rhode Island', value: 'RI' },
|
||||
{ label: 'South Carolina', value: 'SC' },
|
||||
{ label: 'South Dakota', value: 'SD' },
|
||||
{ label: 'Tennessee', value: 'TN' },
|
||||
{ label: 'Texas', value: 'TX' },
|
||||
{ label: 'Utah', value: 'UT' },
|
||||
{ label: 'Vermont', value: 'VT' },
|
||||
{ label: 'Virginia', value: 'VA' },
|
||||
{ label: 'Washington', value: 'WA' },
|
||||
{ label: 'West Virginia', value: 'WV' },
|
||||
{ label: 'Wisconsin', value: 'WI' },
|
||||
{ label: 'Wyoming', value: 'WY' },
|
||||
]
|
||||
@@ -1,32 +0,0 @@
|
||||
import type { TextField } from '@payloadcms/plugin-form-builder/types'
|
||||
import type { FieldErrorsImpl, FieldValues, UseFormRegister } from 'react-hook-form'
|
||||
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import React from 'react'
|
||||
|
||||
import { Error } from '../Error'
|
||||
import { Width } from '../Width'
|
||||
|
||||
export const Text: React.FC<
|
||||
TextField & {
|
||||
errors: Partial<FieldErrorsImpl>
|
||||
register: UseFormRegister<FieldValues>
|
||||
}
|
||||
> = ({ name, defaultValue, errors, label, register, required, width }) => {
|
||||
return (
|
||||
<Width width={width}>
|
||||
<Label htmlFor={name}>
|
||||
{label}
|
||||
|
||||
{required && (
|
||||
<span className="required">
|
||||
* <span className="sr-only">(required)</span>
|
||||
</span>
|
||||
)}
|
||||
</Label>
|
||||
<Input defaultValue={defaultValue} id={name} type="text" {...register(name, { required })} />
|
||||
{errors[name] && <Error name={name} />}
|
||||
</Width>
|
||||
)
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import type { TextField } from '@payloadcms/plugin-form-builder/types'
|
||||
import type { FieldErrorsImpl, FieldValues, UseFormRegister } from 'react-hook-form'
|
||||
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Textarea as TextAreaComponent } from '@/components/ui/textarea'
|
||||
import React from 'react'
|
||||
|
||||
import { Error } from '../Error'
|
||||
import { Width } from '../Width'
|
||||
|
||||
export const Textarea: React.FC<
|
||||
TextField & {
|
||||
errors: Partial<FieldErrorsImpl>
|
||||
register: UseFormRegister<FieldValues>
|
||||
rows?: number
|
||||
}
|
||||
> = ({ name, defaultValue, errors, label, register, required, rows = 3, width }) => {
|
||||
return (
|
||||
<Width width={width}>
|
||||
<Label htmlFor={name}>
|
||||
{label}
|
||||
|
||||
{required && (
|
||||
<span className="required">
|
||||
* <span className="sr-only">(required)</span>
|
||||
</span>
|
||||
)}
|
||||
</Label>
|
||||
|
||||
<TextAreaComponent
|
||||
defaultValue={defaultValue}
|
||||
id={name}
|
||||
rows={rows}
|
||||
{...register(name, { required: required })}
|
||||
/>
|
||||
|
||||
{errors[name] && <Error name={name} />}
|
||||
</Width>
|
||||
)
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import * as React from 'react'
|
||||
|
||||
export const Width: React.FC<{
|
||||
children: React.ReactNode
|
||||
className?: string
|
||||
width?: number | string
|
||||
}> = ({ children, className, width }) => {
|
||||
return (
|
||||
<div className={className} style={{ maxWidth: width ? `${width}%` : undefined }}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import type { Block } from 'payload'
|
||||
|
||||
import {
|
||||
FixedToolbarFeature,
|
||||
HeadingFeature,
|
||||
InlineToolbarFeature,
|
||||
lexicalEditor,
|
||||
} from '@payloadcms/richtext-lexical'
|
||||
|
||||
export const FormBlock: Block = {
|
||||
slug: 'formBlock',
|
||||
interfaceName: 'FormBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'form',
|
||||
type: 'relationship',
|
||||
relationTo: 'forms',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'enableIntro',
|
||||
type: 'checkbox',
|
||||
label: 'Enable Intro Content',
|
||||
},
|
||||
{
|
||||
name: 'introContent',
|
||||
type: 'richText',
|
||||
admin: {
|
||||
condition: (_, { enableIntro }) => Boolean(enableIntro),
|
||||
},
|
||||
editor: lexicalEditor({
|
||||
features: ({ rootFeatures }) => {
|
||||
return [
|
||||
...rootFeatures,
|
||||
HeadingFeature({ enabledHeadingSizes: ['h1', 'h2', 'h3', 'h4'] }),
|
||||
FixedToolbarFeature(),
|
||||
InlineToolbarFeature(),
|
||||
]
|
||||
},
|
||||
}),
|
||||
label: 'Intro Content',
|
||||
},
|
||||
],
|
||||
graphQL: {
|
||||
singularName: 'FormBlock',
|
||||
},
|
||||
labels: {
|
||||
plural: 'Form Blocks',
|
||||
singular: 'Form Block',
|
||||
},
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { Checkbox } from './Checkbox'
|
||||
import { Country } from './Country'
|
||||
import { Email } from './Email'
|
||||
import { Message } from './Message'
|
||||
import { Number } from './Number'
|
||||
import { Select } from './Select'
|
||||
import { State } from './State'
|
||||
import { Text } from './Text'
|
||||
import { Textarea } from './Textarea'
|
||||
|
||||
export const fields = {
|
||||
checkbox: Checkbox,
|
||||
country: Country,
|
||||
email: Email,
|
||||
message: Message,
|
||||
number: Number,
|
||||
select: Select,
|
||||
state: State,
|
||||
text: Text,
|
||||
textarea: Textarea,
|
||||
}
|
||||
@@ -24,7 +24,7 @@ export const RelatedPosts: React.FC<RelatedPostsProps> = (props) => {
|
||||
{docs?.map((doc, index) => {
|
||||
if (typeof doc === 'string') return null
|
||||
|
||||
return <Card key={index} doc={doc} relationTo="posts" showCategories />
|
||||
return <Card key={index} doc={doc} relationTo="posts" />
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,17 +2,13 @@ import React, { Fragment } from 'react'
|
||||
|
||||
import type { Page } from '@/payload-types'
|
||||
|
||||
import { ArchiveBlock } from '@/blocks/ArchiveBlock/Component'
|
||||
import { CallToActionBlock } from '@/blocks/CallToAction/Component'
|
||||
import { ContentBlock } from '@/blocks/Content/Component'
|
||||
import { FormBlock } from '@/blocks/Form/Component'
|
||||
import { MediaBlock } from '@/blocks/MediaBlock/Component'
|
||||
|
||||
const blockComponents = {
|
||||
archive: ArchiveBlock,
|
||||
content: ContentBlock,
|
||||
cta: CallToActionBlock,
|
||||
formBlock: FormBlock,
|
||||
mediaBlock: MediaBlock,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { anyone } from '../access/anyone'
|
||||
import { authenticated } from '../access/authenticated'
|
||||
import { slugField } from 'payload'
|
||||
|
||||
export const Categories: CollectionConfig = {
|
||||
slug: 'categories',
|
||||
access: {
|
||||
create: authenticated,
|
||||
delete: authenticated,
|
||||
read: anyone,
|
||||
update: authenticated,
|
||||
},
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
slugField({
|
||||
position: undefined,
|
||||
}),
|
||||
],
|
||||
}
|
||||
@@ -17,8 +17,8 @@ import {
|
||||
export const Events: CollectionConfig = {
|
||||
slug: 'events',
|
||||
labels: {
|
||||
singular: 'Event',
|
||||
plural: 'Events',
|
||||
singular: 'Termin / Event',
|
||||
plural: 'Termine & Events',
|
||||
},
|
||||
access: {
|
||||
create: authenticated,
|
||||
@@ -28,6 +28,7 @@ export const Events: CollectionConfig = {
|
||||
},
|
||||
admin: {
|
||||
defaultColumns: ['title', 'spaPath', 'slug', 'updatedAt'],
|
||||
group: 'Inhalte',
|
||||
livePreview: {
|
||||
url: ({ data, req }) =>
|
||||
generatePreviewPath({
|
||||
|
||||
@@ -16,6 +16,10 @@ const dirname = path.dirname(filename)
|
||||
|
||||
export const Media: CollectionConfig = {
|
||||
slug: 'media',
|
||||
labels: {
|
||||
singular: 'Medium',
|
||||
plural: 'Medien',
|
||||
},
|
||||
folders: true,
|
||||
access: {
|
||||
create: authenticated,
|
||||
@@ -39,6 +43,9 @@ export const Media: CollectionConfig = {
|
||||
}),
|
||||
},
|
||||
],
|
||||
admin: {
|
||||
group: 'Medien',
|
||||
},
|
||||
upload: {
|
||||
// Upload to the public/media directory in Next.js making them publicly accessible even outside of Payload
|
||||
staticDir: path.resolve(dirname, '../../public/media'),
|
||||
|
||||
@@ -92,9 +92,13 @@ export const homeFields: Field[] = [
|
||||
text('partnersLabel', 'Partner ticker label', homeContent.hero.partnersLabel),
|
||||
{
|
||||
name: 'partners',
|
||||
label: 'Partner ticker names',
|
||||
label: 'Fallback partner ticker names',
|
||||
type: 'array',
|
||||
defaultValue: homeContent.hero.partners,
|
||||
admin: {
|
||||
description:
|
||||
'Used only if partner collection records are unavailable. The frontend prefers the real logo uploads from the Partners collection.',
|
||||
},
|
||||
fields: [text('name', 'Name')],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -2,10 +2,8 @@ import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { authenticated } from '../../access/authenticated'
|
||||
import { authenticatedOrPublished } from '../../access/authenticatedOrPublished'
|
||||
import { Archive } from '../../blocks/ArchiveBlock/config'
|
||||
import { CallToAction } from '../../blocks/CallToAction/config'
|
||||
import { Content } from '../../blocks/Content/config'
|
||||
import { FormBlock } from '../../blocks/Form/config'
|
||||
import { MediaBlock } from '../../blocks/MediaBlock/config'
|
||||
import { hero } from '@/heros/config'
|
||||
import { aboutFields } from './aboutFields'
|
||||
@@ -135,6 +133,10 @@ const isManagedSpaPage = (_: unknown, siblingData?: { slug?: string; spaPath?: s
|
||||
|
||||
export const Pages: CollectionConfig<'pages'> = {
|
||||
slug: 'pages',
|
||||
labels: {
|
||||
singular: 'Seite',
|
||||
plural: 'Seiten',
|
||||
},
|
||||
access: {
|
||||
create: authenticated,
|
||||
delete: authenticated,
|
||||
@@ -150,6 +152,7 @@ export const Pages: CollectionConfig<'pages'> = {
|
||||
},
|
||||
admin: {
|
||||
defaultColumns: ['title', 'spaPath', 'slug', 'updatedAt'],
|
||||
group: 'Inhalte',
|
||||
livePreview: {
|
||||
url: ({ data, req }) =>
|
||||
generatePreviewPath({
|
||||
@@ -190,7 +193,7 @@ export const Pages: CollectionConfig<'pages'> = {
|
||||
{
|
||||
name: 'layout',
|
||||
type: 'blocks',
|
||||
blocks: [CallToAction, Content, MediaBlock, Archive, FormBlock],
|
||||
blocks: [CallToAction, Content, MediaBlock],
|
||||
required: true,
|
||||
admin: {
|
||||
initCollapsed: true,
|
||||
|
||||
@@ -58,46 +58,9 @@ const juryMemberFields: Field[] = [
|
||||
|
||||
const rowFields: Field[] = [text('num', 'Number'), text('label', 'Label'), textarea('body', 'Body')]
|
||||
|
||||
const partnerFields: Field[] = [
|
||||
text('stableId', 'Stable ID'),
|
||||
text('name', 'Name'),
|
||||
text('role', 'Role'),
|
||||
numberField('tier', 'Tier'),
|
||||
textarea('desc', 'Short description'),
|
||||
textarea('fullDesc', 'Full modal description'),
|
||||
{
|
||||
name: 'logoKind',
|
||||
label: 'Logo style',
|
||||
type: 'select',
|
||||
defaultValue: 'text',
|
||||
options: [
|
||||
{ label: 'Text', value: 'text' },
|
||||
{ label: 'Serif text', value: 'serif' },
|
||||
{ label: 'Badge', value: 'badge' },
|
||||
{ label: 'Monogram', value: 'monogram' },
|
||||
{ label: 'Dot mark', value: 'dot' },
|
||||
{ label: 'Leaf mark', value: 'leaf' },
|
||||
{ label: 'RSM blocks', value: 'rsm' },
|
||||
{ label: 'Deutsche Bank mark', value: 'deutschebank' },
|
||||
],
|
||||
},
|
||||
text('logoText', 'Logo text'),
|
||||
text('logoSubtext', 'Logo subtext'),
|
||||
text('logoColor', 'Logo color'),
|
||||
text('industry', 'Industry'),
|
||||
text('location', 'Location'),
|
||||
text('website', 'Website'),
|
||||
text('linkedin', 'LinkedIn URL'),
|
||||
text('heroImg', 'Modal hero image URL'),
|
||||
]
|
||||
|
||||
const benefitFields: Field[] = [text('num', 'Number'), text('label', 'Label'), text('sub', 'Subline')]
|
||||
const packageFields: Field[] = [text('value', 'Value'), text('title', 'Title'), textarea('desc', 'Description')]
|
||||
const formStepFields: Field[] = [text('label', 'Label')]
|
||||
const partnerDefaults = netzwerkContent.partners.items.map(({ id, ...partner }) => ({
|
||||
...partner,
|
||||
stableId: id,
|
||||
}))
|
||||
|
||||
export const netzwerkFields: Field[] = [
|
||||
{
|
||||
@@ -220,7 +183,7 @@ export const netzwerkFields: Field[] = [
|
||||
name: 'partners',
|
||||
label: '06 · Partners',
|
||||
type: 'group',
|
||||
admin: sectionAdmin('Partner section, tier labels, partner records, and modal labels.'),
|
||||
admin: sectionAdmin('Partner section copy, tier labels, and modal labels. Partner records are managed in the Partners collection.'),
|
||||
fields: [
|
||||
text('eyebrow', 'Eyebrow', netzwerkContent.partners.eyebrow),
|
||||
textarea('heading', 'Heading', netzwerkContent.partners.heading),
|
||||
@@ -251,14 +214,6 @@ export const netzwerkFields: Field[] = [
|
||||
text('footerRolePrefix', 'Footer role prefix', netzwerkContent.partners.modal.footerRolePrefix),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'items',
|
||||
label: 'Partners',
|
||||
type: 'array',
|
||||
dbName: 'network_partners',
|
||||
defaultValue: partnerDefaults,
|
||||
fields: partnerFields,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
175
src/collections/Partners.ts
Normal file
175
src/collections/Partners.ts
Normal file
@@ -0,0 +1,175 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { authenticated } from '@/access/authenticated'
|
||||
import { authenticatedOrPublished } from '@/access/authenticatedOrPublished'
|
||||
import { populatePublishedAt } from '@/hooks/populatePublishedAt'
|
||||
|
||||
const logoKindOptions = [
|
||||
{ label: 'Text', value: 'text' },
|
||||
{ label: 'Serif text', value: 'serif' },
|
||||
{ label: 'Badge', value: 'badge' },
|
||||
{ label: 'Monogram', value: 'monogram' },
|
||||
{ label: 'Dot mark', value: 'dot' },
|
||||
{ label: 'Leaf mark', value: 'leaf' },
|
||||
{ label: 'RSM blocks', value: 'rsm' },
|
||||
{ label: 'Deutsche Bank mark', value: 'deutschebank' },
|
||||
]
|
||||
|
||||
export const Partners: CollectionConfig = {
|
||||
slug: 'partners',
|
||||
labels: {
|
||||
singular: 'Partner',
|
||||
plural: 'Partner',
|
||||
},
|
||||
access: {
|
||||
create: authenticated,
|
||||
delete: authenticated,
|
||||
read: authenticatedOrPublished,
|
||||
update: authenticated,
|
||||
},
|
||||
admin: {
|
||||
defaultColumns: ['name', 'role', 'tier', 'sortOrder', 'active', 'showOnHomepage', 'updatedAt'],
|
||||
group: 'Inhalte',
|
||||
useAsTitle: 'name',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'stableId',
|
||||
type: 'text',
|
||||
unique: true,
|
||||
index: true,
|
||||
admin: {
|
||||
description: 'Stable machine-readable key used when migrating or matching partner records.',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'role',
|
||||
type: 'select',
|
||||
required: true,
|
||||
options: [
|
||||
{ label: 'Hauptsponsor', value: 'Hauptsponsor' },
|
||||
{ label: 'Sponsor', value: 'Sponsor' },
|
||||
{ label: 'Finanzpartner', value: 'Finanzpartner' },
|
||||
{ label: 'Partner', value: 'Partner' },
|
||||
{ label: 'Medienpartner', value: 'Medienpartner' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'tier',
|
||||
type: 'number',
|
||||
defaultValue: 3,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'sortOrder',
|
||||
type: 'number',
|
||||
defaultValue: 100,
|
||||
admin: {
|
||||
description: 'Lower numbers appear earlier on partner surfaces.',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'active',
|
||||
type: 'checkbox',
|
||||
defaultValue: true,
|
||||
label: 'Active',
|
||||
},
|
||||
{
|
||||
name: 'showOnHomepage',
|
||||
type: 'checkbox',
|
||||
defaultValue: true,
|
||||
label: 'Show on homepage ticker',
|
||||
},
|
||||
{
|
||||
name: 'logo',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
admin: {
|
||||
description: 'Preferred real partner logo. Styled logo fallback fields below are used when this is empty.',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'logoAlt',
|
||||
type: 'text',
|
||||
label: 'Logo alt text',
|
||||
},
|
||||
{
|
||||
name: 'logoKind',
|
||||
type: 'select',
|
||||
defaultValue: 'text',
|
||||
label: 'Fallback logo style',
|
||||
options: logoKindOptions,
|
||||
},
|
||||
{
|
||||
name: 'logoText',
|
||||
type: 'text',
|
||||
label: 'Fallback logo text',
|
||||
},
|
||||
{
|
||||
name: 'logoSubtext',
|
||||
type: 'text',
|
||||
label: 'Fallback logo subtext',
|
||||
},
|
||||
{
|
||||
name: 'logoColor',
|
||||
type: 'text',
|
||||
label: 'Fallback logo color',
|
||||
},
|
||||
{
|
||||
name: 'desc',
|
||||
type: 'textarea',
|
||||
label: 'Short description',
|
||||
},
|
||||
{
|
||||
name: 'fullDesc',
|
||||
type: 'textarea',
|
||||
label: 'Full modal description',
|
||||
},
|
||||
{
|
||||
name: 'industry',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'location',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'website',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'linkedin',
|
||||
type: 'text',
|
||||
label: 'LinkedIn URL',
|
||||
},
|
||||
{
|
||||
name: 'heroImg',
|
||||
type: 'text',
|
||||
label: 'Modal hero image URL',
|
||||
},
|
||||
{
|
||||
name: 'publishedAt',
|
||||
type: 'date',
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
},
|
||||
],
|
||||
hooks: {
|
||||
beforeChange: [populatePublishedAt],
|
||||
},
|
||||
versions: {
|
||||
drafts: {
|
||||
autosave: {
|
||||
interval: 100,
|
||||
},
|
||||
schedulePublish: true,
|
||||
},
|
||||
maxPerDoc: 50,
|
||||
},
|
||||
}
|
||||
@@ -31,8 +31,8 @@ import { slugField } from 'payload'
|
||||
export const Posts: CollectionConfig<'posts'> = {
|
||||
slug: 'posts',
|
||||
labels: {
|
||||
singular: 'Presse',
|
||||
plural: 'Presse',
|
||||
singular: 'Presseartikel',
|
||||
plural: 'Presseartikel',
|
||||
},
|
||||
access: {
|
||||
create: authenticated,
|
||||
@@ -46,7 +46,6 @@ export const Posts: CollectionConfig<'posts'> = {
|
||||
defaultPopulate: {
|
||||
title: true,
|
||||
slug: true,
|
||||
categories: true,
|
||||
meta: {
|
||||
image: true,
|
||||
description: true,
|
||||
@@ -54,6 +53,7 @@ export const Posts: CollectionConfig<'posts'> = {
|
||||
},
|
||||
admin: {
|
||||
defaultColumns: ['title', 'spaPath', 'slug', 'updatedAt'],
|
||||
group: 'Inhalte',
|
||||
livePreview: {
|
||||
url: ({ data, req }) =>
|
||||
generatePreviewPath({
|
||||
@@ -254,17 +254,8 @@ export const Posts: CollectionConfig<'posts'> = {
|
||||
hasMany: true,
|
||||
relationTo: 'posts',
|
||||
},
|
||||
{
|
||||
name: 'categories',
|
||||
type: 'relationship',
|
||||
admin: {
|
||||
position: 'sidebar',
|
||||
},
|
||||
hasMany: true,
|
||||
relationTo: 'categories',
|
||||
},
|
||||
],
|
||||
label: 'Meta',
|
||||
label: 'Verknüpfungen',
|
||||
},
|
||||
{
|
||||
name: 'meta',
|
||||
|
||||
@@ -28,6 +28,7 @@ export const Preistraeger: CollectionConfig = {
|
||||
},
|
||||
admin: {
|
||||
defaultColumns: ['title', 'spaPath', 'slug', 'updatedAt'],
|
||||
group: 'Inhalte',
|
||||
livePreview: {
|
||||
url: ({ data, req }) =>
|
||||
generatePreviewPath({
|
||||
|
||||
@@ -4,6 +4,10 @@ import { authenticated } from '../../access/authenticated'
|
||||
|
||||
export const Users: CollectionConfig = {
|
||||
slug: 'users',
|
||||
labels: {
|
||||
singular: 'Benutzer',
|
||||
plural: 'Benutzer',
|
||||
},
|
||||
access: {
|
||||
admin: authenticated,
|
||||
create: authenticated,
|
||||
@@ -13,6 +17,7 @@ export const Users: CollectionConfig = {
|
||||
},
|
||||
admin: {
|
||||
defaultColumns: ['name', 'email'],
|
||||
group: 'Administration',
|
||||
useAsTitle: 'name',
|
||||
},
|
||||
auth: true,
|
||||
|
||||
@@ -2,32 +2,30 @@
|
||||
import { cn } from '@/utilities/ui'
|
||||
import useClickableCard from '@/utilities/useClickableCard'
|
||||
import Link from 'next/link'
|
||||
import React, { Fragment } from 'react'
|
||||
import React from 'react'
|
||||
|
||||
import type { Post } from '@/payload-types'
|
||||
|
||||
import { Media } from '@/components/Media'
|
||||
|
||||
export type CardPostData = Pick<Post, 'slug' | 'categories' | 'meta' | 'title'>
|
||||
export type CardPostData = Pick<Post, 'slug' | 'meta' | 'title'>
|
||||
|
||||
export const Card: React.FC<{
|
||||
alignItems?: 'center'
|
||||
className?: string
|
||||
doc?: CardPostData
|
||||
relationTo?: 'posts'
|
||||
showCategories?: boolean
|
||||
title?: string
|
||||
}> = (props) => {
|
||||
const {
|
||||
card: { ref: cardRef },
|
||||
link: { ref: linkRef },
|
||||
} = useClickableCard({})
|
||||
const { className, doc, relationTo, showCategories, title: titleFromProps } = props
|
||||
const { className, doc, relationTo, title: titleFromProps } = props
|
||||
|
||||
const { slug, categories, meta, title } = doc || {}
|
||||
const { slug, meta, title } = doc || {}
|
||||
const { description, image: metaImage } = meta || {}
|
||||
|
||||
const hasCategories = categories && Array.isArray(categories) && categories.length > 0
|
||||
const titleToUse = titleFromProps || title
|
||||
const sanitizedDescription = description?.replace(/\s/g, ' ') // replace non-breaking space with white space
|
||||
const href = `/${relationTo}/${slug}`
|
||||
@@ -45,28 +43,6 @@ export const Card: React.FC<{
|
||||
{metaImage && typeof metaImage !== 'string' && <Media resource={metaImage} size="33vw" />}
|
||||
</div>
|
||||
<div className="p-4">
|
||||
{showCategories && hasCategories && (
|
||||
<div className="uppercase text-sm mb-4">
|
||||
{categories?.map((category, index) => {
|
||||
if (typeof category === 'object') {
|
||||
const { title: titleFromCategory } = category
|
||||
|
||||
const categoryTitle = titleFromCategory || 'Untitled category'
|
||||
|
||||
const isLast = index === categories.length - 1
|
||||
|
||||
return (
|
||||
<Fragment key={index}>
|
||||
{categoryTitle}
|
||||
{!isLast && <Fragment>, </Fragment>}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{titleToUse && (
|
||||
<div className="prose">
|
||||
<h3>
|
||||
|
||||
@@ -18,7 +18,7 @@ export const CollectionArchive: React.FC<Props> = (props) => {
|
||||
if (typeof result === 'object' && result !== null) {
|
||||
return (
|
||||
<div className="col-span-4" key={index}>
|
||||
<Card className="h-full" doc={result} relationTo="posts" showCategories />
|
||||
<Card className="h-full" doc={result} relationTo="posts" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import type React from 'react'
|
||||
import type { Page, Post } from '@/payload-types'
|
||||
|
||||
import { getCachedDocument } from '@/utilities/getDocument'
|
||||
import { getCachedRedirects } from '@/utilities/getRedirects'
|
||||
import { notFound, redirect } from 'next/navigation'
|
||||
|
||||
interface Props {
|
||||
disableNotFound?: boolean
|
||||
url: string
|
||||
}
|
||||
|
||||
/* This component helps us with SSR based dynamic redirects */
|
||||
export const PayloadRedirects: React.FC<Props> = async ({ disableNotFound, url }) => {
|
||||
const redirects = await getCachedRedirects()()
|
||||
|
||||
const redirectItem = redirects.find((redirect) => redirect.from === url)
|
||||
|
||||
if (redirectItem) {
|
||||
if (redirectItem.to?.url) {
|
||||
redirect(redirectItem.to.url)
|
||||
}
|
||||
|
||||
let redirectUrl: string
|
||||
|
||||
if (typeof redirectItem.to?.reference?.value === 'string') {
|
||||
const collection = redirectItem.to?.reference?.relationTo
|
||||
const id = redirectItem.to?.reference?.value
|
||||
|
||||
const document = (await getCachedDocument(collection, id)()) as Page | Post
|
||||
redirectUrl = `${redirectItem.to?.reference?.relationTo !== 'pages' ? `/${redirectItem.to?.reference?.relationTo}` : ''}/${
|
||||
document?.slug
|
||||
}`
|
||||
} else {
|
||||
redirectUrl = `${redirectItem.to?.reference?.relationTo !== 'pages' ? `/${redirectItem.to?.reference?.relationTo}` : ''}/${
|
||||
typeof redirectItem.to?.reference?.value === 'object'
|
||||
? redirectItem.to?.reference?.value?.slug
|
||||
: ''
|
||||
}`
|
||||
}
|
||||
|
||||
if (redirectUrl) redirect(redirectUrl)
|
||||
}
|
||||
|
||||
if (disableNotFound) return null
|
||||
|
||||
notFound()
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
import { RequiredDataFromCollectionSlug } from 'payload'
|
||||
|
||||
export const contactForm: RequiredDataFromCollectionSlug<'forms'> = {
|
||||
confirmationMessage: {
|
||||
root: {
|
||||
type: 'root',
|
||||
children: [
|
||||
{
|
||||
type: 'heading',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'The contact form has been submitted successfully.',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
tag: 'h2',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
confirmationType: 'message',
|
||||
createdAt: '2023-01-12T21:47:41.374Z',
|
||||
emails: [
|
||||
{
|
||||
emailFrom: '"Payload" \u003Cdemo@payloadcms.com\u003E',
|
||||
emailTo: '{{email}}',
|
||||
message: {
|
||||
root: {
|
||||
type: 'root',
|
||||
children: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'Your contact form submission was successfully received.',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
textFormat: 0,
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
subject: "You've received a new message.",
|
||||
},
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
name: 'full-name',
|
||||
blockName: 'full-name',
|
||||
blockType: 'text',
|
||||
label: 'Full Name',
|
||||
required: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
blockName: 'email',
|
||||
blockType: 'email',
|
||||
label: 'Email',
|
||||
required: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
name: 'phone',
|
||||
blockName: 'phone',
|
||||
blockType: 'number',
|
||||
label: 'Phone',
|
||||
required: false,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
name: 'message',
|
||||
blockName: 'message',
|
||||
blockType: 'textarea',
|
||||
label: 'Message',
|
||||
required: true,
|
||||
width: 100,
|
||||
},
|
||||
],
|
||||
redirect: undefined,
|
||||
submitButtonLabel: 'Submit',
|
||||
title: 'Contact Form',
|
||||
updatedAt: '2023-01-12T21:47:41.374Z',
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
import type { Form } from '@/payload-types'
|
||||
import { RequiredDataFromCollectionSlug } from 'payload'
|
||||
|
||||
type ContactArgs = {
|
||||
contactForm: Form
|
||||
}
|
||||
|
||||
export const contact: (args: ContactArgs) => RequiredDataFromCollectionSlug<'pages'> = ({
|
||||
contactForm,
|
||||
}) => {
|
||||
return {
|
||||
slug: 'contact',
|
||||
_status: 'published',
|
||||
hero: {
|
||||
type: 'none',
|
||||
},
|
||||
layout: [
|
||||
{
|
||||
blockType: 'formBlock',
|
||||
enableIntro: true,
|
||||
form: contactForm,
|
||||
introContent: {
|
||||
root: {
|
||||
type: 'root',
|
||||
children: [
|
||||
{
|
||||
type: 'heading',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'Example contact form:',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
tag: 'h3',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
title: 'Contact',
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ export const homeStatic: RequiredDataFromCollectionSlug<'pages'> = {
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'Payload Website Template',
|
||||
text: 'Bayerischer Mittelstandspreis',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
@@ -80,8 +80,8 @@ export const homeStatic: RequiredDataFromCollectionSlug<'pages'> = {
|
||||
},
|
||||
},
|
||||
meta: {
|
||||
description: 'An open-source website built with Payload and Next.js.',
|
||||
title: 'Payload Website Template',
|
||||
description: 'Der Preis für herausragenden Mittelstand in Bayern.',
|
||||
title: 'Bayerischer Mittelstandspreis',
|
||||
},
|
||||
title: 'Home',
|
||||
layout: [],
|
||||
|
||||
@@ -47,7 +47,7 @@ export const home: (args: HomeArgs) => RequiredDataFromCollectionSlug<'pages'> =
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'Payload Website Template',
|
||||
text: 'Bayerischer Mittelstandspreis',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
@@ -513,62 +513,6 @@ export const home: (args: HomeArgs) => RequiredDataFromCollectionSlug<'pages'> =
|
||||
blockType: 'mediaBlock',
|
||||
media: metaImage.id,
|
||||
},
|
||||
{
|
||||
blockName: 'Archive Block',
|
||||
blockType: 'archive',
|
||||
categories: [],
|
||||
introContent: {
|
||||
root: {
|
||||
type: 'root',
|
||||
children: [
|
||||
{
|
||||
type: 'heading',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'Recent posts',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
tag: 'h3',
|
||||
version: 1,
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
detail: 0,
|
||||
format: 0,
|
||||
mode: 'normal',
|
||||
style: '',
|
||||
text: 'The posts below are displayed in an "Archive" layout building block which is an extremely powerful way to display documents on a page. It can be auto-populated by collection or by category, or posts can be individually selected. Pagination controls will automatically appear if the number of results exceeds the number of items per page.',
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
textFormat: 0,
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
direction: 'ltr',
|
||||
format: '',
|
||||
indent: 0,
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
populateBy: 'collection',
|
||||
relationTo: 'posts',
|
||||
},
|
||||
{
|
||||
blockName: 'CTA',
|
||||
blockType: 'cta',
|
||||
@@ -666,9 +610,9 @@ export const home: (args: HomeArgs) => RequiredDataFromCollectionSlug<'pages'> =
|
||||
},
|
||||
],
|
||||
meta: {
|
||||
description: 'An open-source website built with Payload and Next.js.',
|
||||
description: 'Der Preis für herausragenden Mittelstand in Bayern.',
|
||||
image: heroImage.id,
|
||||
title: 'Payload Website Template',
|
||||
title: 'Bayerischer Mittelstandspreis',
|
||||
},
|
||||
title: 'Home',
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import type { CollectionSlug, GlobalSlug, Payload, PayloadRequest, File } from 'payload'
|
||||
|
||||
import { contactForm as contactFormData } from './contact-form'
|
||||
import { contact as contactPageData } from './contact-page'
|
||||
import { home } from './home'
|
||||
import { image1 } from './image-1'
|
||||
import { image2 } from './image-2'
|
||||
@@ -14,19 +12,13 @@ import { defaultFooterData, defaultHeaderData } from '@/spa/cmsNavigation'
|
||||
import { defaultSiteSettings } from '@/spa/siteSettings'
|
||||
|
||||
const collections: CollectionSlug[] = [
|
||||
'categories',
|
||||
'media',
|
||||
'pages',
|
||||
'posts',
|
||||
'forms',
|
||||
'form-submissions',
|
||||
'search',
|
||||
]
|
||||
|
||||
const globals: GlobalSlug[] = ['header', 'footer', 'site-settings', 'application-phase']
|
||||
|
||||
const categories = ['Technology', 'News', 'Finance', 'Design', 'Software', 'Engineering']
|
||||
|
||||
// Next.js revalidation errors are normal when seeding the database without a server running
|
||||
// i.e. running `yarn seed` locally instead of using the admin UI within an active app
|
||||
// The app is not running to revalidate the pages and so the API routes are not available
|
||||
@@ -128,15 +120,6 @@ export const seed = async ({
|
||||
data: imageHero1,
|
||||
file: hero1Buffer,
|
||||
}),
|
||||
categories.map((category) =>
|
||||
payload.create({
|
||||
collection: 'categories',
|
||||
data: {
|
||||
title: category,
|
||||
slug: category,
|
||||
},
|
||||
}),
|
||||
),
|
||||
])
|
||||
|
||||
payload.logger.info(`— Seeding posts...`)
|
||||
@@ -193,14 +176,6 @@ export const seed = async ({
|
||||
},
|
||||
})
|
||||
|
||||
payload.logger.info(`— Seeding contact form...`)
|
||||
|
||||
const contactForm = await payload.create({
|
||||
collection: 'forms',
|
||||
depth: 0,
|
||||
data: contactFormData,
|
||||
})
|
||||
|
||||
payload.logger.info(`— Seeding pages...`)
|
||||
|
||||
await Promise.all([
|
||||
@@ -209,11 +184,6 @@ export const seed = async ({
|
||||
depth: 0,
|
||||
data: home({ heroImage: imageHomeDoc, metaImage: image2Doc }),
|
||||
}),
|
||||
payload.create({
|
||||
collection: 'pages',
|
||||
depth: 0,
|
||||
data: contactPageData({ contactForm: contactForm }),
|
||||
}),
|
||||
])
|
||||
|
||||
payload.logger.info(`— Seeding globals...`)
|
||||
|
||||
@@ -9,7 +9,7 @@ import { formatAuthors } from '@/utilities/formatAuthors'
|
||||
export const PostHero: React.FC<{
|
||||
post: Post
|
||||
}> = ({ post }) => {
|
||||
const { categories, heroImage, populatedAuthors, publishedAt, title } = post
|
||||
const { heroImage, populatedAuthors, publishedAt, title } = post
|
||||
|
||||
const hasAuthors =
|
||||
populatedAuthors && populatedAuthors.length > 0 && formatAuthors(populatedAuthors) !== ''
|
||||
@@ -18,26 +18,6 @@ export const PostHero: React.FC<{
|
||||
<div className="relative -mt-[10.4rem] flex items-end">
|
||||
<div className="container z-10 relative lg:grid lg:grid-cols-[1fr_48rem_1fr] text-white pb-8">
|
||||
<div className="col-start-1 col-span-1 md:col-start-2 md:col-span-2">
|
||||
<div className="uppercase text-sm mb-6">
|
||||
{categories?.map((category, index) => {
|
||||
if (typeof category === 'object' && category !== null) {
|
||||
const { title: categoryTitle } = category
|
||||
|
||||
const titleToUse = categoryTitle || 'Untitled category'
|
||||
|
||||
const isLast = index === categories.length - 1
|
||||
|
||||
return (
|
||||
<React.Fragment key={index}>
|
||||
{titleToUse}
|
||||
{!isLast && <React.Fragment>, </React.Fragment>}
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
return null
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="">
|
||||
<h1 className="mb-6 text-3xl md:text-5xl lg:text-6xl">{title}</h1>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import type { CollectionAfterChangeHook } from 'payload'
|
||||
|
||||
import { revalidateTag } from 'next/cache'
|
||||
|
||||
export const revalidateRedirects: CollectionAfterChangeHook = ({ doc, req: { payload } }) => {
|
||||
payload.logger.info(`Revalidating redirects`)
|
||||
|
||||
revalidateTag('redirects', 'max')
|
||||
|
||||
return doc
|
||||
}
|
||||
33553
src/migrations/20260630_172754_network_partner_logo_uploads.json
Normal file
33553
src/migrations/20260630_172754_network_partner_logo_uploads.json
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,70 @@
|
||||
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-sqlite'
|
||||
|
||||
export async function up({ db, payload: _payload, req: _req }: MigrateUpArgs): Promise<void> {
|
||||
await db.run(sql`ALTER TABLE \`network_partners\` ADD \`logo_id\` integer REFERENCES media(id);`)
|
||||
await db.run(sql`ALTER TABLE \`network_partners\` ADD \`logo_alt\` text;`)
|
||||
await db.run(sql`CREATE INDEX \`network_partners_logo_idx\` ON \`network_partners\` (\`logo_id\`);`)
|
||||
await db.run(sql`ALTER TABLE \`_network_partners_v\` ADD \`logo_id\` integer REFERENCES media(id);`)
|
||||
await db.run(sql`ALTER TABLE \`_network_partners_v\` ADD \`logo_alt\` text;`)
|
||||
await db.run(sql`CREATE INDEX \`_network_partners_v_logo_idx\` ON \`_network_partners_v\` (\`logo_id\`);`)
|
||||
}
|
||||
|
||||
export async function down({ db, payload: _payload, req: _req }: MigrateDownArgs): Promise<void> {
|
||||
await db.run(sql`PRAGMA foreign_keys=OFF;`)
|
||||
await db.run(sql`CREATE TABLE \`__new_network_partners\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`stable_id\` text,
|
||||
\`name\` text,
|
||||
\`role\` text,
|
||||
\`tier\` numeric,
|
||||
\`desc\` text,
|
||||
\`full_desc\` text,
|
||||
\`logo_kind\` text DEFAULT 'text',
|
||||
\`logo_text\` text,
|
||||
\`logo_subtext\` text,
|
||||
\`logo_color\` text,
|
||||
\`industry\` text,
|
||||
\`location\` text,
|
||||
\`website\` text,
|
||||
\`linkedin\` text,
|
||||
\`hero_img\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`pages\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`INSERT INTO \`__new_network_partners\`("_order", "_parent_id", "id", "stable_id", "name", "role", "tier", "desc", "full_desc", "logo_kind", "logo_text", "logo_subtext", "logo_color", "industry", "location", "website", "linkedin", "hero_img") SELECT "_order", "_parent_id", "id", "stable_id", "name", "role", "tier", "desc", "full_desc", "logo_kind", "logo_text", "logo_subtext", "logo_color", "industry", "location", "website", "linkedin", "hero_img" FROM \`network_partners\`;`)
|
||||
await db.run(sql`DROP TABLE \`network_partners\`;`)
|
||||
await db.run(sql`ALTER TABLE \`__new_network_partners\` RENAME TO \`network_partners\`;`)
|
||||
await db.run(sql`PRAGMA foreign_keys=ON;`)
|
||||
await db.run(sql`CREATE INDEX \`network_partners_order_idx\` ON \`network_partners\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`network_partners_parent_id_idx\` ON \`network_partners\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`__new__network_partners_v\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`stable_id\` text,
|
||||
\`name\` text,
|
||||
\`role\` text,
|
||||
\`tier\` numeric,
|
||||
\`desc\` text,
|
||||
\`full_desc\` text,
|
||||
\`logo_kind\` text DEFAULT 'text',
|
||||
\`logo_text\` text,
|
||||
\`logo_subtext\` text,
|
||||
\`logo_color\` text,
|
||||
\`industry\` text,
|
||||
\`location\` text,
|
||||
\`website\` text,
|
||||
\`linkedin\` text,
|
||||
\`hero_img\` text,
|
||||
\`_uuid\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`_pages_v\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`INSERT INTO \`__new__network_partners_v\`("_order", "_parent_id", "id", "stable_id", "name", "role", "tier", "desc", "full_desc", "logo_kind", "logo_text", "logo_subtext", "logo_color", "industry", "location", "website", "linkedin", "hero_img", "_uuid") SELECT "_order", "_parent_id", "id", "stable_id", "name", "role", "tier", "desc", "full_desc", "logo_kind", "logo_text", "logo_subtext", "logo_color", "industry", "location", "website", "linkedin", "hero_img", "_uuid" FROM \`_network_partners_v\`;`)
|
||||
await db.run(sql`DROP TABLE \`_network_partners_v\`;`)
|
||||
await db.run(sql`ALTER TABLE \`__new__network_partners_v\` RENAME TO \`_network_partners_v\`;`)
|
||||
await db.run(sql`CREATE INDEX \`_network_partners_v_order_idx\` ON \`_network_partners_v\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_network_partners_v_parent_id_idx\` ON \`_network_partners_v\` (\`_parent_id\`);`)
|
||||
}
|
||||
33742
src/migrations/20260630_175614_partners_collection.json
Normal file
33742
src/migrations/20260630_175614_partners_collection.json
Normal file
File diff suppressed because one or more lines are too long
367
src/migrations/20260630_175614_partners_collection.ts
Normal file
367
src/migrations/20260630_175614_partners_collection.ts
Normal file
@@ -0,0 +1,367 @@
|
||||
import { type MigrateUpArgs, type MigrateDownArgs, sql } from '@payloadcms/db-sqlite'
|
||||
|
||||
export async function up({ db, payload: _payload, req: _req }: MigrateUpArgs): Promise<void> {
|
||||
await db.run(sql`CREATE TABLE \`partners\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`name\` text,
|
||||
\`stable_id\` text,
|
||||
\`role\` text,
|
||||
\`tier\` numeric DEFAULT 3,
|
||||
\`sort_order\` numeric DEFAULT 100,
|
||||
\`active\` integer DEFAULT true,
|
||||
\`show_on_homepage\` integer DEFAULT true,
|
||||
\`logo_id\` integer,
|
||||
\`logo_alt\` text,
|
||||
\`logo_kind\` text DEFAULT 'text',
|
||||
\`logo_text\` text,
|
||||
\`logo_subtext\` text,
|
||||
\`logo_color\` text,
|
||||
\`desc\` text,
|
||||
\`full_desc\` text,
|
||||
\`industry\` text,
|
||||
\`location\` text,
|
||||
\`website\` text,
|
||||
\`linkedin\` text,
|
||||
\`hero_img\` text,
|
||||
\`published_at\` text,
|
||||
\`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
|
||||
\`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
|
||||
\`_status\` text DEFAULT 'draft',
|
||||
FOREIGN KEY (\`logo_id\`) REFERENCES \`media\`(\`id\`) ON UPDATE no action ON DELETE set null
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE UNIQUE INDEX \`partners_stable_id_idx\` ON \`partners\` (\`stable_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`partners_logo_idx\` ON \`partners\` (\`logo_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`partners_updated_at_idx\` ON \`partners\` (\`updated_at\`);`)
|
||||
await db.run(sql`CREATE INDEX \`partners_created_at_idx\` ON \`partners\` (\`created_at\`);`)
|
||||
await db.run(sql`CREATE INDEX \`partners__status_idx\` ON \`partners\` (\`_status\`);`)
|
||||
await db.run(sql`INSERT INTO \`partners\` (
|
||||
\`name\`,
|
||||
\`stable_id\`,
|
||||
\`role\`,
|
||||
\`tier\`,
|
||||
\`sort_order\`,
|
||||
\`active\`,
|
||||
\`show_on_homepage\`,
|
||||
\`logo_id\`,
|
||||
\`logo_alt\`,
|
||||
\`logo_kind\`,
|
||||
\`logo_text\`,
|
||||
\`logo_subtext\`,
|
||||
\`logo_color\`,
|
||||
\`desc\`,
|
||||
\`full_desc\`,
|
||||
\`industry\`,
|
||||
\`location\`,
|
||||
\`website\`,
|
||||
\`linkedin\`,
|
||||
\`hero_img\`,
|
||||
\`published_at\`,
|
||||
\`updated_at\`,
|
||||
\`created_at\`,
|
||||
\`_status\`
|
||||
)
|
||||
SELECT
|
||||
\`network_partners\`.\`name\`,
|
||||
COALESCE(\`network_partners\`.\`stable_id\`, lower(hex(randomblob(8)))),
|
||||
\`network_partners\`.\`role\`,
|
||||
\`network_partners\`.\`tier\`,
|
||||
\`network_partners\`.\`_order\`,
|
||||
true,
|
||||
true,
|
||||
\`network_partners\`.\`logo_id\`,
|
||||
\`network_partners\`.\`logo_alt\`,
|
||||
\`network_partners\`.\`logo_kind\`,
|
||||
\`network_partners\`.\`logo_text\`,
|
||||
\`network_partners\`.\`logo_subtext\`,
|
||||
\`network_partners\`.\`logo_color\`,
|
||||
\`network_partners\`.\`desc\`,
|
||||
\`network_partners\`.\`full_desc\`,
|
||||
\`network_partners\`.\`industry\`,
|
||||
\`network_partners\`.\`location\`,
|
||||
\`network_partners\`.\`website\`,
|
||||
\`network_partners\`.\`linkedin\`,
|
||||
\`network_partners\`.\`hero_img\`,
|
||||
COALESCE(\`pages\`.\`published_at\`, strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
||||
strftime('%Y-%m-%dT%H:%M:%fZ', 'now'),
|
||||
strftime('%Y-%m-%dT%H:%M:%fZ', 'now'),
|
||||
'published'
|
||||
FROM \`network_partners\`
|
||||
LEFT JOIN \`pages\` ON \`pages\`.\`id\` = \`network_partners\`.\`_parent_id\`
|
||||
WHERE \`network_partners\`.\`_parent_id\` = COALESCE(
|
||||
(SELECT \`id\` FROM \`pages\` WHERE \`spa_path\` = '/netzwerk' OR \`slug\` IN ('netzwerk', 'network') ORDER BY \`id\` LIMIT 1),
|
||||
(SELECT MIN(\`_parent_id\`) FROM \`network_partners\`)
|
||||
)
|
||||
ORDER BY \`network_partners\`.\`_order\`;`)
|
||||
await db.run(sql`CREATE TABLE \`_partners_v\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`parent_id\` integer,
|
||||
\`version_name\` text,
|
||||
\`version_stable_id\` text,
|
||||
\`version_role\` text,
|
||||
\`version_tier\` numeric DEFAULT 3,
|
||||
\`version_sort_order\` numeric DEFAULT 100,
|
||||
\`version_active\` integer DEFAULT true,
|
||||
\`version_show_on_homepage\` integer DEFAULT true,
|
||||
\`version_logo_id\` integer,
|
||||
\`version_logo_alt\` text,
|
||||
\`version_logo_kind\` text DEFAULT 'text',
|
||||
\`version_logo_text\` text,
|
||||
\`version_logo_subtext\` text,
|
||||
\`version_logo_color\` text,
|
||||
\`version_desc\` text,
|
||||
\`version_full_desc\` text,
|
||||
\`version_industry\` text,
|
||||
\`version_location\` text,
|
||||
\`version_website\` text,
|
||||
\`version_linkedin\` text,
|
||||
\`version_hero_img\` text,
|
||||
\`version_published_at\` text,
|
||||
\`version_updated_at\` text,
|
||||
\`version_created_at\` text,
|
||||
\`version__status\` text DEFAULT 'draft',
|
||||
\`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
|
||||
\`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
|
||||
\`latest\` integer,
|
||||
\`autosave\` integer,
|
||||
FOREIGN KEY (\`parent_id\`) REFERENCES \`partners\`(\`id\`) ON UPDATE no action ON DELETE set null,
|
||||
FOREIGN KEY (\`version_logo_id\`) REFERENCES \`media\`(\`id\`) ON UPDATE no action ON DELETE set null
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`_partners_v_parent_idx\` ON \`_partners_v\` (\`parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_partners_v_version_version_stable_id_idx\` ON \`_partners_v\` (\`version_stable_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_partners_v_version_version_logo_idx\` ON \`_partners_v\` (\`version_logo_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_partners_v_version_version_updated_at_idx\` ON \`_partners_v\` (\`version_updated_at\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_partners_v_version_version_created_at_idx\` ON \`_partners_v\` (\`version_created_at\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_partners_v_version_version__status_idx\` ON \`_partners_v\` (\`version__status\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_partners_v_created_at_idx\` ON \`_partners_v\` (\`created_at\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_partners_v_updated_at_idx\` ON \`_partners_v\` (\`updated_at\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_partners_v_latest_idx\` ON \`_partners_v\` (\`latest\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_partners_v_autosave_idx\` ON \`_partners_v\` (\`autosave\`);`)
|
||||
await db.run(sql`INSERT INTO \`_partners_v\` (
|
||||
\`parent_id\`,
|
||||
\`version_name\`,
|
||||
\`version_stable_id\`,
|
||||
\`version_role\`,
|
||||
\`version_tier\`,
|
||||
\`version_sort_order\`,
|
||||
\`version_active\`,
|
||||
\`version_show_on_homepage\`,
|
||||
\`version_logo_id\`,
|
||||
\`version_logo_alt\`,
|
||||
\`version_logo_kind\`,
|
||||
\`version_logo_text\`,
|
||||
\`version_logo_subtext\`,
|
||||
\`version_logo_color\`,
|
||||
\`version_desc\`,
|
||||
\`version_full_desc\`,
|
||||
\`version_industry\`,
|
||||
\`version_location\`,
|
||||
\`version_website\`,
|
||||
\`version_linkedin\`,
|
||||
\`version_hero_img\`,
|
||||
\`version_published_at\`,
|
||||
\`version_updated_at\`,
|
||||
\`version_created_at\`,
|
||||
\`version__status\`,
|
||||
\`created_at\`,
|
||||
\`updated_at\`,
|
||||
\`latest\`,
|
||||
\`autosave\`
|
||||
)
|
||||
SELECT
|
||||
\`id\`,
|
||||
\`name\`,
|
||||
\`stable_id\`,
|
||||
\`role\`,
|
||||
\`tier\`,
|
||||
\`sort_order\`,
|
||||
\`active\`,
|
||||
\`show_on_homepage\`,
|
||||
\`logo_id\`,
|
||||
\`logo_alt\`,
|
||||
\`logo_kind\`,
|
||||
\`logo_text\`,
|
||||
\`logo_subtext\`,
|
||||
\`logo_color\`,
|
||||
\`desc\`,
|
||||
\`full_desc\`,
|
||||
\`industry\`,
|
||||
\`location\`,
|
||||
\`website\`,
|
||||
\`linkedin\`,
|
||||
\`hero_img\`,
|
||||
\`published_at\`,
|
||||
\`updated_at\`,
|
||||
\`created_at\`,
|
||||
\`_status\`,
|
||||
\`created_at\`,
|
||||
\`updated_at\`,
|
||||
true,
|
||||
false
|
||||
FROM \`partners\`
|
||||
ORDER BY \`sort_order\`, \`id\`;`)
|
||||
await db.run(sql`DROP TABLE \`network_partners\`;`)
|
||||
await db.run(sql`DROP TABLE \`_network_partners_v\`;`)
|
||||
await db.run(sql`ALTER TABLE \`payload_locked_documents_rels\` ADD \`partners_id\` integer REFERENCES partners(id);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_partners_id_idx\` ON \`payload_locked_documents_rels\` (\`partners_id\`);`)
|
||||
}
|
||||
|
||||
export async function down({ db, payload: _payload, req: _req }: MigrateDownArgs): Promise<void> {
|
||||
await db.run(sql`CREATE TABLE \`network_partners\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`stable_id\` text,
|
||||
\`name\` text,
|
||||
\`role\` text,
|
||||
\`tier\` numeric,
|
||||
\`desc\` text,
|
||||
\`full_desc\` text,
|
||||
\`logo_id\` integer,
|
||||
\`logo_alt\` text,
|
||||
\`logo_kind\` text DEFAULT 'text',
|
||||
\`logo_text\` text,
|
||||
\`logo_subtext\` text,
|
||||
\`logo_color\` text,
|
||||
\`industry\` text,
|
||||
\`location\` text,
|
||||
\`website\` text,
|
||||
\`linkedin\` text,
|
||||
\`hero_img\` text,
|
||||
FOREIGN KEY (\`logo_id\`) REFERENCES \`media\`(\`id\`) ON UPDATE no action ON DELETE set null,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`pages\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`network_partners_order_idx\` ON \`network_partners\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`network_partners_parent_id_idx\` ON \`network_partners\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`network_partners_logo_idx\` ON \`network_partners\` (\`logo_id\`);`)
|
||||
await db.run(sql`INSERT INTO \`network_partners\` (
|
||||
\`_order\`,
|
||||
\`_parent_id\`,
|
||||
\`id\`,
|
||||
\`stable_id\`,
|
||||
\`name\`,
|
||||
\`role\`,
|
||||
\`tier\`,
|
||||
\`desc\`,
|
||||
\`full_desc\`,
|
||||
\`logo_id\`,
|
||||
\`logo_alt\`,
|
||||
\`logo_kind\`,
|
||||
\`logo_text\`,
|
||||
\`logo_subtext\`,
|
||||
\`logo_color\`,
|
||||
\`industry\`,
|
||||
\`location\`,
|
||||
\`website\`,
|
||||
\`linkedin\`,
|
||||
\`hero_img\`
|
||||
)
|
||||
SELECT
|
||||
COALESCE(\`partners\`.\`sort_order\`, 100),
|
||||
(SELECT \`id\` FROM \`pages\` WHERE \`spa_path\` = '/netzwerk' OR \`slug\` IN ('netzwerk', 'network') ORDER BY \`id\` LIMIT 1),
|
||||
lower(hex(randomblob(12))),
|
||||
\`partners\`.\`stable_id\`,
|
||||
\`partners\`.\`name\`,
|
||||
\`partners\`.\`role\`,
|
||||
\`partners\`.\`tier\`,
|
||||
\`partners\`.\`desc\`,
|
||||
\`partners\`.\`full_desc\`,
|
||||
\`partners\`.\`logo_id\`,
|
||||
\`partners\`.\`logo_alt\`,
|
||||
\`partners\`.\`logo_kind\`,
|
||||
\`partners\`.\`logo_text\`,
|
||||
\`partners\`.\`logo_subtext\`,
|
||||
\`partners\`.\`logo_color\`,
|
||||
\`partners\`.\`industry\`,
|
||||
\`partners\`.\`location\`,
|
||||
\`partners\`.\`website\`,
|
||||
\`partners\`.\`linkedin\`,
|
||||
\`partners\`.\`hero_img\`
|
||||
FROM \`partners\`
|
||||
ORDER BY \`partners\`.\`sort_order\`, \`partners\`.\`id\`;`)
|
||||
await db.run(sql`CREATE TABLE \`_network_partners_v\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`stable_id\` text,
|
||||
\`name\` text,
|
||||
\`role\` text,
|
||||
\`tier\` numeric,
|
||||
\`desc\` text,
|
||||
\`full_desc\` text,
|
||||
\`logo_id\` integer,
|
||||
\`logo_alt\` text,
|
||||
\`logo_kind\` text DEFAULT 'text',
|
||||
\`logo_text\` text,
|
||||
\`logo_subtext\` text,
|
||||
\`logo_color\` text,
|
||||
\`industry\` text,
|
||||
\`location\` text,
|
||||
\`website\` text,
|
||||
\`linkedin\` text,
|
||||
\`hero_img\` text,
|
||||
\`_uuid\` text,
|
||||
FOREIGN KEY (\`logo_id\`) REFERENCES \`media\`(\`id\`) ON UPDATE no action ON DELETE set null,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`_pages_v\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`_network_partners_v_order_idx\` ON \`_network_partners_v\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_network_partners_v_parent_id_idx\` ON \`_network_partners_v\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_network_partners_v_logo_idx\` ON \`_network_partners_v\` (\`logo_id\`);`)
|
||||
await db.run(sql`DROP TABLE \`partners\`;`)
|
||||
await db.run(sql`DROP TABLE \`_partners_v\`;`)
|
||||
await db.run(sql`PRAGMA foreign_keys=OFF;`)
|
||||
await db.run(sql`CREATE TABLE \`__new_payload_locked_documents_rels\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`order\` integer,
|
||||
\`parent_id\` integer NOT NULL,
|
||||
\`path\` text NOT NULL,
|
||||
\`pages_id\` integer,
|
||||
\`posts_id\` integer,
|
||||
\`events_id\` integer,
|
||||
\`preistraeger_id\` integer,
|
||||
\`media_id\` integer,
|
||||
\`categories_id\` integer,
|
||||
\`users_id\` integer,
|
||||
\`redirects_id\` integer,
|
||||
\`forms_id\` integer,
|
||||
\`form_submissions_id\` integer,
|
||||
\`search_id\` integer,
|
||||
\`payload_folders_id\` integer,
|
||||
FOREIGN KEY (\`parent_id\`) REFERENCES \`payload_locked_documents\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`pages_id\`) REFERENCES \`pages\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`posts_id\`) REFERENCES \`posts\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`events_id\`) REFERENCES \`events\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`preistraeger_id\`) REFERENCES \`preistraeger\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`media_id\`) REFERENCES \`media\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`categories_id\`) REFERENCES \`categories\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`redirects_id\`) REFERENCES \`redirects\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`forms_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`form_submissions_id\`) REFERENCES \`form_submissions\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`search_id\`) REFERENCES \`search\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`payload_folders_id\`) REFERENCES \`payload_folders\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`INSERT INTO \`__new_payload_locked_documents_rels\`("id", "order", "parent_id", "path", "pages_id", "posts_id", "events_id", "preistraeger_id", "media_id", "categories_id", "users_id", "redirects_id", "forms_id", "form_submissions_id", "search_id", "payload_folders_id") SELECT "id", "order", "parent_id", "path", "pages_id", "posts_id", "events_id", "preistraeger_id", "media_id", "categories_id", "users_id", "redirects_id", "forms_id", "form_submissions_id", "search_id", "payload_folders_id" FROM \`payload_locked_documents_rels\`;`)
|
||||
await db.run(sql`DROP TABLE \`payload_locked_documents_rels\`;`)
|
||||
await db.run(sql`ALTER TABLE \`__new_payload_locked_documents_rels\` RENAME TO \`payload_locked_documents_rels\`;`)
|
||||
await db.run(sql`PRAGMA foreign_keys=ON;`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_order_idx\` ON \`payload_locked_documents_rels\` (\`order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_parent_idx\` ON \`payload_locked_documents_rels\` (\`parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_path_idx\` ON \`payload_locked_documents_rels\` (\`path\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_pages_id_idx\` ON \`payload_locked_documents_rels\` (\`pages_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_posts_id_idx\` ON \`payload_locked_documents_rels\` (\`posts_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_events_id_idx\` ON \`payload_locked_documents_rels\` (\`events_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_preistraeger_id_idx\` ON \`payload_locked_documents_rels\` (\`preistraeger_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_media_id_idx\` ON \`payload_locked_documents_rels\` (\`media_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_categories_id_idx\` ON \`payload_locked_documents_rels\` (\`categories_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_users_id_idx\` ON \`payload_locked_documents_rels\` (\`users_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_redirects_id_idx\` ON \`payload_locked_documents_rels\` (\`redirects_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_forms_id_idx\` ON \`payload_locked_documents_rels\` (\`forms_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_form_submissions_id_idx\` ON \`payload_locked_documents_rels\` (\`form_submissions_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_search_id_idx\` ON \`payload_locked_documents_rels\` (\`search_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_payload_folders_id_idx\` ON \`payload_locked_documents_rels\` (\`payload_folders_id\`);`)
|
||||
}
|
||||
30886
src/migrations/20260630_182219_prune_unused_admin_collections.json
Normal file
30886
src/migrations/20260630_182219_prune_unused_admin_collections.json
Normal file
File diff suppressed because one or more lines are too long
555
src/migrations/20260630_182219_prune_unused_admin_collections.ts
Normal file
555
src/migrations/20260630_182219_prune_unused_admin_collections.ts
Normal file
@@ -0,0 +1,555 @@
|
||||
import { type MigrateUpArgs, type MigrateDownArgs, sql } from '@payloadcms/db-sqlite'
|
||||
|
||||
export async function up({ db, payload: _payload, req: _req }: MigrateUpArgs): Promise<void> {
|
||||
await db.run(sql`PRAGMA foreign_keys=OFF;`)
|
||||
await db.run(sql`DROP TABLE \`pages_blocks_archive\`;`)
|
||||
await db.run(sql`DROP TABLE \`pages_blocks_form_block\`;`)
|
||||
await db.run(sql`DROP TABLE \`_pages_v_blocks_archive\`;`)
|
||||
await db.run(sql`DROP TABLE \`_pages_v_blocks_form_block\`;`)
|
||||
await db.run(sql`DROP TABLE \`categories_breadcrumbs\`;`)
|
||||
await db.run(sql`DROP TABLE \`categories\`;`)
|
||||
await db.run(sql`DROP TABLE \`redirects\`;`)
|
||||
await db.run(sql`DROP TABLE \`redirects_rels\`;`)
|
||||
await db.run(sql`DROP TABLE \`forms_blocks_checkbox\`;`)
|
||||
await db.run(sql`DROP TABLE \`forms_blocks_country\`;`)
|
||||
await db.run(sql`DROP TABLE \`forms_blocks_email\`;`)
|
||||
await db.run(sql`DROP TABLE \`forms_blocks_message\`;`)
|
||||
await db.run(sql`DROP TABLE \`forms_blocks_number\`;`)
|
||||
await db.run(sql`DROP TABLE \`forms_blocks_select_options\`;`)
|
||||
await db.run(sql`DROP TABLE \`forms_blocks_select\`;`)
|
||||
await db.run(sql`DROP TABLE \`forms_blocks_state\`;`)
|
||||
await db.run(sql`DROP TABLE \`forms_blocks_text\`;`)
|
||||
await db.run(sql`DROP TABLE \`forms_blocks_textarea\`;`)
|
||||
await db.run(sql`DROP TABLE \`forms_emails\`;`)
|
||||
await db.run(sql`DROP TABLE \`forms\`;`)
|
||||
await db.run(sql`DROP TABLE \`form_submissions_submission_data\`;`)
|
||||
await db.run(sql`DROP TABLE \`form_submissions\`;`)
|
||||
await db.run(sql`DROP TABLE \`search_categories\`;`)
|
||||
await db.run(sql`DROP TABLE \`search\`;`)
|
||||
await db.run(sql`DROP TABLE \`search_rels\`;`)
|
||||
await db.run(sql`PRAGMA foreign_keys=OFF;`)
|
||||
await db.run(sql`CREATE TABLE \`__new_pages_rels\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`order\` integer,
|
||||
\`parent_id\` integer NOT NULL,
|
||||
\`path\` text NOT NULL,
|
||||
\`pages_id\` integer,
|
||||
\`posts_id\` integer,
|
||||
\`preistraeger_id\` integer,
|
||||
FOREIGN KEY (\`parent_id\`) REFERENCES \`pages\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`pages_id\`) REFERENCES \`pages\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`posts_id\`) REFERENCES \`posts\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`preistraeger_id\`) REFERENCES \`preistraeger\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`INSERT INTO \`__new_pages_rels\`("id", "order", "parent_id", "path", "pages_id", "posts_id", "preistraeger_id") SELECT "id", "order", "parent_id", "path", "pages_id", "posts_id", "preistraeger_id" FROM \`pages_rels\`;`)
|
||||
await db.run(sql`DROP TABLE \`pages_rels\`;`)
|
||||
await db.run(sql`ALTER TABLE \`__new_pages_rels\` RENAME TO \`pages_rels\`;`)
|
||||
await db.run(sql`PRAGMA foreign_keys=ON;`)
|
||||
await db.run(sql`CREATE INDEX \`pages_rels_order_idx\` ON \`pages_rels\` (\`order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`pages_rels_parent_idx\` ON \`pages_rels\` (\`parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`pages_rels_path_idx\` ON \`pages_rels\` (\`path\`);`)
|
||||
await db.run(sql`CREATE INDEX \`pages_rels_pages_id_idx\` ON \`pages_rels\` (\`pages_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`pages_rels_posts_id_idx\` ON \`pages_rels\` (\`posts_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`pages_rels_preistraeger_id_idx\` ON \`pages_rels\` (\`preistraeger_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`__new__pages_v_rels\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`order\` integer,
|
||||
\`parent_id\` integer NOT NULL,
|
||||
\`path\` text NOT NULL,
|
||||
\`pages_id\` integer,
|
||||
\`posts_id\` integer,
|
||||
\`preistraeger_id\` integer,
|
||||
FOREIGN KEY (\`parent_id\`) REFERENCES \`_pages_v\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`pages_id\`) REFERENCES \`pages\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`posts_id\`) REFERENCES \`posts\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`preistraeger_id\`) REFERENCES \`preistraeger\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`INSERT INTO \`__new__pages_v_rels\`("id", "order", "parent_id", "path", "pages_id", "posts_id", "preistraeger_id") SELECT "id", "order", "parent_id", "path", "pages_id", "posts_id", "preistraeger_id" FROM \`_pages_v_rels\`;`)
|
||||
await db.run(sql`DROP TABLE \`_pages_v_rels\`;`)
|
||||
await db.run(sql`ALTER TABLE \`__new__pages_v_rels\` RENAME TO \`_pages_v_rels\`;`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_rels_order_idx\` ON \`_pages_v_rels\` (\`order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_rels_parent_idx\` ON \`_pages_v_rels\` (\`parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_rels_path_idx\` ON \`_pages_v_rels\` (\`path\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_rels_pages_id_idx\` ON \`_pages_v_rels\` (\`pages_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_rels_posts_id_idx\` ON \`_pages_v_rels\` (\`posts_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_rels_preistraeger_id_idx\` ON \`_pages_v_rels\` (\`preistraeger_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`__new_posts_rels\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`order\` integer,
|
||||
\`parent_id\` integer NOT NULL,
|
||||
\`path\` text NOT NULL,
|
||||
\`posts_id\` integer,
|
||||
\`users_id\` integer,
|
||||
FOREIGN KEY (\`parent_id\`) REFERENCES \`posts\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`posts_id\`) REFERENCES \`posts\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`INSERT INTO \`__new_posts_rels\`("id", "order", "parent_id", "path", "posts_id", "users_id") SELECT "id", "order", "parent_id", "path", "posts_id", "users_id" FROM \`posts_rels\`;`)
|
||||
await db.run(sql`DROP TABLE \`posts_rels\`;`)
|
||||
await db.run(sql`ALTER TABLE \`__new_posts_rels\` RENAME TO \`posts_rels\`;`)
|
||||
await db.run(sql`CREATE INDEX \`posts_rels_order_idx\` ON \`posts_rels\` (\`order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`posts_rels_parent_idx\` ON \`posts_rels\` (\`parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`posts_rels_path_idx\` ON \`posts_rels\` (\`path\`);`)
|
||||
await db.run(sql`CREATE INDEX \`posts_rels_posts_id_idx\` ON \`posts_rels\` (\`posts_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`posts_rels_users_id_idx\` ON \`posts_rels\` (\`users_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`__new__posts_v_rels\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`order\` integer,
|
||||
\`parent_id\` integer NOT NULL,
|
||||
\`path\` text NOT NULL,
|
||||
\`posts_id\` integer,
|
||||
\`users_id\` integer,
|
||||
FOREIGN KEY (\`parent_id\`) REFERENCES \`_posts_v\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`posts_id\`) REFERENCES \`posts\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`INSERT INTO \`__new__posts_v_rels\`("id", "order", "parent_id", "path", "posts_id", "users_id") SELECT "id", "order", "parent_id", "path", "posts_id", "users_id" FROM \`_posts_v_rels\`;`)
|
||||
await db.run(sql`DROP TABLE \`_posts_v_rels\`;`)
|
||||
await db.run(sql`ALTER TABLE \`__new__posts_v_rels\` RENAME TO \`_posts_v_rels\`;`)
|
||||
await db.run(sql`CREATE INDEX \`_posts_v_rels_order_idx\` ON \`_posts_v_rels\` (\`order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_posts_v_rels_parent_idx\` ON \`_posts_v_rels\` (\`parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_posts_v_rels_path_idx\` ON \`_posts_v_rels\` (\`path\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_posts_v_rels_posts_id_idx\` ON \`_posts_v_rels\` (\`posts_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_posts_v_rels_users_id_idx\` ON \`_posts_v_rels\` (\`users_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`__new_payload_locked_documents_rels\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`order\` integer,
|
||||
\`parent_id\` integer NOT NULL,
|
||||
\`path\` text NOT NULL,
|
||||
\`pages_id\` integer,
|
||||
\`preistraeger_id\` integer,
|
||||
\`partners_id\` integer,
|
||||
\`posts_id\` integer,
|
||||
\`events_id\` integer,
|
||||
\`media_id\` integer,
|
||||
\`users_id\` integer,
|
||||
\`payload_folders_id\` integer,
|
||||
FOREIGN KEY (\`parent_id\`) REFERENCES \`payload_locked_documents\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`pages_id\`) REFERENCES \`pages\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`preistraeger_id\`) REFERENCES \`preistraeger\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`partners_id\`) REFERENCES \`partners\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`posts_id\`) REFERENCES \`posts\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`events_id\`) REFERENCES \`events\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`media_id\`) REFERENCES \`media\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`payload_folders_id\`) REFERENCES \`payload_folders\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`INSERT INTO \`__new_payload_locked_documents_rels\`("id", "order", "parent_id", "path", "pages_id", "preistraeger_id", "partners_id", "posts_id", "events_id", "media_id", "users_id", "payload_folders_id") SELECT "id", "order", "parent_id", "path", "pages_id", "preistraeger_id", "partners_id", "posts_id", "events_id", "media_id", "users_id", "payload_folders_id" FROM \`payload_locked_documents_rels\`;`)
|
||||
await db.run(sql`DROP TABLE \`payload_locked_documents_rels\`;`)
|
||||
await db.run(sql`ALTER TABLE \`__new_payload_locked_documents_rels\` RENAME TO \`payload_locked_documents_rels\`;`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_order_idx\` ON \`payload_locked_documents_rels\` (\`order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_parent_idx\` ON \`payload_locked_documents_rels\` (\`parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_path_idx\` ON \`payload_locked_documents_rels\` (\`path\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_pages_id_idx\` ON \`payload_locked_documents_rels\` (\`pages_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_preistraeger_id_idx\` ON \`payload_locked_documents_rels\` (\`preistraeger_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_partners_id_idx\` ON \`payload_locked_documents_rels\` (\`partners_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_posts_id_idx\` ON \`payload_locked_documents_rels\` (\`posts_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_events_id_idx\` ON \`payload_locked_documents_rels\` (\`events_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_media_id_idx\` ON \`payload_locked_documents_rels\` (\`media_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_users_id_idx\` ON \`payload_locked_documents_rels\` (\`users_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_payload_folders_id_idx\` ON \`payload_locked_documents_rels\` (\`payload_folders_id\`);`)
|
||||
}
|
||||
|
||||
export async function down({ db, payload: _payload, req: _req }: MigrateDownArgs): Promise<void> {
|
||||
await db.run(sql`CREATE TABLE \`pages_blocks_archive\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`intro_content\` text,
|
||||
\`populate_by\` text DEFAULT 'collection',
|
||||
\`relation_to\` text DEFAULT 'posts',
|
||||
\`limit\` numeric DEFAULT 10,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`pages\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`pages_blocks_archive_order_idx\` ON \`pages_blocks_archive\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`pages_blocks_archive_parent_id_idx\` ON \`pages_blocks_archive\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`pages_blocks_archive_path_idx\` ON \`pages_blocks_archive\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE TABLE \`pages_blocks_form_block\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`form_id\` integer,
|
||||
\`enable_intro\` integer,
|
||||
\`intro_content\` text,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`form_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE set null,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`pages\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`pages_blocks_form_block_order_idx\` ON \`pages_blocks_form_block\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`pages_blocks_form_block_parent_id_idx\` ON \`pages_blocks_form_block\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`pages_blocks_form_block_path_idx\` ON \`pages_blocks_form_block\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE INDEX \`pages_blocks_form_block_form_idx\` ON \`pages_blocks_form_block\` (\`form_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`_pages_v_blocks_archive\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`intro_content\` text,
|
||||
\`populate_by\` text DEFAULT 'collection',
|
||||
\`relation_to\` text DEFAULT 'posts',
|
||||
\`limit\` numeric DEFAULT 10,
|
||||
\`_uuid\` text,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`_pages_v\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_blocks_archive_order_idx\` ON \`_pages_v_blocks_archive\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_blocks_archive_parent_id_idx\` ON \`_pages_v_blocks_archive\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_blocks_archive_path_idx\` ON \`_pages_v_blocks_archive\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE TABLE \`_pages_v_blocks_form_block\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`form_id\` integer,
|
||||
\`enable_intro\` integer,
|
||||
\`intro_content\` text,
|
||||
\`_uuid\` text,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`form_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE set null,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`_pages_v\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_blocks_form_block_order_idx\` ON \`_pages_v_blocks_form_block\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_blocks_form_block_parent_id_idx\` ON \`_pages_v_blocks_form_block\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_blocks_form_block_path_idx\` ON \`_pages_v_blocks_form_block\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_blocks_form_block_form_idx\` ON \`_pages_v_blocks_form_block\` (\`form_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`categories_breadcrumbs\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`doc_id\` integer,
|
||||
\`url\` text,
|
||||
\`label\` text,
|
||||
FOREIGN KEY (\`doc_id\`) REFERENCES \`categories\`(\`id\`) ON UPDATE no action ON DELETE set null,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`categories\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`categories_breadcrumbs_order_idx\` ON \`categories_breadcrumbs\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`categories_breadcrumbs_parent_id_idx\` ON \`categories_breadcrumbs\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`categories_breadcrumbs_doc_idx\` ON \`categories_breadcrumbs\` (\`doc_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`categories\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`title\` text NOT NULL,
|
||||
\`generate_slug\` integer DEFAULT true,
|
||||
\`slug\` text NOT NULL,
|
||||
\`parent_id\` integer,
|
||||
\`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
|
||||
\`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
|
||||
FOREIGN KEY (\`parent_id\`) REFERENCES \`categories\`(\`id\`) ON UPDATE no action ON DELETE set null
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE UNIQUE INDEX \`categories_slug_idx\` ON \`categories\` (\`slug\`);`)
|
||||
await db.run(sql`CREATE INDEX \`categories_parent_idx\` ON \`categories\` (\`parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`categories_updated_at_idx\` ON \`categories\` (\`updated_at\`);`)
|
||||
await db.run(sql`CREATE INDEX \`categories_created_at_idx\` ON \`categories\` (\`created_at\`);`)
|
||||
await db.run(sql`CREATE TABLE \`redirects\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`from\` text NOT NULL,
|
||||
\`to_type\` text DEFAULT 'reference',
|
||||
\`to_url\` text,
|
||||
\`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
|
||||
\`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE UNIQUE INDEX \`redirects_from_idx\` ON \`redirects\` (\`from\`);`)
|
||||
await db.run(sql`CREATE INDEX \`redirects_updated_at_idx\` ON \`redirects\` (\`updated_at\`);`)
|
||||
await db.run(sql`CREATE INDEX \`redirects_created_at_idx\` ON \`redirects\` (\`created_at\`);`)
|
||||
await db.run(sql`CREATE TABLE \`redirects_rels\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`order\` integer,
|
||||
\`parent_id\` integer NOT NULL,
|
||||
\`path\` text NOT NULL,
|
||||
\`pages_id\` integer,
|
||||
\`posts_id\` integer,
|
||||
FOREIGN KEY (\`parent_id\`) REFERENCES \`redirects\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`pages_id\`) REFERENCES \`pages\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`posts_id\`) REFERENCES \`posts\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`redirects_rels_order_idx\` ON \`redirects_rels\` (\`order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`redirects_rels_parent_idx\` ON \`redirects_rels\` (\`parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`redirects_rels_path_idx\` ON \`redirects_rels\` (\`path\`);`)
|
||||
await db.run(sql`CREATE INDEX \`redirects_rels_pages_id_idx\` ON \`redirects_rels\` (\`pages_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`redirects_rels_posts_id_idx\` ON \`redirects_rels\` (\`posts_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`forms_blocks_checkbox\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`name\` text NOT NULL,
|
||||
\`label\` text,
|
||||
\`width\` numeric,
|
||||
\`required\` integer,
|
||||
\`default_value\` integer,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_checkbox_order_idx\` ON \`forms_blocks_checkbox\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_checkbox_parent_id_idx\` ON \`forms_blocks_checkbox\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_checkbox_path_idx\` ON \`forms_blocks_checkbox\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE TABLE \`forms_blocks_country\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`name\` text NOT NULL,
|
||||
\`label\` text,
|
||||
\`width\` numeric,
|
||||
\`required\` integer,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_country_order_idx\` ON \`forms_blocks_country\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_country_parent_id_idx\` ON \`forms_blocks_country\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_country_path_idx\` ON \`forms_blocks_country\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE TABLE \`forms_blocks_email\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`name\` text NOT NULL,
|
||||
\`label\` text,
|
||||
\`width\` numeric,
|
||||
\`required\` integer,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_email_order_idx\` ON \`forms_blocks_email\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_email_parent_id_idx\` ON \`forms_blocks_email\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_email_path_idx\` ON \`forms_blocks_email\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE TABLE \`forms_blocks_message\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`message\` text,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_message_order_idx\` ON \`forms_blocks_message\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_message_parent_id_idx\` ON \`forms_blocks_message\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_message_path_idx\` ON \`forms_blocks_message\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE TABLE \`forms_blocks_number\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`name\` text NOT NULL,
|
||||
\`label\` text,
|
||||
\`width\` numeric,
|
||||
\`default_value\` numeric,
|
||||
\`required\` integer,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_number_order_idx\` ON \`forms_blocks_number\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_number_parent_id_idx\` ON \`forms_blocks_number\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_number_path_idx\` ON \`forms_blocks_number\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE TABLE \`forms_blocks_select_options\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` text NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`label\` text NOT NULL,
|
||||
\`value\` text NOT NULL,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`forms_blocks_select\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_select_options_order_idx\` ON \`forms_blocks_select_options\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_select_options_parent_id_idx\` ON \`forms_blocks_select_options\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`forms_blocks_select\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`name\` text NOT NULL,
|
||||
\`label\` text,
|
||||
\`width\` numeric,
|
||||
\`default_value\` text,
|
||||
\`placeholder\` text,
|
||||
\`required\` integer,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_select_order_idx\` ON \`forms_blocks_select\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_select_parent_id_idx\` ON \`forms_blocks_select\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_select_path_idx\` ON \`forms_blocks_select\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE TABLE \`forms_blocks_state\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`name\` text NOT NULL,
|
||||
\`label\` text,
|
||||
\`width\` numeric,
|
||||
\`required\` integer,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_state_order_idx\` ON \`forms_blocks_state\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_state_parent_id_idx\` ON \`forms_blocks_state\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_state_path_idx\` ON \`forms_blocks_state\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE TABLE \`forms_blocks_text\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`name\` text NOT NULL,
|
||||
\`label\` text,
|
||||
\`width\` numeric,
|
||||
\`default_value\` text,
|
||||
\`required\` integer,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_text_order_idx\` ON \`forms_blocks_text\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_text_parent_id_idx\` ON \`forms_blocks_text\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_text_path_idx\` ON \`forms_blocks_text\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE TABLE \`forms_blocks_textarea\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`_path\` text NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`name\` text NOT NULL,
|
||||
\`label\` text,
|
||||
\`width\` numeric,
|
||||
\`default_value\` text,
|
||||
\`required\` integer,
|
||||
\`block_name\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_textarea_order_idx\` ON \`forms_blocks_textarea\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_textarea_parent_id_idx\` ON \`forms_blocks_textarea\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_blocks_textarea_path_idx\` ON \`forms_blocks_textarea\` (\`_path\`);`)
|
||||
await db.run(sql`CREATE TABLE \`forms_emails\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`email_to\` text,
|
||||
\`cc\` text,
|
||||
\`bcc\` text,
|
||||
\`reply_to\` text,
|
||||
\`email_from\` text,
|
||||
\`subject\` text DEFAULT 'You''ve received a new message.' NOT NULL,
|
||||
\`message\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`forms_emails_order_idx\` ON \`forms_emails\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_emails_parent_id_idx\` ON \`forms_emails\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`forms\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`title\` text NOT NULL,
|
||||
\`submit_button_label\` text,
|
||||
\`confirmation_type\` text DEFAULT 'message',
|
||||
\`confirmation_message\` text,
|
||||
\`redirect_url\` text,
|
||||
\`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
|
||||
\`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`forms_updated_at_idx\` ON \`forms\` (\`updated_at\`);`)
|
||||
await db.run(sql`CREATE INDEX \`forms_created_at_idx\` ON \`forms\` (\`created_at\`);`)
|
||||
await db.run(sql`CREATE TABLE \`form_submissions_submission_data\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`field\` text NOT NULL,
|
||||
\`value\` text NOT NULL,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`form_submissions\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`form_submissions_submission_data_order_idx\` ON \`form_submissions_submission_data\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`form_submissions_submission_data_parent_id_idx\` ON \`form_submissions_submission_data\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`form_submissions\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`form_id\` integer NOT NULL,
|
||||
\`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
|
||||
\`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
|
||||
FOREIGN KEY (\`form_id\`) REFERENCES \`forms\`(\`id\`) ON UPDATE no action ON DELETE set null
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`form_submissions_form_idx\` ON \`form_submissions\` (\`form_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`form_submissions_updated_at_idx\` ON \`form_submissions\` (\`updated_at\`);`)
|
||||
await db.run(sql`CREATE INDEX \`form_submissions_created_at_idx\` ON \`form_submissions\` (\`created_at\`);`)
|
||||
await db.run(sql`CREATE TABLE \`search_categories\` (
|
||||
\`_order\` integer NOT NULL,
|
||||
\`_parent_id\` integer NOT NULL,
|
||||
\`id\` text PRIMARY KEY NOT NULL,
|
||||
\`relation_to\` text,
|
||||
\`category_i_d\` text,
|
||||
\`title\` text,
|
||||
FOREIGN KEY (\`_parent_id\`) REFERENCES \`search\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`search_categories_order_idx\` ON \`search_categories\` (\`_order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`search_categories_parent_id_idx\` ON \`search_categories\` (\`_parent_id\`);`)
|
||||
await db.run(sql`CREATE TABLE \`search\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`title\` text,
|
||||
\`priority\` numeric,
|
||||
\`slug\` text,
|
||||
\`meta_title\` text,
|
||||
\`meta_description\` text,
|
||||
\`meta_image_id\` integer,
|
||||
\`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
|
||||
\`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
|
||||
FOREIGN KEY (\`meta_image_id\`) REFERENCES \`media\`(\`id\`) ON UPDATE no action ON DELETE set null
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`search_slug_idx\` ON \`search\` (\`slug\`);`)
|
||||
await db.run(sql`CREATE INDEX \`search_meta_meta_image_idx\` ON \`search\` (\`meta_image_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`search_updated_at_idx\` ON \`search\` (\`updated_at\`);`)
|
||||
await db.run(sql`CREATE INDEX \`search_created_at_idx\` ON \`search\` (\`created_at\`);`)
|
||||
await db.run(sql`CREATE TABLE \`search_rels\` (
|
||||
\`id\` integer PRIMARY KEY NOT NULL,
|
||||
\`order\` integer,
|
||||
\`parent_id\` integer NOT NULL,
|
||||
\`path\` text NOT NULL,
|
||||
\`posts_id\` integer,
|
||||
FOREIGN KEY (\`parent_id\`) REFERENCES \`search\`(\`id\`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (\`posts_id\`) REFERENCES \`posts\`(\`id\`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
`)
|
||||
await db.run(sql`CREATE INDEX \`search_rels_order_idx\` ON \`search_rels\` (\`order\`);`)
|
||||
await db.run(sql`CREATE INDEX \`search_rels_parent_idx\` ON \`search_rels\` (\`parent_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`search_rels_path_idx\` ON \`search_rels\` (\`path\`);`)
|
||||
await db.run(sql`CREATE INDEX \`search_rels_posts_id_idx\` ON \`search_rels\` (\`posts_id\`);`)
|
||||
await db.run(sql`ALTER TABLE \`pages_rels\` ADD \`categories_id\` integer REFERENCES categories(id);`)
|
||||
await db.run(sql`CREATE INDEX \`pages_rels_categories_id_idx\` ON \`pages_rels\` (\`categories_id\`);`)
|
||||
await db.run(sql`ALTER TABLE \`_pages_v_rels\` ADD \`categories_id\` integer REFERENCES categories(id);`)
|
||||
await db.run(sql`CREATE INDEX \`_pages_v_rels_categories_id_idx\` ON \`_pages_v_rels\` (\`categories_id\`);`)
|
||||
await db.run(sql`ALTER TABLE \`posts_rels\` ADD \`categories_id\` integer REFERENCES categories(id);`)
|
||||
await db.run(sql`CREATE INDEX \`posts_rels_categories_id_idx\` ON \`posts_rels\` (\`categories_id\`);`)
|
||||
await db.run(sql`ALTER TABLE \`_posts_v_rels\` ADD \`categories_id\` integer REFERENCES categories(id);`)
|
||||
await db.run(sql`CREATE INDEX \`_posts_v_rels_categories_id_idx\` ON \`_posts_v_rels\` (\`categories_id\`);`)
|
||||
await db.run(sql`ALTER TABLE \`payload_locked_documents_rels\` ADD \`categories_id\` integer REFERENCES categories(id);`)
|
||||
await db.run(sql`ALTER TABLE \`payload_locked_documents_rels\` ADD \`redirects_id\` integer REFERENCES redirects(id);`)
|
||||
await db.run(sql`ALTER TABLE \`payload_locked_documents_rels\` ADD \`forms_id\` integer REFERENCES forms(id);`)
|
||||
await db.run(sql`ALTER TABLE \`payload_locked_documents_rels\` ADD \`form_submissions_id\` integer REFERENCES form_submissions(id);`)
|
||||
await db.run(sql`ALTER TABLE \`payload_locked_documents_rels\` ADD \`search_id\` integer REFERENCES search(id);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_categories_id_idx\` ON \`payload_locked_documents_rels\` (\`categories_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_redirects_id_idx\` ON \`payload_locked_documents_rels\` (\`redirects_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_forms_id_idx\` ON \`payload_locked_documents_rels\` (\`forms_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_form_submissions_id_idx\` ON \`payload_locked_documents_rels\` (\`form_submissions_id\`);`)
|
||||
await db.run(sql`CREATE INDEX \`payload_locked_documents_rels_search_id_idx\` ON \`payload_locked_documents_rels\` (\`search_id\`);`)
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
import * as migration_20260630_133242 from './20260630_133242';
|
||||
import * as migration_20260630_165002_participation_awards_grid from './20260630_165002_participation_awards_grid';
|
||||
import * as migration_20260630_172754_network_partner_logo_uploads from './20260630_172754_network_partner_logo_uploads';
|
||||
import * as migration_20260630_175614_partners_collection from './20260630_175614_partners_collection';
|
||||
import * as migration_20260630_182219_prune_unused_admin_collections from './20260630_182219_prune_unused_admin_collections';
|
||||
|
||||
export const migrations = [
|
||||
{
|
||||
@@ -10,6 +13,21 @@ export const migrations = [
|
||||
{
|
||||
up: migration_20260630_165002_participation_awards_grid.up,
|
||||
down: migration_20260630_165002_participation_awards_grid.down,
|
||||
name: '20260630_165002_participation_awards_grid'
|
||||
name: '20260630_165002_participation_awards_grid',
|
||||
},
|
||||
{
|
||||
up: migration_20260630_172754_network_partner_logo_uploads.up,
|
||||
down: migration_20260630_172754_network_partner_logo_uploads.down,
|
||||
name: '20260630_172754_network_partner_logo_uploads',
|
||||
},
|
||||
{
|
||||
up: migration_20260630_175614_partners_collection.up,
|
||||
down: migration_20260630_175614_partners_collection.down,
|
||||
name: '20260630_175614_partners_collection',
|
||||
},
|
||||
{
|
||||
up: migration_20260630_182219_prune_unused_admin_collections.up,
|
||||
down: migration_20260630_182219_prune_unused_admin_collections.down,
|
||||
name: '20260630_182219_prune_unused_admin_collections',
|
||||
},
|
||||
];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,10 +4,10 @@ import path from 'path'
|
||||
import { buildConfig, PayloadRequest } from 'payload'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import { Categories } from './collections/Categories'
|
||||
import { Events } from './collections/Events'
|
||||
import { Media } from './collections/Media'
|
||||
import { Pages } from './collections/Pages'
|
||||
import { Partners } from './collections/Partners'
|
||||
import { Posts } from './collections/Posts'
|
||||
import { Preistraeger } from './collections/Preistraeger'
|
||||
import { Users } from './collections/Users'
|
||||
@@ -66,7 +66,7 @@ export default buildConfig({
|
||||
url: process.env.DATABASE_URL || '',
|
||||
},
|
||||
}),
|
||||
collections: [Pages, Posts, Events, Preistraeger, Media, Categories, Users],
|
||||
collections: [Pages, Preistraeger, Partners, Posts, Events, Media, Users],
|
||||
cors: [getServerSideURL()].filter(Boolean),
|
||||
globals: [Header, Footer, SiteSettings, ApplicationPhase],
|
||||
plugins,
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
import { formBuilderPlugin } from '@payloadcms/plugin-form-builder'
|
||||
import { nestedDocsPlugin } from '@payloadcms/plugin-nested-docs'
|
||||
import { redirectsPlugin } from '@payloadcms/plugin-redirects'
|
||||
import { seoPlugin } from '@payloadcms/plugin-seo'
|
||||
import { searchPlugin } from '@payloadcms/plugin-search'
|
||||
import { Plugin } from 'payload'
|
||||
import { revalidateRedirects } from '@/hooks/revalidateRedirects'
|
||||
import { GenerateTitle, GenerateURL } from '@payloadcms/plugin-seo/types'
|
||||
import { FixedToolbarFeature, HeadingFeature, lexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
import { searchFields } from '@/search/fieldOverrides'
|
||||
import { beforeSyncWithSearch } from '@/search/beforeSync'
|
||||
|
||||
import { Page, Post } from '@/payload-types'
|
||||
import { getServerSideURL } from '@/utilities/getURL'
|
||||
|
||||
const siteName = 'Bayerischer Mittelstandspreis'
|
||||
|
||||
const generateTitle: GenerateTitle<Post | Page> = ({ doc }) => {
|
||||
return doc?.title ? `${doc.title} | Payload Website Template` : 'Payload Website Template'
|
||||
return doc?.title ? `${doc.title} | ${siteName}` : siteName
|
||||
}
|
||||
|
||||
const generateURL: GenerateURL<Post | Page> = ({ doc }) => {
|
||||
@@ -24,69 +18,8 @@ const generateURL: GenerateURL<Post | Page> = ({ doc }) => {
|
||||
}
|
||||
|
||||
export const plugins: Plugin[] = [
|
||||
redirectsPlugin({
|
||||
collections: ['pages', 'posts'],
|
||||
overrides: {
|
||||
// @ts-expect-error - This is a valid override, mapped fields don't resolve to the same type
|
||||
fields: ({ defaultFields }) => {
|
||||
return defaultFields.map((field) => {
|
||||
if ('name' in field && field.name === 'from') {
|
||||
return {
|
||||
...field,
|
||||
admin: {
|
||||
description: 'You will need to rebuild the website when changing this field.',
|
||||
},
|
||||
}
|
||||
}
|
||||
return field
|
||||
})
|
||||
},
|
||||
hooks: {
|
||||
afterChange: [revalidateRedirects],
|
||||
},
|
||||
},
|
||||
}),
|
||||
nestedDocsPlugin({
|
||||
collections: ['categories'],
|
||||
generateURL: (docs) => docs.reduce((url, doc) => `${url}/${doc.slug}`, ''),
|
||||
}),
|
||||
seoPlugin({
|
||||
generateTitle,
|
||||
generateURL,
|
||||
}),
|
||||
formBuilderPlugin({
|
||||
fields: {
|
||||
payment: false,
|
||||
},
|
||||
formOverrides: {
|
||||
fields: ({ defaultFields }) => {
|
||||
return defaultFields.map((field) => {
|
||||
if ('name' in field && field.name === 'confirmationMessage') {
|
||||
return {
|
||||
...field,
|
||||
editor: lexicalEditor({
|
||||
features: ({ rootFeatures }) => {
|
||||
return [
|
||||
...rootFeatures,
|
||||
FixedToolbarFeature(),
|
||||
HeadingFeature({ enabledHeadingSizes: ['h1', 'h2', 'h3', 'h4'] }),
|
||||
]
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
return field
|
||||
})
|
||||
},
|
||||
},
|
||||
}),
|
||||
searchPlugin({
|
||||
collections: ['posts'],
|
||||
beforeSync: beforeSyncWithSearch,
|
||||
searchOverrides: {
|
||||
fields: ({ defaultFields }) => {
|
||||
return [...defaultFields, ...searchFields]
|
||||
},
|
||||
},
|
||||
}),
|
||||
]
|
||||
|
||||
@@ -125,7 +125,6 @@ function postData(page: SpaPageRegistryEntry, mediaMap: MediaMap) {
|
||||
`Dieser Presseartikel wird aktuell noch von der migrierten SPA gerendert. Über „Preview“ kann der aktuelle Stand unter ${page.path} betrachtet werden.`,
|
||||
),
|
||||
relatedPosts: [],
|
||||
categories: [],
|
||||
authors: [],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,11 +30,52 @@ const itemsWithImageUploads = async <T extends { image?: string }>(payload: Payl
|
||||
}),
|
||||
)
|
||||
|
||||
const partnersForPayload = netzwerkContent.partners.items.map(({ id, ...partner }) => ({
|
||||
const partnersForPayload = netzwerkContent.partners.items.map(({ id, ...partner }, index) => ({
|
||||
...partner,
|
||||
stableId: id,
|
||||
active: true,
|
||||
showOnHomepage: true,
|
||||
sortOrder: index,
|
||||
_status: 'published' as const,
|
||||
}))
|
||||
|
||||
async function upsertPartners(payload: Payload) {
|
||||
await Promise.all(
|
||||
partnersForPayload.map(async (partner) => {
|
||||
const existing = await payload.find({
|
||||
collection: 'partners',
|
||||
limit: 1,
|
||||
pagination: false,
|
||||
draft: true,
|
||||
overrideAccess: true,
|
||||
where: {
|
||||
stableId: { equals: partner.stableId },
|
||||
},
|
||||
})
|
||||
|
||||
const doc = existing.docs[0]
|
||||
|
||||
if (doc) {
|
||||
await payload.update({
|
||||
collection: 'partners',
|
||||
id: doc.id,
|
||||
overrideAccess: true,
|
||||
context: { disableRevalidate: true },
|
||||
data: partner as never,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
await payload.create({
|
||||
collection: 'partners',
|
||||
overrideAccess: true,
|
||||
context: { disableRevalidate: true },
|
||||
data: partner as never,
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const payload = await getPayload({ config })
|
||||
|
||||
@@ -56,6 +97,7 @@ async function main() {
|
||||
const sponsoringImage = await mediaByFilename(payload, netzwerkContent.sponsoring.imageFilename)
|
||||
const { imageFilename: _heroFilename, ...heroContent } = netzwerkContent.hero
|
||||
const { imageFilename: _sponsoringFilename, ...sponsoringContent } = netzwerkContent.sponsoring
|
||||
const { items: _partnerItems, ...partnerSectionContent } = netzwerkContent.partners
|
||||
const [patronPeople, juryMembers] = await Promise.all([
|
||||
itemsWithImageUploads(payload, netzwerkContent.patronage.people),
|
||||
itemsWithImageUploads(payload, netzwerkContent.jury.members),
|
||||
@@ -86,13 +128,14 @@ async function main() {
|
||||
image: sponsoringImage,
|
||||
},
|
||||
partners: {
|
||||
...netzwerkContent.partners,
|
||||
items: partnersForPayload,
|
||||
...partnerSectionContent,
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
})
|
||||
|
||||
await upsertPartners(payload)
|
||||
|
||||
payload.logger.info(`Preloaded Netzwerk CMS fields for page ${page.id}`)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
@@ -132,7 +132,6 @@ async function upsertAwardPosts(payload: Payload, mediaIds: Map<string, string |
|
||||
content: emptyRichText(articleBody),
|
||||
publishedAt: existing?.publishedAt || publishedAt,
|
||||
relatedPosts: [],
|
||||
categories: [],
|
||||
authors: [],
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
'use client'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { useDebounce } from '@/utilities/useDebounce'
|
||||
import { useRouter } from 'next/navigation'
|
||||
|
||||
export const Search: React.FC = () => {
|
||||
const [value, setValue] = useState('')
|
||||
const router = useRouter()
|
||||
|
||||
const debouncedValue = useDebounce(value)
|
||||
|
||||
useEffect(() => {
|
||||
router.push(`/search${debouncedValue ? `?q=${debouncedValue}` : ''}`)
|
||||
}, [debouncedValue, router])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault()
|
||||
}}
|
||||
>
|
||||
<Label htmlFor="search" className="sr-only">
|
||||
Search
|
||||
</Label>
|
||||
<Input
|
||||
id="search"
|
||||
onChange={(event) => {
|
||||
setValue(event.target.value)
|
||||
}}
|
||||
placeholder="Search"
|
||||
/>
|
||||
<button type="submit" className="sr-only">
|
||||
submit
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import { BeforeSync, DocToSync } from '@payloadcms/plugin-search/types'
|
||||
|
||||
export const beforeSyncWithSearch: BeforeSync = async ({ req, originalDoc, searchDoc }) => {
|
||||
const {
|
||||
doc: { relationTo: collection },
|
||||
} = searchDoc
|
||||
|
||||
const { slug, id, categories, title, meta } = originalDoc
|
||||
|
||||
const modifiedDoc: DocToSync = {
|
||||
...searchDoc,
|
||||
slug,
|
||||
meta: {
|
||||
...meta,
|
||||
title: meta?.title || title,
|
||||
image: meta?.image?.id || meta?.image,
|
||||
description: meta?.description,
|
||||
},
|
||||
categories: [],
|
||||
}
|
||||
|
||||
if (categories && Array.isArray(categories) && categories.length > 0) {
|
||||
const populatedCategories: { id: string | number; title: string }[] = []
|
||||
for (const category of categories) {
|
||||
if (!category) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (typeof category === 'object') {
|
||||
populatedCategories.push(category)
|
||||
continue
|
||||
}
|
||||
|
||||
const doc = await req.payload.findByID({
|
||||
collection: 'categories',
|
||||
id: category,
|
||||
disableErrors: true,
|
||||
depth: 0,
|
||||
select: { title: true },
|
||||
req,
|
||||
})
|
||||
|
||||
if (doc !== null) {
|
||||
populatedCategories.push(doc)
|
||||
} else {
|
||||
console.error(
|
||||
`Failed. Category not found when syncing collection '${collection}' with id: '${id}' to search.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
modifiedDoc.categories = populatedCategories.map((each) => ({
|
||||
relationTo: 'categories',
|
||||
categoryID: String(each.id),
|
||||
title: each.title,
|
||||
}))
|
||||
}
|
||||
|
||||
return modifiedDoc
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
import { Field } from 'payload'
|
||||
|
||||
export const searchFields: Field[] = [
|
||||
{
|
||||
name: 'slug',
|
||||
type: 'text',
|
||||
index: true,
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'meta',
|
||||
label: 'Meta',
|
||||
type: 'group',
|
||||
index: true,
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'title',
|
||||
label: 'Title',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'description',
|
||||
label: 'Description',
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
label: 'Image',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Categories',
|
||||
name: 'categories',
|
||||
type: 'array',
|
||||
admin: {
|
||||
readOnly: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'relationTo',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'categoryID',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
@@ -5,7 +5,7 @@ import React, { createContext, useContext } from 'react'
|
||||
import type { SpaApplicationPhaseData } from '@/spa/applicationPhase'
|
||||
import type { SpaSiteSettingsData } from '@/spa/siteSettings'
|
||||
|
||||
export type CmsRouteCollection = 'pages' | 'posts' | 'events' | 'preistraeger'
|
||||
export type CmsRouteCollection = 'pages' | 'posts' | 'events' | 'preistraeger' | 'partners'
|
||||
|
||||
export type CmsRouteDoc = {
|
||||
id: number | string
|
||||
|
||||
155
src/spa/components/ui/partner-logo.tsx
Normal file
155
src/spa/components/ui/partner-logo.tsx
Normal file
@@ -0,0 +1,155 @@
|
||||
import React from 'react'
|
||||
|
||||
import { mediaAlt, mediaUrl } from '@/spa/cmsMediaField'
|
||||
import Image from '@/spa/components/ui/UnoptimizedImage'
|
||||
|
||||
const FF = '"IBM Plex Sans", sans-serif'
|
||||
const FB = '"Inter", sans-serif'
|
||||
|
||||
export type PartnerLogoData = {
|
||||
id?: string | number | null
|
||||
stableId?: string | null
|
||||
name?: string | null
|
||||
logo?: unknown
|
||||
logoAlt?: string | null
|
||||
logoKind?: 'text' | 'serif' | 'badge' | 'monogram' | 'dot' | 'leaf' | 'rsm' | 'deutschebank' | null
|
||||
logoText?: string | null
|
||||
logoSubtext?: string | null
|
||||
logoColor?: string | null
|
||||
sortOrder?: number | null
|
||||
active?: boolean | null
|
||||
showOnHomepage?: boolean | null
|
||||
}
|
||||
|
||||
const fallbackText = (value: unknown, fallback: string) =>
|
||||
typeof value === 'string' && value.length > 0 ? value : fallback
|
||||
|
||||
const logoShellStyle: React.CSSProperties = {
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
height: '100%',
|
||||
justifyContent: 'center',
|
||||
maxHeight: '100%',
|
||||
minWidth: 0,
|
||||
width: '100%',
|
||||
}
|
||||
|
||||
const containedTextStyle: React.CSSProperties = {
|
||||
minWidth: 0,
|
||||
whiteSpace: 'nowrap',
|
||||
}
|
||||
|
||||
const fittedTextSize = (text: string, preferred: number, compact = 12) => {
|
||||
if (text.length > 18) return compact - 1
|
||||
if (text.length > 13) return compact
|
||||
if (text.length > 9) return Math.max(compact + 1, preferred - 3)
|
||||
return preferred
|
||||
}
|
||||
|
||||
export function PartnerLogoMark({
|
||||
partner,
|
||||
defaultLogoColor = '#111D55',
|
||||
}: {
|
||||
partner: PartnerLogoData
|
||||
defaultLogoColor?: string
|
||||
}) {
|
||||
const realLogo = mediaUrl(partner.logo, '')
|
||||
const alt = mediaAlt(partner.logo, fallbackText(partner.logoAlt, fallbackText(partner.name, 'Partner logo')))
|
||||
|
||||
if (realLogo) {
|
||||
return (
|
||||
<span style={logoShellStyle}>
|
||||
<Image
|
||||
unoptimized
|
||||
src={realLogo}
|
||||
alt={alt}
|
||||
style={{ display: 'block', maxWidth: '100%', maxHeight: '100%', width: 'auto', height: 'auto', objectFit: 'contain' }}
|
||||
/>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
const color = fallbackText(partner.logoColor, defaultLogoColor)
|
||||
const text = fallbackText(partner.logoText, fallbackText(partner.name, 'Partner'))
|
||||
const subtext = fallbackText(partner.logoSubtext, '')
|
||||
const textSize = fittedTextSize(text, partner.logoKind === 'serif' ? 21 : 16)
|
||||
|
||||
if (partner.logoKind === 'badge') {
|
||||
return (
|
||||
<span style={logoShellStyle}>
|
||||
<span style={{ background: color, color: '#fff', fontWeight: 900, fontSize: 14, padding: '4px 10px', lineHeight: 1.25, display: 'inline-block', textAlign: 'center', fontFamily: FF }}>
|
||||
{text.split('\n').map((line, index) => (
|
||||
<React.Fragment key={`${line}-${index}`}>{index > 0 && <br />}{line}</React.Fragment>
|
||||
))}
|
||||
</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'monogram') {
|
||||
return (
|
||||
<span style={logoShellStyle}>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 }}>
|
||||
<span style={{ width: 22, height: 22, background: '#3a3a3a', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 900, fontSize: 11, fontFamily: FF, flexShrink: 0 }}>{subtext || text.slice(0, 2)}</span>
|
||||
<span style={{ ...containedTextStyle, fontWeight: 700, fontSize: fittedTextSize(text, 15, 11), color, fontFamily: FF }}>{text}</span>
|
||||
</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'dot') {
|
||||
return (
|
||||
<span style={logoShellStyle}>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 }}>
|
||||
<span style={{ width: 20, height: 20, borderRadius: '50%', background: color, display: 'block', flexShrink: 0 }} />
|
||||
<span style={{ ...containedTextStyle, fontWeight: 700, fontSize: fittedTextSize(text, 16, 11), color, fontFamily: FF }}>{text}</span>
|
||||
</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'leaf') {
|
||||
return (
|
||||
<span style={logoShellStyle}>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 }}>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" aria-hidden="true" style={{ flexShrink: 0 }}><circle cx="10" cy="10" r="9" fill={color} /><path d="M10 3 Q14 7 14 10 Q14 14 10 17 Q6 14 6 10 Q6 7 10 3Z" fill="white" opacity="0.8" /></svg>
|
||||
<span style={{ ...containedTextStyle, fontWeight: 700, fontSize: fittedTextSize(text, 15, 11), color, fontFamily: FB }}>{text}</span>
|
||||
</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'rsm') {
|
||||
return (
|
||||
<span style={logoShellStyle}>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 }}>
|
||||
<span style={{ display: 'flex', gap: 2, flexShrink: 0 }}>
|
||||
<span style={{ width: 10, height: 10, background: '#6b7280', display: 'block' }} />
|
||||
<span style={{ width: 10, height: 10, background: '#22c55e', display: 'block' }} />
|
||||
<span style={{ width: 10, height: 10, background: '#3b82f6', display: 'block' }} />
|
||||
</span>
|
||||
<span style={{ ...containedTextStyle, fontWeight: 900, fontSize: 15, letterSpacing: 0, color, fontFamily: FF }}>{text} {subtext && <span style={{ color: '#6b7280', fontWeight: 600 }}>{subtext}</span>}</span>
|
||||
</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'deutschebank') {
|
||||
return (
|
||||
<span style={logoShellStyle}>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" aria-hidden="true" style={{ flexShrink: 0 }}><rect x="1" y="1" width="18" height="18" fill="none" stroke={color} strokeWidth="1.5" /><line x1="5" y1="15" x2="15" y2="5" stroke={color} strokeWidth="2" /></svg>
|
||||
<span style={{ ...containedTextStyle, fontWeight: 600, fontSize: fittedTextSize(text, 15, 11), color, fontFamily: FB }}>{text}</span>
|
||||
</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<span style={logoShellStyle}>
|
||||
<span style={{ ...containedTextStyle, fontWeight: 900, fontSize: textSize, letterSpacing: partner.logoKind === 'serif' ? '0.08em' : 0, color, fontFamily: partner.logoKind === 'serif' ? 'Georgia, serif' : FF }}>
|
||||
{text}
|
||||
</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
@@ -30,9 +30,8 @@ export function PartnerTicker({ logos }: PartnerTickerProps) {
|
||||
padding: '0 24px',
|
||||
color: '#fff',
|
||||
fontFamily: '"IBM Plex Sans", sans-serif',
|
||||
textTransform: 'uppercase',
|
||||
whiteSpace: 'nowrap',
|
||||
width: 140,
|
||||
width: 260,
|
||||
flexShrink: 0,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
|
||||
@@ -13,6 +13,8 @@ import type { SpaApplicationPhaseData, SpaApplicationPhaseItem } from '@/spa/app
|
||||
import { useApplicationPhase, useCmsCollection, useCmsRoute } from '@/spa/cmsRoute'
|
||||
import { mediaAlt, mediaUrl } from '@/spa/cmsMediaField'
|
||||
import { homeContent } from '@/spa/homeContent'
|
||||
import { netzwerkContent } from '@/spa/netzwerkContent'
|
||||
import { PartnerLogoMark, type PartnerLogoData } from '@/spa/components/ui/partner-logo'
|
||||
|
||||
const FF = '"IBM Plex Sans", sans-serif';
|
||||
|
||||
@@ -84,6 +86,9 @@ type HomeCms = {
|
||||
videoModal?: HomeVideoModalCms;
|
||||
winners?: HomeSectionCms;
|
||||
};
|
||||
type NetzwerkPartnersCms = {
|
||||
defaultLogoColor?: string | null;
|
||||
};
|
||||
type RenderedStatusPhase = Omit<SpaApplicationPhaseItem, 'accent' | 'bg' | 'cta' | 'membershipCta'> & {
|
||||
accent: string;
|
||||
bg: string;
|
||||
@@ -121,16 +126,39 @@ function Lines({ text }: { text: string }) {
|
||||
return <>{text.split('\n').map((line, i) => <React.Fragment key={`${line}-${i}`}>{i > 0 && <br />}{line}</React.Fragment>)}</>;
|
||||
}
|
||||
|
||||
function partnerLogos(partners: unknown) {
|
||||
return fallbackArray(partners, homeContent.hero.partners).map((partner) => {
|
||||
const item = partner as { id?: string; name?: string; label?: React.ReactNode };
|
||||
return item.label
|
||||
? { id: item.id || String(item.name || ''), label: item.label }
|
||||
: {
|
||||
id: item.id || String(item.name || ''),
|
||||
label: <span style={{ fontWeight: 700, fontSize: 10, letterSpacing: 1.5 }}>{item.name}</span>,
|
||||
};
|
||||
});
|
||||
const isNetzwerkPage = (page: CmsRecord) =>
|
||||
page.spaPath === '/netzwerk' || page.slug === 'netzwerk' || page.slug === 'network'
|
||||
|
||||
function partnerLogos(partners: PartnerLogoData[], defaultLogoColor: string) {
|
||||
return partners.map((partner, index) => ({
|
||||
id: String(partner.stableId || partner.id || partner.name || index),
|
||||
label: (
|
||||
<span
|
||||
aria-label={fallbackText(partner.name, 'Partner')}
|
||||
style={{
|
||||
width: 224,
|
||||
height: 54,
|
||||
padding: '9px 18px',
|
||||
background: 'rgba(255,255,255,0.92)',
|
||||
border: '1px solid rgba(255,255,255,0.18)',
|
||||
borderRadius: 6,
|
||||
boxShadow: '0 8px 24px rgba(0,0,0,0.12)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<PartnerLogoMark partner={partner} defaultLogoColor={defaultLogoColor} />
|
||||
</span>
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
function sortedPartners<T extends PartnerLogoData>(partners: T[]) {
|
||||
return partners
|
||||
.map((partner, index) => ({ partner, index }))
|
||||
.sort((a, b) => Number(a.partner.sortOrder ?? a.index) - Number(b.partner.sortOrder ?? b.index))
|
||||
.map(({ partner }) => partner);
|
||||
}
|
||||
|
||||
function HomeWinnerCard({
|
||||
@@ -187,6 +215,20 @@ const Home: React.FC = () => {
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const isMobile = useIsMobile();
|
||||
const home = (useCmsRoute()?.doc?.home || {}) as HomeCms;
|
||||
const netzwerkPage = useCmsCollection('pages').find((page) => isNetzwerkPage(page as CmsRecord)) as
|
||||
| ({ netzwerk?: { partners?: NetzwerkPartnersCms } } & CmsRecord)
|
||||
| undefined;
|
||||
const partnerSection = netzwerkPage?.netzwerk?.partners;
|
||||
const defaultLogoColor = fallbackText(partnerSection?.defaultLogoColor, netzwerkContent.partners.defaultLogoColor);
|
||||
const cmsPartners = useCmsCollection('partners') as PartnerLogoData[];
|
||||
const partnerSource = cmsPartners.length ? cmsPartners : (netzwerkContent.partners.items as PartnerLogoData[]);
|
||||
const networkPartners = sortedPartners(partnerSource)
|
||||
.filter((partner) => partner.active !== false && partner.showOnHomepage !== false)
|
||||
.map((partner) => ({
|
||||
...partner,
|
||||
id: partner.stableId || partner.id,
|
||||
logoColor: fallbackText(partner.logoColor, defaultLogoColor),
|
||||
}));
|
||||
const hero = home.hero || {};
|
||||
const quickCheck = home.quickCheck || {};
|
||||
const intro = home.intro || {};
|
||||
@@ -301,11 +343,11 @@ const Home: React.FC = () => {
|
||||
<div className="px-8 py-5 flex items-center justify-between opacity-60 hover:opacity-100 transition-opacity duration-500">
|
||||
{/* Left: label – stays put */}
|
||||
<span style={{ fontFamily: '"IBM Plex Sans", sans-serif', fontSize: 9, fontWeight: 700, letterSpacing: '0.3em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.5)', whiteSpace: 'nowrap', flexShrink: 0 }}>{fallbackText(hero.partnersLabel, homeContent.hero.partnersLabel)}</span>
|
||||
{/* Right: ticker – fixed window, exactly 4 logos wide */}
|
||||
{/* Right: ticker window */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 16, flexShrink: 0 }}>
|
||||
<div style={{ width: 1, height: 20, background: 'rgba(255,255,255,0.2)' }} />
|
||||
<div style={{ width: 560, overflow: 'hidden', flexShrink: 0 }}>
|
||||
<PartnerTicker logos={partnerLogos(hero.partners)} />
|
||||
<div style={{ width: 'min(820px, calc(100vw - 260px))', overflow: 'hidden', flexShrink: 0 }}>
|
||||
<PartnerTicker logos={partnerLogos(networkPartners, defaultLogoColor)} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { mediaAlt, mediaUrl } from '@/spa/cmsMediaField';
|
||||
import { homeContent } from '@/spa/homeContent';
|
||||
import { netzwerkContent } from '@/spa/netzwerkContent';
|
||||
import Image from '@/spa/components/ui/UnoptimizedImage'
|
||||
import { PartnerLogoMark, type PartnerLogoData } from '@/spa/components/ui/partner-logo';
|
||||
|
||||
const FF = '"IBM Plex Sans", sans-serif';
|
||||
const FB = '"Inter", sans-serif';
|
||||
@@ -44,7 +45,17 @@ type HomeVideoCms = {
|
||||
|
||||
type PatronPerson = (typeof netzwerkContent.patronage.people)[number] & { imageUpload?: unknown }
|
||||
type JuryMember = (typeof netzwerkContent.jury.members)[number] & { imageUpload?: unknown }
|
||||
type Partner = (typeof netzwerkContent.partners.items)[number] & { stableId?: string; tier: 1 | 2 | 3; heroImg?: string; linkedin?: string; logoSubtext?: string }
|
||||
type Partner = (typeof netzwerkContent.partners.items)[number] &
|
||||
PartnerLogoData & {
|
||||
active?: boolean | null
|
||||
heroImg?: string
|
||||
linkedin?: string
|
||||
logoSubtext?: string
|
||||
showOnHomepage?: boolean | null
|
||||
sortOrder?: number | null
|
||||
stableId?: string | null
|
||||
tier: 1 | 2 | 3
|
||||
}
|
||||
type PartnerTier = (typeof netzwerkContent.partners.tiers)[number]
|
||||
type ExpertiseRow = (typeof netzwerkContent.expertise.rows)[number]
|
||||
type StatItem = (typeof netzwerkContent.juryIntro.stats)[number]
|
||||
@@ -54,6 +65,11 @@ type PartnerModalCopy = typeof netzwerkContent.partners.modal
|
||||
const fallbackText = (value: unknown, fallback: string) => typeof value === 'string' && value.length > 0 ? value : fallback;
|
||||
const fallbackArray = <T,>(value: unknown, fallback: T[]) => Array.isArray(value) && value.length ? value as T[] : fallback;
|
||||
const managedImage = (upload: unknown, fallback: unknown) => mediaUrl(upload, fallbackText(fallback, ''))
|
||||
const sortedPartners = <T extends PartnerLogoData>(partners: T[]) =>
|
||||
partners
|
||||
.map((partner, index) => ({ partner, index }))
|
||||
.sort((a, b) => Number(a.partner.sortOrder ?? a.index) - Number(b.partner.sortOrder ?? b.index))
|
||||
.map(({ partner }) => partner)
|
||||
const isMembershipCta = (cta?: { label?: string | null; url?: string | null } | null) => {
|
||||
const normalizedLabel = cta?.label?.trim().toLowerCase();
|
||||
|
||||
@@ -185,38 +201,6 @@ const JuryChairCard: React.FC<{ member: JuryMember; badge: string }> = ({ member
|
||||
|
||||
// ── SponsorCell (tiered) ──────────────────────────────────────────────────────
|
||||
|
||||
function PartnerLogo({ partner }: { partner: Partner }) {
|
||||
const color = fallbackText(partner.logoColor, netzwerkContent.partners.defaultLogoColor);
|
||||
const text = fallbackText(partner.logoText, partner.name);
|
||||
const subtext = fallbackText(partner.logoSubtext, '');
|
||||
|
||||
if (partner.logoKind === 'badge') {
|
||||
return <span style={{ background: color, color: '#fff', fontWeight: 900, fontSize: 14, padding: '4px 10px', lineHeight: 1.25, display: 'inline-block', textAlign: 'center' as const, fontFamily: FF }}>{text.split('\n').map((line, index) => <React.Fragment key={`${line}-${index}`}>{index > 0 && <br />}{line}</React.Fragment>)}</span>
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'monogram') {
|
||||
return <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}><span style={{ width: 22, height: 22, background: '#3a3a3a', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 900, fontSize: 11, fontFamily: FF }}>{subtext || text.slice(0, 2)}</span><span style={{ fontWeight: 700, fontSize: 15, color, fontFamily: FF }}>{text}</span></span>
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'dot') {
|
||||
return <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}><span style={{ width: 20, height: 20, borderRadius: '50%', background: color, display: 'block' }} /><span style={{ fontWeight: 700, fontSize: 16, color, fontFamily: FF }}>{text}</span></span>
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'leaf') {
|
||||
return <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}><svg width="20" height="20" viewBox="0 0 20 20"><circle cx="10" cy="10" r="9" fill={color} /><path d="M10 3 Q14 7 14 10 Q14 14 10 17 Q6 14 6 10 Q6 7 10 3Z" fill="white" opacity="0.8" /></svg><span style={{ fontWeight: 700, fontSize: 15, color, fontFamily: FB }}>{text}</span></span>
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'rsm') {
|
||||
return <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}><span style={{ display: 'flex', gap: 2 }}><span style={{ width: 10, height: 10, background: '#6b7280', display: 'block' }} /><span style={{ width: 10, height: 10, background: '#22c55e', display: 'block' }} /><span style={{ width: 10, height: 10, background: '#3b82f6', display: 'block' }} /></span><span style={{ fontWeight: 900, fontSize: 15, letterSpacing: '-0.02em', color, fontFamily: FF }}>{text} {subtext && <span style={{ color: '#6b7280', fontWeight: 600 }}>{subtext}</span>}</span></span>
|
||||
}
|
||||
|
||||
if (partner.logoKind === 'deutschebank') {
|
||||
return <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}><svg width="20" height="20" viewBox="0 0 20 20"><rect x="1" y="1" width="18" height="18" fill="none" stroke={color} strokeWidth="1.5" /><line x1="5" y1="15" x2="15" y2="5" stroke={color} strokeWidth="2" /></svg><span style={{ fontWeight: 600, fontSize: 15, color, fontFamily: FB }}>{text}</span></span>
|
||||
}
|
||||
|
||||
return <span style={{ fontWeight: 900, fontSize: partner.logoKind === 'serif' ? 21 : 16, letterSpacing: partner.logoKind === 'serif' ? '0.12em' : '-0.01em', color, fontFamily: partner.logoKind === 'serif' ? 'Georgia, serif' : FF }}>{text}</span>
|
||||
}
|
||||
|
||||
const SponsorCell: React.FC<{ partner: Partner; variant: 'lg' | 'md' | 'sm'; idx: number; cols: number; detailLabel: string; premiumLabel: string; onClick: () => void }> = ({ partner, variant, idx, cols, detailLabel, premiumLabel, onClick }) => {
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const isMobileCell = useIsMobile();
|
||||
@@ -242,7 +226,7 @@ const SponsorCell: React.FC<{ partner: Partner; variant: 'lg' | 'md' | 'sm'; idx
|
||||
{lg && (
|
||||
<span style={{ position: 'absolute', top: 18, right: 18, fontFamily: FF, fontSize: 9, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.18em', color: '#101828', background: GOLD, padding: '4px 10px', borderRadius: 100, zIndex: 1 }}>{premiumLabel}</span>
|
||||
)}
|
||||
<div style={{ height: lg ? 52 : 44, display: 'flex', alignItems: 'center' }}><PartnerLogo partner={partner} /></div>
|
||||
<div style={{ height: lg ? 52 : 44, display: 'flex', alignItems: 'center' }}><PartnerLogoMark partner={partner} /></div>
|
||||
<div style={{ width: hovered ? 48 : 20, height: 1, background: GOLD, transition: 'width 0.3s ease' }} />
|
||||
<div style={{ fontFamily: FF, fontSize: lg ? 22 : 18, fontWeight: 700, color: '#101828', letterSpacing: '-0.01em', lineHeight: 1.15 }}>{partner.name}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: sm ? 10 : 11, color: GOLD, textTransform: 'uppercase', letterSpacing: '0.2em', fontWeight: 700 }}>{partner.role}</div>
|
||||
@@ -353,7 +337,7 @@ function PartnerModal({ partner, copy, onClose }: { partner: Partner; copy: Part
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
padding: 10, zIndex: 2,
|
||||
}}>
|
||||
<PartnerLogo partner={partner} />
|
||||
<PartnerLogoMark partner={partner} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -466,6 +450,7 @@ const Netzwerk: React.FC = () => {
|
||||
const greetingVideoRef = useRef<HTMLVideoElement>(null);
|
||||
const cms = (useCmsRoute()?.doc?.netzwerk || {}) as NetzwerkCms;
|
||||
const homePage = useCmsCollection('pages').find((page) => page.spaPath === '/' || page.slug === 'startseite' || page.slug === 'home');
|
||||
const cmsPartners = useCmsCollection('partners') as unknown as Partner[];
|
||||
const home = (homePage?.home || {}) as HomeVideoCms;
|
||||
const homeVideoModal = home.videoModal || {};
|
||||
const hero = { ...netzwerkContent.hero, ...(cms.hero || {}) };
|
||||
@@ -480,11 +465,14 @@ const Netzwerk: React.FC = () => {
|
||||
const juryMembers = fallbackArray<JuryMember>(jury.members, netzwerkContent.jury.members);
|
||||
const expertiseRows = fallbackArray<ExpertiseRow>(expertise.rows, netzwerkContent.expertise.rows);
|
||||
const defaultLogoColor = fallbackText(partnerSection.defaultLogoColor, netzwerkContent.partners.defaultLogoColor);
|
||||
const partners = fallbackArray<Partner>(partnerSection.items, netzwerkContent.partners.items as Partner[]).map((partner) => ({
|
||||
...partner,
|
||||
id: partner.stableId || partner.id,
|
||||
logoColor: fallbackText(partner.logoColor, defaultLogoColor),
|
||||
}));
|
||||
const partnerSource = cmsPartners.length ? cmsPartners : (netzwerkContent.partners.items as Partner[]);
|
||||
const partners = sortedPartners(partnerSource)
|
||||
.filter((partner) => partner.active !== false)
|
||||
.map((partner) => ({
|
||||
...partner,
|
||||
id: partner.stableId || partner.id,
|
||||
logoColor: fallbackText(partner.logoColor, defaultLogoColor),
|
||||
}));
|
||||
const partnerTiers = fallbackArray<PartnerTier>(partnerSection.tiers, netzwerkContent.partners.tiers);
|
||||
const mobileStats = fallbackArray<StatItem>(juryIntro.stats, netzwerkContent.juryIntro.stats);
|
||||
const desktopStats = fallbackArray<StatItem>(juryIntro.desktopStats, netzwerkContent.juryIntro.desktopStats);
|
||||
|
||||
@@ -5,6 +5,8 @@ import type { Media, Page, Post, Config } from '../payload-types'
|
||||
import { mergeOpenGraph } from './mergeOpenGraph'
|
||||
import { getServerSideURL } from './getURL'
|
||||
|
||||
const siteName = 'Bayerischer Mittelstandspreis'
|
||||
|
||||
const getImageURL = (image?: Media | Config['db']['defaultIDType'] | null) => {
|
||||
const serverUrl = getServerSideURL()
|
||||
|
||||
@@ -26,9 +28,7 @@ export const generateMeta = async (args: {
|
||||
|
||||
const ogImage = getImageURL(doc?.meta?.image)
|
||||
|
||||
const title = doc?.meta?.title
|
||||
? doc?.meta?.title + ' | Payload Website Template'
|
||||
: 'Payload Website Template'
|
||||
const title = doc?.meta?.title ? doc?.meta?.title + ` | ${siteName}` : siteName
|
||||
|
||||
return {
|
||||
description: doc?.meta?.description,
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import configPromise from '@payload-config'
|
||||
import { getPayload } from 'payload'
|
||||
import { unstable_cache } from 'next/cache'
|
||||
|
||||
export async function getRedirects(depth = 1) {
|
||||
const payload = await getPayload({ config: configPromise })
|
||||
|
||||
const { docs: redirects } = await payload.find({
|
||||
collection: 'redirects',
|
||||
depth,
|
||||
limit: 0,
|
||||
pagination: false,
|
||||
})
|
||||
|
||||
return redirects
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unstable_cache function mapped with the cache tag for 'redirects'.
|
||||
*
|
||||
* Cache all redirects together to avoid multiple fetches.
|
||||
*/
|
||||
export const getCachedRedirects = () =>
|
||||
unstable_cache(async () => getRedirects(), ['redirects'], {
|
||||
tags: ['redirects'],
|
||||
})
|
||||
@@ -1,16 +1,18 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { getServerSideURL } from './getURL'
|
||||
|
||||
const siteName = 'Bayerischer Mittelstandspreis'
|
||||
|
||||
const defaultOpenGraph: Metadata['openGraph'] = {
|
||||
type: 'website',
|
||||
description: 'An open-source website built with Payload and Next.js.',
|
||||
description: 'Der Preis für herausragenden Mittelstand in Bayern.',
|
||||
images: [
|
||||
{
|
||||
url: `${getServerSideURL()}/website-template-OG.webp`,
|
||||
},
|
||||
],
|
||||
siteName: 'Payload Website Template',
|
||||
title: 'Payload Website Template',
|
||||
siteName,
|
||||
title: siteName,
|
||||
}
|
||||
|
||||
export const mergeOpenGraph = (og?: Metadata['openGraph']): Metadata['openGraph'] => {
|
||||
|
||||
Reference in New Issue
Block a user