feature: group page

This commit is contained in:
Benno Tielen 2024-12-03 16:24:09 +01:00
parent 388ab0b2e6
commit 9ac5c43e65
10 changed files with 303 additions and 74 deletions

View file

@ -13,6 +13,7 @@ import { Button } from '@/components/Button/Button'
import { ContactSection } from '@/compositions/ContactSection/ContactSection' import { ContactSection } from '@/compositions/ContactSection/ContactSection'
import { Gallery } from '@/components/Gallery/Gallery' import { Gallery } from '@/components/Gallery/Gallery'
import { transformGallery } from '@/utils/dto/gallery' import { transformGallery } from '@/utils/dto/gallery'
import { Blocks } from '@/compositions/Blocks/Blocks'
async function fetchBlog(id: string) { async function fetchBlog(id: string) {
const res = await fetch(`http://localhost:3000/api/blog/${id}`) const res = await fetch(`http://localhost:3000/api/blog/${id}`)
@ -54,50 +55,8 @@ export default async function BlogPage({ params }: { params: Promise<{id: string
</Container> </Container>
</Section> </Section>
<div> <Blocks content={data.content} />
{data.content.map(item => {
if (item.blockType === "text" && item.content_html) {
return (
<Container key={item.id}>
<HTMLText width={item.width} html={item.content_html} />
</Container>
);
}
if (item.blockType === "document" && typeof item.file === "object") {
return (
<Container key={item.id}>
<Section padding={"medium"}>
<Button size={"lg"} href={item.file.url || "notfound"} schema={"contrast"}>{item.button}</Button>
</Section>
</Container>
)
}
if (item.blockType === "contactform") {
return (
<ContactSection
key={item.id}
title={item.title}
description={item.description}
backgroundColor={"off-white"}
/>
)
}
if (item.blockType === "gallery") {
return (
<Section key={item.id}>
<Gallery items={transformGallery(item.items)} />
</Section>
)
}
})}
</div>
{ shouldAddMargin &&
<Section></Section>
}
</> </>
) )
} }

View file

@ -1,3 +1,4 @@
import styles from "./styles.module.scss"
import { ImageWithText } from '@/compositions/ImageWithText/ImageWithText' import { ImageWithText } from '@/compositions/ImageWithText/ImageWithText'
import { fetchGroup } from '@/fetch/group' import { fetchGroup } from '@/fetch/group'
import { notFound } from 'next/navigation' import { notFound } from 'next/navigation'
@ -9,6 +10,10 @@ import { transformEvents } from '@/utils/dto/events'
import { Container } from '@/components/Container/Container' import { Container } from '@/components/Container/Container'
import { HR } from '@/components/HorizontalRule/HorizontalRule' import { HR } from '@/components/HorizontalRule/HorizontalRule'
import { TextDiv } from '@/components/Text/TextDiv' import { TextDiv } from '@/components/Text/TextDiv'
import { Col } from '@/components/Flex/Col'
import { Row } from '@/components/Flex/Row'
import { RawHTML } from '@/components/RawHTML/RawHTML'
import { Blocks } from '@/compositions/Blocks/Blocks'
export default async function GroupPage({ params }: { params: Promise<{slug: string}>}) { export default async function GroupPage({ params }: { params: Promise<{slug: string}>}) {
@ -19,7 +24,7 @@ export default async function GroupPage({ params }: { params: Promise<{slug: str
notFound(); notFound();
} }
const {id, description, photo,name } = groups.docs[0] const {id, shortDescription, photo,name, text_html, content } = groups.docs[0]
const media = { const media = {
src: typeof photo === "object" && photo ? photo.url || "" : "", src: typeof photo === "object" && photo ? photo.url || "" : "",
width: typeof photo === "object" && photo ? photo.width || 0 : 0, width: typeof photo === "object" && photo ? photo.width || 0 : 0,
@ -35,8 +40,9 @@ export default async function GroupPage({ params }: { params: Promise<{slug: str
<ImageWithText <ImageWithText
title={name} title={name}
backgroundColor={"soft"} backgroundColor={"soft"}
text={description} text={shortDescription}
image={media} image={media}
schema={"contrast"}
/> />
} }
@ -46,7 +52,7 @@ export default async function GroupPage({ params }: { params: Promise<{slug: str
<Container> <Container>
<Title title={name} /> <Title title={name} />
<strong> <strong>
<TextDiv text={description} /> <TextDiv text={shortDescription} />
</strong> </strong>
</Container> </Container>
@ -56,16 +62,39 @@ export default async function GroupPage({ params }: { params: Promise<{slug: str
} }
{ events && events.docs.length > 0 &&
<Section> <Section>
<Container> <Container>
<Title title={"Veranstaltungen"} size={"md"} /> <Row>
<Events events={transformEvents(events.docs)} n={3} /> <Col>
</Container> <div className={styles.content}>
<Section></Section> { text_html &&
</Section> <RawHTML html={text_html} />
} }
</div>
</Col>
<Col>
{ events && events.docs.length > 0 &&
<>
<Title
title={"Veranstaltungen"}
size={"md"}
color={"contrast"}
/>
<Events
events={transformEvents(events.docs)}
n={3}
schema={"contrast"}
/>
</>
}
</Col>
</Row>
</Container>
</Section>
{ content && content.length > 0 &&
<Blocks content={content} />
}
</> </>
) )
} }

View file

@ -0,0 +1,5 @@
@import "template.scss";
.content h3, .content h4, .content h5, .content h6 {
color: $base-color;
}

View file

@ -57,23 +57,23 @@ export default function RootLayout({
items: [ items: [
{ {
title: "Kathoccino", title: "Kathoccino",
description: "Begegnung mit Gott", description: "Brunchgruppe für Jungerwachsene",
href: "/gruppe/kathocchino" href: "/gruppe/kathocchino"
}, },
{ {
title: "Credo & Agape", title: "Credo & Agape",
description: "Gebet der Meditation", description: "Gesprächskreis für Erwachsene ab 45 Jahren",
href: "https://" href: "/gruppe/credo-agape"
}, },
{ {
title: "Mädchengruppe", title: "Mädchengruppe",
description: "Stille Begegnung mit Gott", description: "Zusammen die Welt entdecken",
href: "https://" href: "/gruppe/maedchen"
}, },
{ {
title: "Alphakurs", title: "Alphakurs",
description: "Dank, Ehre und Freude", description: "Freude am glauben entdecken",
href: "https://" href: "/gruppe/alphakurs"
}, },
] ]
}, },
@ -81,14 +81,14 @@ export default function RootLayout({
title: "Musik", title: "Musik",
items: [ items: [
{ {
title: "Little Richards", title: "Chor St. Clara",
description: "Der Hausband von St. Richard", description: "Singen und mitgestalten",
href: "https://" href: "/gruppe/chor-st-clara"
}, },
{ {
title: "Kindergruppe", title: "Kindergruppe",
description: "Jeden Freitag singen und spielen", description: "Jeden Freitag singen und spielen",
href: "https://" href: "/gruppe/kinder-musik"
} }
] ]
} }
@ -154,12 +154,12 @@ export default function RootLayout({
{ {
title: "Anbetung", title: "Anbetung",
description: "Stille Begegnung mit Gott", description: "Stille Begegnung mit Gott",
href: "https://" href: "/gruppe/eucharistische-anbetung"
}, },
{ {
title: "Lobpreis", title: "Holy Hour",
description: "Dank, Ehre und Freude", description: "Dank, Ehre und Freude",
href: "https://" href: "/gruppe/lobpreis"
}, },
] ]
} }
@ -178,12 +178,12 @@ export default function RootLayout({
title: "Ehrenamt", title: "Ehrenamt",
items: [ items: [
{ {
href: 'http://', href: '/gruppe/waermestube',
title: 'Wärmestube', title: 'Wärmestube',
description: 'Kälteschutz für Bedurftigen', description: 'Kälteschutz für Bedurftigen',
}, },
{ {
href: 'http://', href: '/gruppe/essen-ist-fertig',
title: 'Essen ist Fertig', title: 'Essen ist Fertig',
description: 'Essensausgabe Neukölln', description: 'Essensausgabe Neukölln',
}, },
@ -195,7 +195,22 @@ export default function RootLayout({
] ]
}, },
{ {
title: "Aktivitaten", title: "Projekte",
items: [
{
title: "Umgekehrter Advent",
description: "Geben statt nehmen ",
href: "/gruppe/umgekehrter-advent"
},
{
title: "Dicke Linda",
description: "Marktstand auf dem Kranoldplatz",
href: "/gruppe/dicke-linda"
},
]
},
{
title: "Aktivitäten",
items: [ items: [
{ {
title: "Kochen", title: "Kochen",

View file

@ -1,5 +1,10 @@
import { CollectionConfig } from 'payload' import { CollectionConfig } from 'payload'
import { isAdminOrEmployee } from '@/collections/access/admin' import { isAdminOrEmployee } from '@/collections/access/admin'
import { ParagraphBlock } from '@/collections/blocks/Paragraph'
import { GalleryBlock } from '@/collections/blocks/Gallery'
import { ContactformBlock } from '@/collections/blocks/Contactform'
import { DocumentBlock } from '@/collections/blocks/Document'
import { lexicalHTML } from '@payloadcms/richtext-lexical'
export const Groups: CollectionConfig = { export const Groups: CollectionConfig = {
slug: 'group', slug: 'group',
@ -38,13 +43,32 @@ export const Groups: CollectionConfig = {
unique: true unique: true
}, },
{ {
name: 'description', name: 'shortDescription',
type: 'textarea', type: 'textarea',
label: { label: {
de: 'Umschreibung', de: 'Kurzumschreibung',
}, },
required: true, required: true,
}, },
{
name: 'text',
type: 'richText',
label: {
de: 'Umschreibung',
},
required: false,
},
lexicalHTML('text', { name: 'text_html' }),
{
name: 'content',
type: 'blocks',
blocks: [
ParagraphBlock,
GalleryBlock,
DocumentBlock,
ContactformBlock
]
}
], ],
admin: { admin: {
useAsTitle: 'name', useAsTitle: 'name',

View file

@ -1,9 +1,14 @@
import styles from "./styles.module.scss"
type RawHTMLProps = { type RawHTMLProps = {
html: string html: string
} }
export const RawHTML = ({html}: RawHTMLProps) => { export const RawHTML = ({html}: RawHTMLProps) => {
return ( return (
<div dangerouslySetInnerHTML={{__html: html}}></div> <div
className={styles.content}
dangerouslySetInnerHTML={{__html: html}}
></div>
) )
} }

View file

@ -0,0 +1,14 @@
@import "template.scss";
.content a {
color: inherit;
}
.content a:hover {
color: $base-color;
}
.content h3 {
font-size: 33px;
margin: 33px 0 20px 0;
}

View file

@ -0,0 +1,68 @@
import { Blog } from "@/payload-types"
import { Container } from '@/components/Container/Container'
import { HTMLText } from '@/components/Text/HTMLText'
import { Section } from '@/components/Section/Section'
import { Button } from '@/components/Button/Button'
import { ContactSection } from '@/compositions/ContactSection/ContactSection'
import { Gallery } from '@/components/Gallery/Gallery'
import { transformGallery } from '@/utils/dto/gallery'
type BlocksProps = {
content: Blog['content']
}
export function Blocks({ content }: BlocksProps) {
// determine if some margin at the bottom should be added
const length = content.length;
const shouldAddMargin = content[length - 1].blockType === "text"
return (
<>
<div>
{content.map(item => {
if (item.blockType === "text" && item.content_html) {
return (
<Container key={item.id}>
<HTMLText width={item.width} html={item.content_html} />
</Container>
);
}
if (item.blockType === "document" && typeof item.file === "object") {
return (
<Container key={item.id}>
<Section padding={"medium"}>
<Button size={"lg"} href={item.file.url || "notfound"} schema={"contrast"}>{item.button}</Button>
</Section>
</Container>
)
}
if (item.blockType === "contactform") {
return (
<ContactSection
key={item.id}
title={item.title}
description={item.description}
backgroundColor={"off-white"}
/>
)
}
if (item.blockType === "gallery") {
return (
<Section key={item.id}>
<Gallery items={transformGallery(item.items)} />
</Section>
)
}
})}
</div>
{ shouldAddMargin &&
<Section></Section>
}
</>
)
}

View file

@ -376,7 +376,73 @@ export interface Group {
photo?: (string | null) | Media; photo?: (string | null) | Media;
name: string; name: string;
slug: string; slug: string;
shortDescription: string;
text?: {
root: {
type: string;
children: {
type: string;
version: number;
[k: string]: unknown;
}[];
direction: ('ltr' | 'rtl') | null;
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
indent: number;
version: number;
};
[k: string]: unknown;
} | null;
text_html?: string | null;
content?:
| (
| {
content: {
root: {
type: string;
children: {
type: string;
version: number;
[k: string]: unknown;
}[];
direction: ('ltr' | 'rtl') | null;
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
indent: number;
version: number;
};
[k: string]: unknown;
};
content_html?: string | null;
width: '1/2' | '3/4';
id?: string | null;
blockName?: string | null;
blockType: 'text';
}
| {
items: {
photo: string | Media;
id?: string | null;
}[];
id?: string | null;
blockName?: string | null;
blockType: 'gallery';
}
| {
file: string | Document;
button: string;
id?: string | null;
blockName?: string | null;
blockType: 'document';
}
| {
title: string;
description: string; description: string;
email: string;
id?: string | null;
blockName?: string | null;
blockType: 'contactform';
}
)[]
| null;
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;
} }
@ -768,7 +834,51 @@ export interface GroupSelect<T extends boolean = true> {
photo?: T; photo?: T;
name?: T; name?: T;
slug?: T; slug?: T;
shortDescription?: T;
text?: T;
text_html?: T;
content?:
| T
| {
text?:
| T
| {
content?: T;
content_html?: T;
width?: T;
id?: T;
blockName?: T;
};
gallery?:
| T
| {
items?:
| T
| {
photo?: T;
id?: T;
};
id?: T;
blockName?: T;
};
document?:
| T
| {
file?: T;
button?: T;
id?: T;
blockName?: T;
};
contactform?:
| T
| {
title?: T;
description?: T; description?: T;
email?: T;
id?: T;
blockName?: T;
};
};
updatedAt?: T; updatedAt?: T;
createdAt?: T; createdAt?: T;
} }

View file

@ -14,7 +14,7 @@ export const highlightLink = (highlight: Highlight) => {
case 'worship': case 'worship':
return `/gottesdienst/${highlight.link.value.id}`; return `/gottesdienst/${highlight.link.value.id}`;
case 'event': case 'event':
return `/event/${highlight.link.value.id}`; return `/veranstaltungen/${highlight.link.value.id}`;
case 'blog': case 'blog':
return `/blog/${highlight.link.value.id}`; return `/blog/${highlight.link.value.id}`;
default: default: