church-website/src/app/(home)/veranstaltungen/page.tsx
2026-06-05 13:43:17 +02:00

149 lines
4.8 KiB
TypeScript

import moment from 'moment'
import { fetchUpcomingOccurrences } from '@/fetch/eventOccurrences'
import { fetchGroup, fetchAllGroups } from '@/fetch/group'
import { fetchParish, fetchAllParishes } from '@/fetch/parish'
import { transformOccurrences } from '@/utils/dto/events'
import { PageHeader } from '@/compositions/PageHeader/PageHeader'
import { Section } from '@/components/Section/Section'
import { Container } from '@/components/Container/Container'
import { EventRow } from '@/components/EventRow/EventRow'
import { NextPrevButtons } from '@/components/NextPrevButtons/NextPrevButtons'
import { EventFilterBar } from '@/compositions/EventFilterBar/EventFilterBar'
import { AdminMenu } from '@/components/AdminMenu/AdminMenu'
import Error from '@/components/Error/Error'
import { isAuthenticated } from '@/utils/auth'
import { Title } from '@/components/Title/Title'
import { HR } from '@/components/HorizontalRule/HorizontalRule'
import { P } from '@/components/Text/Paragraph'
const DATE_FMT = 'YYYY-MM-DD'
const PAGE_SIZE = 10
type Query = {
group?: string
parish?: string
from?: string
to?: string
page?: string
}
const parseDate = (value: string | undefined): Date | undefined => {
if (!value) return undefined
const m = moment(value, DATE_FMT, true)
return m.isValid() ? m.toDate() : undefined
}
const buildHref = (q: Query, page: number): string => {
const params = new URLSearchParams()
if (q.group) params.set('group', q.group)
if (q.parish) params.set('parish', q.parish)
if (q.from) params.set('from', q.from)
if (q.to) params.set('to', q.to)
if (page > 1) params.set('page', String(page))
const qs = params.toString()
return qs ? `/veranstaltungen?${qs}` : '/veranstaltungen'
}
export default async function EventsOverviewPage({
searchParams,
}: {
searchParams: Promise<Query>
}) {
const authenticated = await isAuthenticated()
const query = await searchParams
const fromDate = parseDate(query.from) ?? moment().startOf('day').toDate()
const toDate = parseDate(query.to)
const parsedPage = parseInt(query.page ?? '1', 10)
const page = Number.isFinite(parsedPage) && parsedPage > 0 ? parsedPage : 1
const [allGroups, allParishes, groupDoc, parishDoc] = await Promise.all([
fetchAllGroups(),
fetchAllParishes(),
query.group ? fetchGroup(query.group) : Promise.resolve(null),
query.parish ? fetchParish(query.parish) : Promise.resolve(null),
])
const paginated = await fetchUpcomingOccurrences({
limit: PAGE_SIZE,
page,
fromDate,
toDate,
groupId: groupDoc?.id,
parishId: parishDoc?.id,
})
if (!paginated) {
return <Error statusCode={503} message={'Veranstaltungen konnten nicht geladen werden.'} />
}
const events = transformOccurrences(paginated.docs)
const initial = {
group: groupDoc?.slug ?? undefined,
parish: parishDoc?.slug ?? undefined,
from: query.from && parseDate(query.from) ? query.from : undefined,
to: query.to && parseDate(query.to) ? query.to : undefined,
}
return (
<>
<Section paddingBottom={"small"}>
<Container>
<Title
title={`Veranstaltungen`}
size={"lg"}
color={"contrast"}
/>
<P width={"3/4"}>
Entdecken Sie unsere kommenden Veranstaltungen und seien Sie dabei! Hier finden Sie alle Termine, Informationen und Highlights auf einen Blick.
</P>
<EventFilterBar
groups={allGroups.docs.map((g) => ({ slug: g.slug, name: g.name }))}
parishes={allParishes.docs.map((p) => ({ slug: p.slug, name: p.name }))}
initial={initial}
/>
</Container>
<HR />
</Section>
<Section padding={'small'} paddingBottom={'large'}>
<Container>
{events.map((e) => (
<EventRow
key={e.id}
date={e.date}
end={e.end}
title={e.title}
href={e.href}
location={e.location}
cancelled={e.cancelled}
/>
))}
{events.length === 0 && <p>Keine Veranstaltungen gefunden</p>}
</Container>
</Section>
<AdminMenu collection={'event'} isAuthenticated={authenticated} />
{(paginated.hasPrevPage || paginated.hasNextPage) && (
<Section padding={'small'}>
<NextPrevButtons
prev={
paginated.hasPrevPage && paginated.prevPage
? { href: buildHref(query, paginated.prevPage), text: 'Vorige Seite' }
: undefined
}
next={
paginated.hasNextPage && paginated.nextPage
? { href: buildHref(query, paginated.nextPage), text: 'Nächste Seite' }
: undefined
}
/>
</Section>
)}
</>
)
}