Files
seminarhof-e2e-mrffdsce/packages/functions/src/functions/get-events-listing.function.ts
2026-07-10 23:06:04 +02:00

103 lines
2.9 KiB
TypeScript

import { z } from 'zod'
import { pikkuSessionlessFunc } from '#pikku'
import { BookingZ } from '#pikku/db/zod.gen.js'
export const GetEventsListingInput = z.object({
venueSlug: z.string().default('drawehn'),
filter: z.enum(['this_year', 'next_year', 'all']).default('all'),
search: z.string().optional(),
})
const Card = BookingZ
.pick({
bookingId: true,
eventName: true,
eventOutline: true,
description: true,
coverImageUrl: true,
organiserWebsite: true,
})
.extend({
startDate: z.date(),
endDate: z.date(),
clientName: z.string().nullable(),
})
export const GetEventsListingOutput = z.object({
events: z.array(Card),
})
export const getEventsListing = pikkuSessionlessFunc({
expose: true,
description: 'Public events listing — opted-in bookings only.',
input: GetEventsListingInput,
output: GetEventsListingOutput,
func: async ({ kysely }, { venueSlug, filter, search }) => {
const venue = await kysely
.selectFrom('venue')
.where('slug', '=', venueSlug)
.select('venueId')
.executeTakeFirstOrThrow()
const today = new Date().toISOString().slice(0, 10)
const year = Number(today.slice(0, 4))
let q = kysely
.selectFrom('booking')
.innerJoin('client', 'client.clientId', 'booking.clientId')
.where('booking.venueId', '=', venue.venueId)
.where('booking.onlineAd', '=', 1)
.where('booking.status', 'not in', ['cancelled', 'enquiry'])
.where('booking.endDate', '>=', today)
if (filter === 'this_year') {
q = q.where('booking.startDate', '<=', `${year}-12-31`)
} else if (filter === 'next_year') {
q = q.where('booking.startDate', '>=', `${year + 1}-01-01`)
.where('booking.startDate', '<=', `${year + 1}-12-31`)
}
if (search?.trim()) {
const term = `%${search.trim()}%`
q = q.where((eb) =>
eb.or([
eb('booking.eventName', 'like', term),
eb('client.name', 'like', term),
]),
)
}
const rows = await q
.orderBy('booking.startDate', 'asc')
.select([
'booking.bookingId',
'booking.eventName',
'booking.startDate',
'booking.endDate',
'booking.eventOutline',
'booking.description',
'booking.coverImageUrl',
'booking.organiserWebsite',
'client.name as clientName',
])
.execute()
const events = rows
.filter((r): r is typeof r & { startDate: string; endDate: string } =>
r.startDate != null && r.endDate != null,
)
.map((r) => ({
bookingId: r.bookingId,
eventName: r.eventName,
startDate: new Date(r.startDate),
endDate: new Date(r.endDate),
eventOutline: r.eventOutline,
description: r.description,
coverImageUrl: r.coverImageUrl,
organiserWebsite: r.organiserWebsite,
clientName: r.clientName,
}))
return { events }
},
})