feature: contact persons
Some checks are pending
Deploy / deploy (push) Waiting to run

This commit is contained in:
Benno Tielen 2026-03-20 00:01:36 +01:00
parent 3f8269aa4a
commit ed273454a3
12 changed files with 36536 additions and 1 deletions

View file

@ -25,6 +25,13 @@ export const ContactPerson: CollectionConfig = {
de: "Name" de: "Name"
} }
}, },
{
name: 'role',
type: 'text',
label: {
de: 'Funktion',
},
},
{ {
name: 'email', name: 'email',
type: 'email', type: 'email',

View file

@ -19,6 +19,7 @@ import { MassTimesBlock } from '@/collections/blocks/MassTimes'
import { CollapsibleImageWithTextBlock } from '@/collections/blocks/CollapsibleImageWithText' import { CollapsibleImageWithTextBlock } from '@/collections/blocks/CollapsibleImageWithText'
import { EventsBlock } from '@/collections/blocks/Events' import { EventsBlock } from '@/collections/blocks/Events'
import { PublicationAndNewsletterBlock } from '@/collections/blocks/PublicationAndNewsletter' import { PublicationAndNewsletterBlock } from '@/collections/blocks/PublicationAndNewsletter'
import { ContactPersonBlock } from '@/collections/blocks/ContactPersonBlock'
import { isPublishedPublic } from '@/collections/access/public' import { isPublishedPublic } from '@/collections/access/public'
export const Pages: CollectionConfig = { export const Pages: CollectionConfig = {
@ -97,6 +98,7 @@ export const Pages: CollectionConfig = {
CollapsibleImageWithTextBlock, CollapsibleImageWithTextBlock,
MassTimesBlock, MassTimesBlock,
EventsBlock, EventsBlock,
ContactPersonBlock,
], ],
}, },
], ],

View file

@ -0,0 +1,24 @@
import { Block } from 'payload'
export const ContactPersonBlock: Block = {
slug: 'contactPersonBlock',
labels: {
singular: {
de: 'Ansprechperson',
},
plural: {
de: 'Ansprechpersonen',
},
},
fields: [
{
name: 'contact',
type: 'relationship',
relationTo: 'contactPerson',
required: true,
label: {
de: 'Ansprechperson',
},
},
],
}

View file

@ -0,0 +1,58 @@
import styles from './styles.module.scss'
import { ContactPerson } from '@/payload-types'
import Image, { StaticImageData } from 'next/image'
type ContactPersonCardProps = {
contact: null | string | undefined | ContactPerson
photo?: StaticImageData
}
export const ContactPersonCard = ({
contact,
photo,
}: ContactPersonCardProps) => {
if (
contact === null ||
contact === undefined ||
typeof contact === 'string'
) {
return null
}
return (
<div className={styles.card}>
<div>
{photo && (
<Image
className={styles.photo}
src={photo}
alt={contact.name}
width={200}
height={200}
unoptimized={true}
/>
)}
</div>
<div>
{contact.role && (
<h3 className={styles.role}>{contact.role}</h3>
)}
<div className={styles.info}>
<span className={styles.name}>{contact.name}</span>
{contact.email && (
<a href={`mailto:${contact.email}`} className={styles.link}>
{contact.email}
</a>
)}
{contact.telephone && (
<a href={`tel:${contact.telephone}`} className={styles.link}>
{contact.telephone}
</a>
)}
</div>
</div>
</div>
)
}

View file

@ -0,0 +1,40 @@
@use 'template' as *;
.card {
display: flex;
flex-direction: row;
align-items: center;
gap: 50px;
}
.photo {
width: 200px;
height: 200px;
object-fit: cover;
border-radius: 50%;
}
.role {
font-size: 25px;
color: $base-color;
margin: 0;
}
.info {
display: flex;
flex-direction: column;
gap: 4px;
}
.name {
font-weight: bold;
}
.link {
text-decoration: none;
color: inherit;
&:hover {
text-decoration: underline;
}
}

View file

