From ff0f3846e9303c16fc055ba74ad853d84420c634 Mon Sep 17 00:00:00 2001 From: Jonas Braathen Date: Thu, 21 Nov 2024 22:04:20 +0100 Subject: [PATCH] web: add api route for compact event listing for app --- web/.env | 1 + web/src/app/api/v1/events/route.ts | 93 ++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 web/src/app/api/v1/events/route.ts diff --git a/web/.env b/web/.env index 9ff6a64..e12c1d2 100644 --- a/web/.env +++ b/web/.env @@ -1 +1,2 @@ GRAPHQL_ENDPOINT=https://cms.neuf.no/api/graphql/ +URL=http://localhost:3000 diff --git a/web/src/app/api/v1/events/route.ts b/web/src/app/api/v1/events/route.ts new file mode 100644 index 0000000..bbf4bc1 --- /dev/null +++ b/web/src/app/api/v1/events/route.ts @@ -0,0 +1,93 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getClient } from "@/app/client"; +import { + eventsOverviewQuery, + getSingularEvents, + getFutureOccurrences, + EventFragment, + EventCategory, + EventOrganizer, +} from "@/lib/event"; +import { VenueFragment } from "@/gql/graphql"; + +type CompactEvent = { + id: string; + slug: string; + title: string; + subtitle: string; + nextOccurrence: { + id: string; + start: string; + end?: string; + venue: { + id: string; + slug: string; + title: string; + preposition: string; + url: string; + }; + }; +}; + +type ResponseData = { + events: CompactEvent[]; + total: number; +}; + +const whitelistFilter = (obj: Record, whitelist: string[]) => + Object.entries(obj) + .filter(([key, value]) => whitelist.includes(key)) + .reduce( + (obj: Record, [key, value]) => ((obj[key] = value), obj), + {} + ); + +export async function GET(req: NextRequest, res: NextResponse) { + const searchParams = req.nextUrl.searchParams; + const view = searchParams.get("view"); + + if (view !== "compact-app") { + return NextResponse.json( + { error: "must provide valid view parameter" }, + { status: 400 } + ); + } + + const { data, error } = await getClient().query(eventsOverviewQuery, {}); + if (error) { + throw new Error(error.message); + } + if ( + !data?.index || + !data?.events?.futureEvents || + !data?.eventCategories || + !data?.eventOrganizers || + !data?.venues + ) { + throw new Error("Failed to fetch events"); + } + + const futureEvents = (data?.events?.futureEvents ?? []) as EventFragment[]; + const eventCategories = (data?.eventCategories ?? []) as EventCategory[]; + const eventOrganizers = (data?.eventOrganizers ?? []) as EventOrganizer[]; + const venues = (data?.venues ?? []) as VenueFragment[]; + + const keepKeys = ["id", "slug", "title", "subtitle", "occurrence"]; + const compactEvents = futureEvents.map((event) => { + const futureOccurrences = getFutureOccurrences(event); + const nextOccurrence = futureOccurrences.length + ? futureOccurrences[0] + : null; + + return { + url: `${process.env.URL}/arrangementer/${event.slug}`, + nextOccurrence: nextOccurrence, + ...whitelistFilter(event, keepKeys), + }; + }); + + return NextResponse.json( + { events: compactEvents, total: compactEvents.length }, + { status: 200 } + ); +}