--- import { z } from 'astro/zod' import { Icon } from 'astro-icon/components' import { orderBy } from 'lodash-es' import Button from '../components/Button.astro' import FormatTimeInterval from '../components/FormatTimeInterval.astro' import MyPicture from '../components/MyPicture.astro' import TimeFormatted from '../components/TimeFormatted.astro' import { eventTypes, eventTypesZodEnumBySlug, getEventTypeInfo, getEventTypeInfoBySlug, } from '../constants/eventTypes' import { getServiceVisibilityInfo } from '../constants/serviceVisibility' import { getVerificationStatusInfo } from '../constants/verificationStatus' import BaseLayout from '../layouts/BaseLayout.astro' import { cn } from '../lib/cn' import { zodParseQueryParamsStoringErrors } from '../lib/parseUrlFilters' import { prisma } from '../lib/prisma' import { formatDateShort } from '../lib/timeAgo' import { createPageUrl } from '../lib/urls' import type { Prisma } from '@prisma/client' const PAGE_SIZE = 100 const { data: params, hasDefaultData: hasDefaultFilters } = zodParseQueryParamsStoringErrors( { page: z.coerce.number().int().min(1).default(1), now: z.coerce.date().default(new Date()), from: z.preprocess((val) => (val === '' ? undefined : val), z.coerce.date().optional()), to: z.preprocess((val) => (val === '' ? undefined : val), z.coerce.date().optional()), /** Service's slug */ service: z.string().optional(), type: eventTypesZodEnumBySlug.optional(), }, Astro ) const [services, [dbEvents, totalEvents]] = await Astro.locals.banners.tryMany([ [ 'Error fetching services', async () => prisma.service.findMany({ where: { serviceVisibility: { in: ['PUBLIC', 'ARCHIVED'] }, }, select: { id: true, slug: true, name: true, imageUrl: true, verificationStatus: true, }, orderBy: { name: 'asc', }, }), [], ], [ 'Error fetching events', async () => prisma.event.findManyAndCount({ where: { visible: true, createdAt: { lte: params.now, }, service: { slug: params.service ?? undefined, serviceVisibility: { in: params.service ? ['PUBLIC', 'ARCHIVED', 'UNLISTED'] : ['PUBLIC', 'ARCHIVED'], }, }, type: params.type ? getEventTypeInfoBySlug(params.type).id : undefined, ...(params.from || params.to ? { OR: [ ...(params.from ? ([ { endedAt: null }, { endedAt: { gte: params.from } }, ] satisfies Prisma.EventWhereInput[]) : []), ...(params.to ? ([{ startedAt: { lte: params.to } }] satisfies Prisma.EventWhereInput[]) : []), ], } : {}), }, select: { id: true, title: true, content: true, source: true, type: true, startedAt: true, endedAt: true, service: { select: { id: true, slug: true, name: true, imageUrl: true, verificationStatus: true, serviceVisibility: true, }, }, }, orderBy: { startedAt: 'desc', }, skip: (params.page - 1) * PAGE_SIZE, take: PAGE_SIZE, }), [[], 0] as const, ], ]) const events = orderBy( dbEvents.map((event) => ({ ...event, actualEndedAt: event.endedAt ?? params.now, typeInfo: getEventTypeInfo(event.type), service: { ...event.service, verificationStatusInfo: getVerificationStatusInfo(event.service.verificationStatus), serviceVisibilityInfo: getServiceVisibilityInfo(event.service.serviceVisibility), }, })), ['actualEndedAt', 'startedAt'], 'desc' ) const totalPages = Math.ceil(totalEvents / PAGE_SIZE) || 1 const hasMorePages = params.page < totalPages const createUrlWithoutFilter = (paramName: keyof typeof params) => { const url = new URL(Astro.url) url.searchParams.delete(paramName) url.searchParams.forEach((value, key) => { if (value === '') { url.searchParams.delete(key) } }) return url.toString() } ---

Service Events Timeline

FILTERS

Clear all