@ -15,6 +15,8 @@ import { MainText } from '@/components/MainText/MainText'
import { HR } from '@/components/HorizontalRule/HorizontalRule' import { HR } from '@/components/HorizontalRule/HorizontalRule'
import { CollapsibleImageWithText } from '@/compositions/CollapsibleImageWithText/CollapsibleImageWithText' import { CollapsibleImageWithText } from '@/compositions/CollapsibleImageWithText/CollapsibleImageWithText'
import { PublicationAndNewsletter } from '@/compositions/PublicationAndNewsletter/PublicationAndNewsletter' import { PublicationAndNewsletter } from '@/compositions/PublicationAndNewsletter/PublicationAndNewsletter'
import { ContactPersonCard } from '@/components/ContactPersonCard/ContactPersonCard'
import { getPhoto } from '@/utils/dto/gallery'
import { BlogSliderBlock } from '@/compositions/Blocks/BlogSliderBlock' import { BlogSliderBlock } from '@/compositions/Blocks/BlogSliderBlock'
import { MassTimesBlock } from '@/compositions/Blocks/MassTimesBlock' import { MassTimesBlock } from '@/compositions/Blocks/MassTimesBlock'
import { EventsBlock } from '@/compositions/Blocks/EventsBlock' import { EventsBlock } from '@/compositions/Blocks/EventsBlock'
@ -231,6 +233,22 @@ export function Blocks({ content }: BlocksProps) {
) )
} }
if (item.blockType === 'contactPersonBlock') {
const contact = typeof item.contact === 'object'
? item.contact
: undefined
const photo = contact
? getPhoto('thumbnail', contact.photo)
: undefined
return (
<Section key={item.id} padding={'small'}>
<Container>
<ContactPersonCard contact={contact} photo={photo} />
</Container>
</Section>
)
}
// if (item.blockType === 'publicationAndNewsletter') { // if (item.blockType === 'publicationAndNewsletter') {
// return <PublicationAndNewsletter key={item.id} /> // return <PublicationAndNewsletter key={item.id} />
// } // }

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,50 @@
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
CREATE TABLE "pages_blocks_contact_person_block" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"contact_id" uuid,
"block_name" varchar
);
CREATE TABLE "_pages_v_blocks_contact_person_block" (
"_order" integer NOT NULL,
"_parent_id" uuid NOT NULL,
"_path" text NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"contact_id" uuid,
"_uuid" varchar,
"block_name" varchar
);
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-03-22T22:38:03.504Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-03-22T22:38:03.783Z';
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-04-18T21:38:03.836Z';
ALTER TABLE "pages_blocks_contact_person_block" ADD CONSTRAINT "pages_blocks_contact_person_block_contact_id_contact_person_id_fk" FOREIGN KEY ("contact_id") REFERENCES "public"."contact_person"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "pages_blocks_contact_person_block" ADD CONSTRAINT "pages_blocks_contact_person_block_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_pages_v_blocks_contact_person_block" ADD CONSTRAINT "_pages_v_blocks_contact_person_block_contact_id_contact_person_id_fk" FOREIGN KEY ("contact_id") REFERENCES "public"."contact_person"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "_pages_v_blocks_contact_person_block" ADD CONSTRAINT "_pages_v_blocks_contact_person_block_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_pages_v"("id") ON DELETE cascade ON UPDATE no action;
CREATE INDEX "pages_blocks_contact_person_block_order_idx" ON "pages_blocks_contact_person_block" USING btree ("_order");
CREATE INDEX "pages_blocks_contact_person_block_parent_id_idx" ON "pages_blocks_contact_person_block" USING btree ("_parent_id");
CREATE INDEX "pages_blocks_contact_person_block_path_idx" ON "pages_blocks_contact_person_block" USING btree ("_path");
CREATE INDEX "pages_blocks_contact_person_block_contact_idx" ON "pages_blocks_contact_person_block" USING btree ("contact_id");
CREATE INDEX "_pages_v_blocks_contact_person_block_order_idx" ON "_pages_v_blocks_contact_person_block" USING btree ("_order");
CREATE INDEX "_pages_v_blocks_contact_person_block_parent_id_idx" ON "_pages_v_blocks_contact_person_block" USING btree ("_parent_id");
CREATE INDEX "_pages_v_blocks_contact_person_block_path_idx" ON "_pages_v_blocks_contact_person_block" USING btree ("_path");
CREATE INDEX "_pages_v_blocks_contact_person_block_contact_idx" ON "_pages_v_blocks_contact_person_block" USING btree ("contact_id");`)
}
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
ALTER TABLE "pages_blocks_contact_person_block" DISABLE ROW LEVEL SECURITY;
ALTER TABLE "_pages_v_blocks_contact_person_block" DISABLE ROW LEVEL SECURITY;
DROP TABLE "pages_blocks_contact_person_block" CASCADE;
DROP TABLE "_pages_v_blocks_contact_person_block" CASCADE;
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-03-22T21:58:39.666Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-03-22T21:58:39.963Z';
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-04-18T20:58:40.019Z';`)
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,17 @@
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-03-22T22:44:18.451Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-03-22T22:44:18.743Z';
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-04-18T21:44:18.801Z';
ALTER TABLE "contact_person" ADD COLUMN "role" varchar;`)
}
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
ALTER TABLE "announcement" ALTER COLUMN "date" SET DEFAULT '2026-03-22T22:38:03.504Z';
ALTER TABLE "calendar" ALTER COLUMN "date" SET DEFAULT '2026-03-22T22:38:03.783Z';
ALTER TABLE "classifieds" ALTER COLUMN "until" SET DEFAULT '2026-04-18T21:38:03.836Z';
ALTER TABLE "contact_person" DROP COLUMN "role";`)
}

