From 0240f2df4f06bd4a8abf1bff21396907d3254b52 Mon Sep 17 00:00:00 2001 From: Benno Tielen Date: Fri, 6 Mar 2026 13:29:11 +0100 Subject: [PATCH] feat: customizable footer --- src/collections/Prayers.ts | 38 ++++++++++ src/components/RandomPrayer/RandomPrayer.tsx | 42 +++++------ src/compositions/Footer/Footer.tsx | 59 ++++++++-------- src/fetch/footer.ts | 13 ++++ src/fetch/prayers.ts | 11 +++ src/globals/Footer.ts | 65 +++++++++++++++++ src/migrations/20260306_100000_prayers.ts | 65 +++++++++++++++++ src/migrations/index.ts | 8 ++- src/payload-types.ts | 73 ++++++++++++++++++++ src/payload.config.ts | 6 +- 10 files changed, 323 insertions(+), 57 deletions(-) create mode 100644 src/collections/Prayers.ts create mode 100644 src/fetch/footer.ts create mode 100644 src/fetch/prayers.ts create mode 100644 src/globals/Footer.ts create mode 100644 src/migrations/20260306_100000_prayers.ts diff --git a/src/collections/Prayers.ts b/src/collections/Prayers.ts new file mode 100644 index 0000000..06d6fa6 --- /dev/null +++ b/src/collections/Prayers.ts @@ -0,0 +1,38 @@ +import { CollectionConfig } from 'payload' +import { revalidateTag } from 'next/cache' +import { isAdminOrEmployee } from '@/collections/access/admin' + +export const Prayers: CollectionConfig = { + slug: 'prayers', + labels: { + singular: { + de: 'Stoßgebet', + }, + plural: { + de: 'Stoßgebete', + }, + }, + fields: [ + { + name: 'text', + type: 'text', + required: true, + label: { + de: 'Gebet', + }, + }, + ], + admin: { + useAsTitle: 'text', + }, + access: { + read: () => true, + create: isAdminOrEmployee(), + update: isAdminOrEmployee(), + delete: isAdminOrEmployee(), + }, + hooks: { + afterChange: [() => revalidateTag('prayers')], + afterDelete: [() => revalidateTag('prayers')], + }, +} diff --git a/src/components/RandomPrayer/RandomPrayer.tsx b/src/components/RandomPrayer/RandomPrayer.tsx index 9fcccbd..99e275f 100644 --- a/src/components/RandomPrayer/RandomPrayer.tsx +++ b/src/components/RandomPrayer/RandomPrayer.tsx @@ -1,38 +1,32 @@ -"use client" +'use client' -import { randomPrayer } from '@/utils/randomPrayer' import { useCallback, useEffect, useState } from 'react' -export const RandomPrayer = () => { - const [intervalId, setIntervalId] = useState(undefined) - const [prayer, setPrayer] = useState("") +type RandomPrayerProps = { + prayers: string[] +} - // Set interval to change the prayer - const newPrayerEveryInterval = useCallback(() => { - const i = setInterval(() => { - setPrayer(randomPrayer()) - }, 60 * 1000) +const pickRandom = (prayers: string[]) => + prayers[Math.floor(Math.random() * prayers.length)] || '' - setIntervalId(i) - }, [setPrayer, setIntervalId]) +export const RandomPrayer = ({ prayers }: RandomPrayerProps) => { + const [prayer, setPrayer] = useState('') - // Set new random prayer and reset timer interval const newPrayer = useCallback(() => { - clearInterval(intervalId) - setPrayer(randomPrayer()) - newPrayerEveryInterval() - }, [intervalId, setPrayer, newPrayerEveryInterval]) + setPrayer(pickRandom(prayers)) + }, [prayers]) - // Every 30 seconds set a new prayer useEffect(() => { - setPrayer(randomPrayer()) - newPrayerEveryInterval() - return () => clearInterval(intervalId) - }, [newPrayerEveryInterval]) + setPrayer(pickRandom(prayers)) + const interval = setInterval(() => { + setPrayer(pickRandom(prayers)) + }, 60 * 1000) + return () => clearInterval(interval) + }, [prayers]) return ( -

+

{prayer}

) -} \ No newline at end of file +} diff --git a/src/compositions/Footer/Footer.tsx b/src/compositions/Footer/Footer.tsx index f78eec3..3dd6fc4 100644 --- a/src/compositions/Footer/Footer.tsx +++ b/src/compositions/Footer/Footer.tsx @@ -1,24 +1,30 @@ import { Section } from '@/components/Section/Section' import { Container } from '@/components/Container/Container' import { Logo } from '@/components/Logo/Logo' -import styles from "./styles.module.scss" +import styles from './styles.module.scss' import { Row } from '@/components/Flex/Row' import { Col } from '@/components/Flex/Col' import { RandomPrayer } from '@/components/RandomPrayer/RandomPrayer' import Link from 'next/link' +import { fetchPrayers } from '@/fetch/prayers' +import { fetchFooter } from '@/fetch/footer' +export const Footer = async () => { + const [prayers, footer] = await Promise.all([ + fetchPrayers(), + fetchFooter(), + ]) -export const Footer = () => { return (
-
+
@@ -26,34 +32,25 @@ export const Footer = () => { - -

Gemeinden

-
    -
  • St. Christophorus
  • -
  • St. Clara
  • -
  • St. Richard
  • -
- + {footer.groups?.map((group, i) => ( + +

+ {group.title} +

+
    + {group.links?.map((link, j) => ( +
  • + {link.label} +
  • + ))} +
+ + ))}

- Navigation -

-
    -
  • Kontakt
  • -
  • Gottesdienste
  • -
  • Veranstaltungen
  • -
  • Mithelfen
  • -
  • Datenschutz
  • -
  • Schutzkonzept
  • -
  • Hinweisgeber
  • -
  • Impressum
  • -
- - -

Stoßgebet

- +
@@ -61,5 +58,5 @@ export const Footer = () => {
- ); -} \ No newline at end of file + ) +} diff --git a/src/fetch/footer.ts b/src/fetch/footer.ts new file mode 100644 index 0000000..a9ea914 --- /dev/null +++ b/src/fetch/footer.ts @@ -0,0 +1,13 @@ +import { Footer } from '@/payload-types' + +export async function fetchFooter(): Promise