feature: cache events

This commit is contained in:
Benno Tielen 2026-06-24 14:24:51 +02:00
parent ba2721fbea
commit bff425c3bd
2 changed files with 112 additions and 55 deletions

View file

@ -32,7 +32,7 @@ export async function EventsBlock({
<Title color={'contrast'} title={title || 'Veranstaltungen'} /> <Title color={'contrast'} title={title || 'Veranstaltungen'} />
<Events <Events
events={transformOccurrences(occurrenceDocs)} events={transformOccurrences(occurrenceDocs)}
n={itemsPerPage || 6} n={6}
schema={'contrast'} schema={'contrast'}
/> />
</Section> </Section>

View file

@ -1,7 +1,10 @@
import { getPayload, PaginatedDocs } from 'payload' import { getPayload, PaginatedDocs } from 'payload'
import { unstable_cache } from 'next/cache'
import config from '@/payload.config' import config from '@/payload.config'
import { EventOccurrence } from '@/payload-types' import { EventOccurrence } from '@/payload-types'
const CACHE_TTL = 300 // 5 minutes
type ListArgs = { type ListArgs = {
parishId?: string parishId?: string
groupId?: string groupId?: string
@ -12,32 +15,41 @@ type ListArgs = {
toDate?: Date toDate?: Date
} }
// Resolved args use ISO strings so they serialize into a stable cache key.
type ResolvedArgs = {
parishId?: string
groupId?: string
eventId?: string
limit: number
page: number
fromDate?: string
toDate?: string
}
// Round down to the cache window so a default `new Date()` (millisecond
// precision) produces a stable key for the duration of the TTL.
function roundDownToTtl(date: Date): Date {
const ms = CACHE_TTL * 1000
return new Date(Math.floor(date.getTime() / ms) * ms)
}
/** /**
* Fetch upcoming event occurrences, joined to their parent event. Always * Fetch upcoming event occurrences, joined to their parent event. Always
* filters to occurrences whose parent event is published. * filters to occurrences whose parent event is published.
*/ */
export async function fetchUpcomingOccurrences( const getUpcomingOccurrences = unstable_cache(
args?: ListArgs, async (args: ResolvedArgs): Promise<PaginatedDocs<EventOccurrence>> => {
): Promise<PaginatedDocs<EventOccurrence>> { const { parishId, groupId, eventId, limit, page, fromDate, toDate } = args
const {
parishId,
groupId,
eventId,
limit = 30,
page = 0,
fromDate = new Date(),
toDate,
} = args || {}
const query: any = { const query: any = {
and: [ and: [
{ date: { greater_than_equal: fromDate.toISOString() } }, { date: { greater_than_equal: fromDate } },
{ 'event._status': { equals: 'published' } }, { 'event._status': { equals: 'published' } },
], ],
} }
if (toDate) { if (toDate) {
query.and.push({ date: { less_than: toDate.toISOString() } }) query.and.push({ date: { less_than: toDate } })
} }
if (eventId) { if (eventId) {
query.and.push({ event: { equals: eventId } }) query.and.push({ event: { equals: eventId } })
@ -58,13 +70,12 @@ export async function fetchUpcomingOccurrences(
limit, limit,
page, page,
}) as Promise<PaginatedDocs<EventOccurrence>> }) as Promise<PaginatedDocs<EventOccurrence>>
} },
['fetchUpcomingOccurrences'],
{ revalidate: CACHE_TTL },
)
/** export async function fetchUpcomingOccurrences(
* Fetch past event occurrences (most recent first), joined to their parent
* event. Always filters to occurrences whose parent event is published.
*/
export async function fetchPastOccurrences(
args?: ListArgs, args?: ListArgs,
): Promise<PaginatedDocs<EventOccurrence>> { ): Promise<PaginatedDocs<EventOccurrence>> {
const { const {
@ -73,19 +84,38 @@ export async function fetchPastOccurrences(
eventId, eventId,
limit = 30, limit = 30,
page = 0, page = 0,
fromDate, fromDate = new Date(),
toDate = new Date(), toDate,
} = args || {} } = args || {}
return getUpcomingOccurrences({
parishId,
groupId,
eventId,
limit,
page,
fromDate: roundDownToTtl(fromDate).toISOString(),
toDate: toDate?.toISOString(),
})
}
/**
* Fetch past event occurrences (most recent first), joined to their parent
* event. Always filters to occurrences whose parent event is published.
*/
const getPastOccurrences = unstable_cache(
async (args: ResolvedArgs): Promise<PaginatedDocs<EventOccurrence>> => {
const { parishId, groupId, eventId, limit, page, fromDate, toDate } = args
const query: any = { const query: any = {
and: [ and: [
{ date: { less_than: toDate.toISOString() } }, { date: { less_than: toDate } },
{ 'event._status': { equals: 'published' } }, { 'event._status': { equals: 'published' } },
], ],
} }
if (fromDate) { if (fromDate) {
query.and.push({ date: { greater_than_equal: fromDate.toISOString() } }) query.and.push({ date: { greater_than_equal: fromDate } })
} }
if (eventId) { if (eventId) {
query.and.push({ event: { equals: eventId } }) query.and.push({ event: { equals: eventId } })
@ -106,6 +136,33 @@ export async function fetchPastOccurrences(
limit, limit,
page, page,
}) as Promise<PaginatedDocs<EventOccurrence>> }) as Promise<PaginatedDocs<EventOccurrence>>
},
['fetchPastOccurrences'],
{ revalidate: CACHE_TTL },
)
export async function fetchPastOccurrences(
args?: ListArgs,
): Promise<PaginatedDocs<EventOccurrence>> {
const {
parishId,
groupId,
eventId,
limit = 30,
page = 0,
fromDate,
toDate = new Date(),
} = args || {}
return getPastOccurrences({
parishId,
groupId,
eventId,
limit,
page,
fromDate: fromDate?.toISOString(),
toDate: roundDownToTtl(toDate).toISOString(),
})
} }
/** /**