View file

@ -22,6 +22,8 @@ import * as migration_20260310_143800 from './20260310_143800';
import * as migration_20260311_105947_drop_features from './20260311_105947_drop_features'; import * as migration_20260311_105947_drop_features from './20260311_105947_drop_features';
import * as migration_20260311_110236_live_preview from './20260311_110236_live_preview'; import * as migration_20260311_110236_live_preview from './20260311_110236_live_preview';
import * as migration_20260319_215840_collaps_item from './20260319_215840_collaps_item'; import * as migration_20260319_215840_collaps_item from './20260319_215840_collaps_item';
import * as migration_20260319_223804_contactperson_block from './20260319_223804_contactperson_block';
import * as migration_20260319_224419 from './20260319_224419';
export const migrations = [ export const migrations = [
{ {
@ -142,6 +144,16 @@ export const migrations = [
{ {
up: migration_20260319_215840_collaps_item.up, up: migration_20260319_215840_collaps_item.up,
down: migration_20260319_215840_collaps_item.down, down: migration_20260319_215840_collaps_item.down,
name: '20260319_215840_collaps_item' name: '20260319_215840_collaps_item',
},
{
up: migration_20260319_223804_contactperson_block.up,
down: migration_20260319_223804_contactperson_block.down,
name: '20260319_223804_contactperson_block',
},
{
up: migration_20260319_224419.up,
down: migration_20260319_224419.down,
name: '20260319_224419'
}, },
]; ];

View file

@ -645,6 +645,7 @@ export interface ContactPerson {
id: string; id: string;
photo?: (string | null) | Media; photo?: (string | null) | Media;
name: string; name: string;
role?: string | null;
email?: string | null; email?: string | null;
telephone?: string | null; telephone?: string | null;
updatedAt: string; updatedAt: string;
@ -885,6 +886,12 @@ export interface Page {
blockName?: string | null; blockName?: string | null;
blockType: 'events'; blockType: 'events';
} }
| {
contact: string | ContactPerson;
id?: string | null;
blockName?: string | null;
blockType: 'contactPersonBlock';
}
)[] )[]
| null; | null;
updatedAt: string; updatedAt: string;
@ -1353,6 +1360,7 @@ export interface ClassifiedsSelect<T extends boolean = true> {
export interface ContactPersonSelect<T extends boolean = true> { export interface ContactPersonSelect<T extends boolean = true> {
photo?: T; photo?: T;
name?: T; name?: T;
role?: T;
email?: T; email?: T;
telephone?: T; telephone?: T;
updatedAt?: T; updatedAt?: T;
@ -1615,6 +1623,13 @@ export interface PagesSelect<T extends boolean = true> {
id?: T; id?: T;
blockName?: T; blockName?: T;
}; };
contactPersonBlock?:
| T
| {
contact?: T;
id?: T;
blockName?: T;
};
}; };
updatedAt?: T; updatedAt?: T;
createdAt?: T; createdAt?: T;