Compare commits
3 Commits
337407c771
...
e4c0558527
| Author | SHA1 | Date | |
|---|---|---|---|
| e4c0558527 | |||
| 80b9cdbc33 | |||
| 154338057d |
+18
-2
@@ -1,7 +1,7 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Min, Q, UniqueConstraint
|
from django.db.models import Min, Prefetch, Q, UniqueConstraint
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.html import mark_safe
|
from django.utils.html import mark_safe
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@@ -45,7 +45,23 @@ class EventIndex(HeadlessMixin, Page):
|
|||||||
subpage_types = ["events.EventPage"]
|
subpage_types = ["events.EventPage"]
|
||||||
|
|
||||||
def future_events(self, info, **kwargs):
|
def future_events(self, info, **kwargs):
|
||||||
return EventPage.objects.live().future().order_by("next_occurrence")
|
return (
|
||||||
|
EventPage.objects.live()
|
||||||
|
.future()
|
||||||
|
.order_by("next_occurrence")
|
||||||
|
.select_related("featured_image")
|
||||||
|
.prefetch_related(
|
||||||
|
Prefetch(
|
||||||
|
"occurrences",
|
||||||
|
queryset=EventOccurrence.objects.select_related("venue"),
|
||||||
|
),
|
||||||
|
"categories",
|
||||||
|
Prefetch(
|
||||||
|
"organizers",
|
||||||
|
queryset=EventOrganizer.objects.select_related("association"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
graphql_fields = [
|
graphql_fields = [
|
||||||
GraphQLCollection(
|
GraphQLCollection(
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ from datetime import datetime, timedelta
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.db import connection
|
||||||
|
from django.test.utils import CaptureQueriesContext
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from events.admin import EventDateColumn, OrganizersColumn
|
from events.admin import EventDateColumn, OrganizersColumn
|
||||||
@@ -188,6 +190,64 @@ def test_graphql_event_index_future_events_query(event_index, graphql_post):
|
|||||||
assert "Upcoming gig" in titles
|
assert "Upcoming gig" in titles
|
||||||
|
|
||||||
|
|
||||||
|
def test_future_events_does_not_have_n_plus_one_queries(
|
||||||
|
event_index, venue, association_index, graphql_post
|
||||||
|
):
|
||||||
|
"""Regression test: query count for futureEvents stays bounded as events grow."""
|
||||||
|
konsert = EventCategory.objects.create(name="Konsert", slug="konsert")
|
||||||
|
association = AssociationPageFactory(parent=association_index, title="DNS")
|
||||||
|
org = EventOrganizer.objects.create(name="Forening", slug="forening", association=association)
|
||||||
|
image = CustomImageFactory(title="Cover")
|
||||||
|
now = timezone.now()
|
||||||
|
|
||||||
|
for i in range(5):
|
||||||
|
event = EventPageFactory(
|
||||||
|
parent=event_index,
|
||||||
|
title=f"Event {i}",
|
||||||
|
body=[("paragraph", "<p>x</p>")],
|
||||||
|
featured_image=image,
|
||||||
|
)
|
||||||
|
event.categories.add(konsert)
|
||||||
|
EventOrganizerLink.objects.create(event=event, organizer=org)
|
||||||
|
EventOccurrence.objects.create(
|
||||||
|
event=event,
|
||||||
|
start=now + timedelta(days=i + 1),
|
||||||
|
venue=venue,
|
||||||
|
)
|
||||||
|
|
||||||
|
home_query = """
|
||||||
|
query {
|
||||||
|
eventIndex {
|
||||||
|
futureEvents {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
subtitle
|
||||||
|
body { blockType }
|
||||||
|
featuredImage { url }
|
||||||
|
occurrences { start end venueCustom venue { title } }
|
||||||
|
categories { name slug }
|
||||||
|
organizers { name slug association { title } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
with CaptureQueriesContext(connection) as ctx:
|
||||||
|
response, body = graphql_post(home_query)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "errors" not in body, body
|
||||||
|
assert len(body["data"]["eventIndex"]["futureEvents"]) == 5
|
||||||
|
|
||||||
|
# Bump only alongside an intentional resolver change.
|
||||||
|
max_queries = 6
|
||||||
|
assert len(ctx) <= max_queries, (
|
||||||
|
f"futureEvents took {len(ctx)} queries for 5 events — likely N+1. "
|
||||||
|
f"Captured queries:\n"
|
||||||
|
+ "\n".join(f" {i + 1}. {q['sql'][:120]}" for i, q in enumerate(ctx.captured_queries))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_graphql_event_index_future_events_ordered_by_next_occurrence(event_index, graphql_post):
|
def test_graphql_event_index_future_events_ordered_by_next_occurrence(event_index, graphql_post):
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export default function RootLayout({
|
|||||||
return (
|
return (
|
||||||
<html lang="no">
|
<html lang="no">
|
||||||
<head>
|
<head>
|
||||||
|
<link rel="preconnect" href="https://use.typekit.net" crossOrigin="anonymous" />
|
||||||
<link rel="stylesheet" href="https://use.typekit.net/spa5smt.css" />
|
<link rel="stylesheet" href="https://use.typekit.net/spa5smt.css" />
|
||||||
{process.env.UMAMI_SCRIPT_URL && process.env.UMAMI_WEBSITE_ID && (
|
{process.env.UMAMI_SCRIPT_URL && process.env.UMAMI_WEBSITE_ID && (
|
||||||
<script
|
<script
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Image } from "@/components/general/Image";
|
|||||||
import {
|
import {
|
||||||
SingularEvent,
|
SingularEvent,
|
||||||
EventFragment,
|
EventFragment,
|
||||||
|
EventListItemFragment,
|
||||||
getFutureOccurrences,
|
getFutureOccurrences,
|
||||||
} from "@/lib/event";
|
} from "@/lib/event";
|
||||||
import {
|
import {
|
||||||
@@ -22,7 +23,11 @@ export const EventItem = ({
|
|||||||
size,
|
size,
|
||||||
imageLoading,
|
imageLoading,
|
||||||
}: {
|
}: {
|
||||||
event: SingularEvent | EventFragment;
|
event:
|
||||||
|
| SingularEvent
|
||||||
|
| SingularEvent<EventListItemFragment>
|
||||||
|
| EventFragment
|
||||||
|
| EventListItemFragment;
|
||||||
mode: "list" | "calendar" | "singular-time-only";
|
mode: "list" | "calendar" | "singular-time-only";
|
||||||
size?: "small" | "medium" | "large";
|
size?: "small" | "medium" | "large";
|
||||||
imageLoading?: "eager" | "lazy";
|
imageLoading?: "eager" | "lazy";
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { EventFragment } from "@/gql/graphql";
|
import { EventListItemFragment } from "@/gql/graphql";
|
||||||
import { EventItem } from "./EventItem";
|
import { EventItem } from "./EventItem";
|
||||||
import styles from "./featuredEvents.module.scss";
|
import styles from "./featuredEvents.module.scss";
|
||||||
import { SectionHeader } from "../general/SectionHeader";
|
import { SectionHeader } from "../general/SectionHeader";
|
||||||
import { SectionFooter } from "../general/SectionFooter";
|
import { SectionFooter } from "../general/SectionFooter";
|
||||||
|
|
||||||
export const FeaturedEvents = ({ events }: { events: EventFragment[] }) => {
|
export const FeaturedEvents = ({ events }: { events: EventListItemFragment[] }) => {
|
||||||
return (
|
return (
|
||||||
<section className={styles.featuredEvents}>
|
<section className={styles.featuredEvents}>
|
||||||
<SectionHeader heading="Arrangementer" link="/arrangementer" linkText="Se alle arrangementer" />
|
<SectionHeader heading="Arrangementer" link="/arrangementer" linkText="Se alle arrangementer" />
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
import { EventFragment } from "@/gql/graphql";
|
import { EventListItemFragment } from "@/gql/graphql";
|
||||||
import { isTodayOrFuture, formatDate } from "@/lib/date";
|
import { isTodayOrFuture } from "@/lib/date";
|
||||||
import { parse } from "date-fns";
|
|
||||||
import {
|
import {
|
||||||
getSingularEvents,
|
getSingularEvents,
|
||||||
organizeEventsByDate,
|
organizeEventsByDate,
|
||||||
sortSingularEvents,
|
sortSingularEvents,
|
||||||
} from "@/lib/event";
|
} from "@/lib/event";
|
||||||
import Link from "next/link";
|
|
||||||
import { EventItem } from "./EventItem";
|
import { EventItem } from "./EventItem";
|
||||||
import styles from "./upcomingEvents.module.scss";
|
import styles from "./upcomingEvents.module.scss";
|
||||||
import { SectionHeader } from "../general/SectionHeader";
|
import { SectionHeader } from "../general/SectionHeader";
|
||||||
import { SectionFooter } from "../general/SectionFooter";
|
import { SectionFooter } from "../general/SectionFooter";
|
||||||
|
|
||||||
export const UpcomingEvents = ({ events }: { events: EventFragment[] }) => {
|
export const UpcomingEvents = ({ events }: { events: EventListItemFragment[] }) => {
|
||||||
const upcomingSingularEvents = sortSingularEvents(
|
const upcomingSingularEvents = sortSingularEvents(
|
||||||
getSingularEvents(events).filter((event) =>
|
getSingularEvents(events).filter((event) =>
|
||||||
isTodayOrFuture(event.occurrence.start)
|
isTodayOrFuture(event.occurrence.start)
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import Link from "next/link";
|
|||||||
import { graphql } from "@/gql";
|
import { graphql } from "@/gql";
|
||||||
import { HomeFragment } from "@/gql/graphql";
|
import { HomeFragment } from "@/gql/graphql";
|
||||||
import { getClient } from "@/app/client";
|
import { getClient } from "@/app/client";
|
||||||
import { EventFragment } from "@/lib/event";
|
import { EventListItemFragment } from "@/lib/event";
|
||||||
import { NewsFragment } from "@/lib/news";
|
import { NewsListItemFragment } from "@/lib/news";
|
||||||
import { FeaturedEvents } from "@/components/events/FeaturedEvents";
|
import { FeaturedEvents } from "@/components/events/FeaturedEvents";
|
||||||
import { UpcomingEvents } from "@/components/events/UpcomingEvents";
|
import { UpcomingEvents } from "@/components/events/UpcomingEvents";
|
||||||
import { Icon } from "@/components/general/Icon";
|
import { Icon } from "@/components/general/Icon";
|
||||||
@@ -28,7 +28,7 @@ const homeQuery = graphql(`
|
|||||||
... on EventIndex {
|
... on EventIndex {
|
||||||
futureEvents {
|
futureEvents {
|
||||||
... on EventPage {
|
... on EventPage {
|
||||||
...Event
|
...EventListItem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ const homeQuery = graphql(`
|
|||||||
}
|
}
|
||||||
news: pages(contentType: "news.newsPage", order: "-first_published_at", limit: 4) {
|
news: pages(contentType: "news.newsPage", order: "-first_published_at", limit: 4) {
|
||||||
... on NewsPage {
|
... on NewsPage {
|
||||||
...News
|
...NewsListItem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,8 +48,8 @@ const homeQuery = graphql(`
|
|||||||
|
|
||||||
export type HomePageViewProps = {
|
export type HomePageViewProps = {
|
||||||
home: HomeFragment;
|
home: HomeFragment;
|
||||||
events: EventFragment[];
|
events: EventListItemFragment[];
|
||||||
news: NewsFragment[];
|
news: NewsListItemFragment[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function loadHomePageProps(overrides?: {
|
export async function loadHomePageProps(overrides?: {
|
||||||
@@ -59,8 +59,8 @@ export async function loadHomePageProps(overrides?: {
|
|||||||
if (error) throw new Error(error.message);
|
if (error) throw new Error(error.message);
|
||||||
const home = overrides?.homeOverride ?? (data?.home as HomeFragment | undefined);
|
const home = overrides?.homeOverride ?? (data?.home as HomeFragment | undefined);
|
||||||
if (!home) throw new Error("Failed to load /");
|
if (!home) throw new Error("Failed to load /");
|
||||||
const events = (data?.events?.futureEvents ?? []) as EventFragment[];
|
const events = (data?.events?.futureEvents ?? []) as EventListItemFragment[];
|
||||||
const news = (data?.news ?? []) as NewsFragment[];
|
const news = (data?.news ?? []) as NewsListItemFragment[];
|
||||||
return { home, events, news };
|
return { home, events, news };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import styles from "./newsItem.module.scss";
|
import styles from "./newsItem.module.scss";
|
||||||
import { Image } from "@/components/general/Image";
|
import { Image } from "@/components/general/Image";
|
||||||
import { NewsFragment } from "@/lib/news";
|
import { NewsFragment, NewsListItemFragment } from "@/lib/news";
|
||||||
import { formatDate } from "@/lib/date";
|
import { formatDate } from "@/lib/date";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
export const NewsItem = ({ news }: { news: NewsFragment }) => {
|
export const NewsItem = ({ news }: { news: NewsFragment | NewsListItemFragment }) => {
|
||||||
const featuredImage: any = news.featuredImage;
|
const featuredImage: any = news.featuredImage;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useState } from "react";
|
|||||||
import { SectionHeader } from "../general/SectionHeader";
|
import { SectionHeader } from "../general/SectionHeader";
|
||||||
import { NewsItem } from "./NewsItem";
|
import { NewsItem } from "./NewsItem";
|
||||||
import styles from "./newsList.module.scss";
|
import styles from "./newsList.module.scss";
|
||||||
import { NewsFragment } from "@/lib/news";
|
import { NewsFragment, NewsListItemFragment } from "@/lib/news";
|
||||||
import { SectionFooter } from "../general/SectionFooter";
|
import { SectionFooter } from "../general/SectionFooter";
|
||||||
|
|
||||||
export const NewsList = ({
|
export const NewsList = ({
|
||||||
@@ -11,7 +11,7 @@ export const NewsList = ({
|
|||||||
heading,
|
heading,
|
||||||
featured
|
featured
|
||||||
}: {
|
}: {
|
||||||
news: NewsFragment[];
|
news: (NewsFragment | NewsListItemFragment)[];
|
||||||
heading?: string;
|
heading?: string;
|
||||||
featured?: boolean;
|
featured?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
|
|||||||
+15
-3
@@ -45,7 +45,7 @@ type Documents = {
|
|||||||
"\n fragment Generic on GenericPage {\n __typename\n id\n urlPath\n seoTitle\n searchDescription\n title\n lead\n pig\n body {\n ...Blocks\n }\n }\n": typeof types.GenericFragmentDoc,
|
"\n fragment Generic on GenericPage {\n __typename\n id\n urlPath\n seoTitle\n searchDescription\n title\n lead\n pig\n body {\n ...Blocks\n }\n }\n": typeof types.GenericFragmentDoc,
|
||||||
"\n query genericPageByUrl($urlPath: String!) {\n page: page(contentType: \"generic.GenericPage\", urlPath: $urlPath) {\n ... on GenericPage {\n ...Generic\n }\n }\n }\n": typeof types.GenericPageByUrlDocument,
|
"\n query genericPageByUrl($urlPath: String!) {\n page: page(contentType: \"generic.GenericPage\", urlPath: $urlPath) {\n ... on GenericPage {\n ...Generic\n }\n }\n }\n": typeof types.GenericPageByUrlDocument,
|
||||||
"\n fragment Home on HomePage {\n __typename\n featuredEvents {\n id\n }\n }\n": typeof types.HomeFragmentDoc,
|
"\n fragment Home on HomePage {\n __typename\n featuredEvents {\n id\n }\n }\n": typeof types.HomeFragmentDoc,
|
||||||
"\n query home {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n home: page(contentType: \"home.HomePage\", urlPath: \"/home/\") {\n ... on HomePage {\n ...Home\n }\n }\n news: pages(contentType: \"news.newsPage\", order: \"-first_published_at\", limit: 4) {\n ... on NewsPage {\n ...News\n }\n }\n }\n": typeof types.HomeDocument,
|
"\n query home {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...EventListItem\n }\n }\n }\n }\n home: page(contentType: \"home.HomePage\", urlPath: \"/home/\") {\n ... on HomePage {\n ...Home\n }\n }\n news: pages(contentType: \"news.newsPage\", order: \"-first_published_at\", limit: 4) {\n ... on NewsPage {\n ...NewsListItem\n }\n }\n }\n": typeof types.HomeDocument,
|
||||||
"\n query newsBySlug($slug: String!) {\n news: page(contentType: \"news.NewsPage\", slug: $slug) {\n ... on NewsPage {\n ...News\n }\n }\n }\n": typeof types.NewsBySlugDocument,
|
"\n query newsBySlug($slug: String!) {\n news: page(contentType: \"news.NewsPage\", slug: $slug) {\n ... on NewsPage {\n ...News\n }\n }\n }\n": typeof types.NewsBySlugDocument,
|
||||||
"\n fragment Sponsor on SponsorBlock {\n id\n name\n logo {\n ...Image\n }\n text\n website\n }\n": typeof types.SponsorFragmentDoc,
|
"\n fragment Sponsor on SponsorBlock {\n id\n name\n logo {\n ...Image\n }\n text\n website\n }\n": typeof types.SponsorFragmentDoc,
|
||||||
"\n fragment SponsorsPage on SponsorsPage {\n __typename\n title\n seoTitle\n searchDescription\n lead\n body {\n ...Blocks\n }\n sponsors {\n ... on SponsorBlock {\n ...Sponsor\n }\n }\n }\n": typeof types.SponsorsPageFragmentDoc,
|
"\n fragment SponsorsPage on SponsorsPage {\n __typename\n title\n seoTitle\n searchDescription\n lead\n body {\n ...Blocks\n }\n sponsors {\n ... on SponsorBlock {\n ...Sponsor\n }\n }\n }\n": typeof types.SponsorsPageFragmentDoc,
|
||||||
@@ -65,10 +65,12 @@ type Documents = {
|
|||||||
"\n fragment ContactEntity on ContactEntity {\n id\n name\n contactType\n title\n email\n phoneNumber\n image {\n ...Image\n }\n }\n": typeof types.ContactEntityFragmentDoc,
|
"\n fragment ContactEntity on ContactEntity {\n id\n name\n contactType\n title\n email\n phoneNumber\n image {\n ...Image\n }\n }\n": typeof types.ContactEntityFragmentDoc,
|
||||||
"\n fragment EventCategory on EventCategory {\n __typename\n name\n slug\n pig\n showInFilters\n }\n": typeof types.EventCategoryFragmentDoc,
|
"\n fragment EventCategory on EventCategory {\n __typename\n name\n slug\n pig\n showInFilters\n }\n": typeof types.EventCategoryFragmentDoc,
|
||||||
"\n fragment EventOrganizer on EventOrganizer {\n __typename\n id\n name\n slug\n externalUrl\n association {\n ... on AssociationPage {\n url\n }\n }\n }\n": typeof types.EventOrganizerFragmentDoc,
|
"\n fragment EventOrganizer on EventOrganizer {\n __typename\n id\n name\n slug\n externalUrl\n association {\n ... on AssociationPage {\n url\n }\n }\n }\n": typeof types.EventOrganizerFragmentDoc,
|
||||||
|
"\n fragment EventListItem on EventPage {\n __typename\n id\n slug\n title\n subtitle\n featuredImage {\n ...Image\n }\n occurrences(limit: 5000) {\n ... on EventOccurrence {\n __typename\n id\n start\n end\n }\n }\n }\n": typeof types.EventListItemFragmentDoc,
|
||||||
"\n fragment Event on EventPage {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n subtitle\n lead\n body {\n ...OneLevelOfBlocks\n }\n featuredImage {\n ...Image\n }\n pig\n facebookUrl\n ticketUrl\n free\n priceRegular\n priceMember\n priceStudent\n categories {\n ... on EventCategory {\n ...EventCategory\n }\n }\n occurrences(limit: 5000) {\n ... on EventOccurrence {\n __typename\n id\n start\n end\n venue {\n __typename\n id\n slug\n title\n preposition\n url\n }\n venueCustom\n }\n }\n organizers {\n ... on EventOrganizer {\n ...EventOrganizer\n }\n }\n }\n": typeof types.EventFragmentDoc,
|
"\n fragment Event on EventPage {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n subtitle\n lead\n body {\n ...OneLevelOfBlocks\n }\n featuredImage {\n ...Image\n }\n pig\n facebookUrl\n ticketUrl\n free\n priceRegular\n priceMember\n priceStudent\n categories {\n ... on EventCategory {\n ...EventCategory\n }\n }\n occurrences(limit: 5000) {\n ... on EventOccurrence {\n __typename\n id\n start\n end\n venue {\n __typename\n id\n slug\n title\n preposition\n url\n }\n venueCustom\n }\n }\n organizers {\n ... on EventOrganizer {\n ...EventOrganizer\n }\n }\n }\n": typeof types.EventFragmentDoc,
|
||||||
"\n fragment EventIndex on EventIndex {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n }\n": typeof types.EventIndexFragmentDoc,
|
"\n fragment EventIndex on EventIndex {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n }\n": typeof types.EventIndexFragmentDoc,
|
||||||
"\n query eventIndexMetadata {\n index: eventIndex {\n ... on EventIndex {\n ...EventIndex\n }\n }\n }\n": typeof types.EventIndexMetadataDocument,
|
"\n query eventIndexMetadata {\n index: eventIndex {\n ... on EventIndex {\n ...EventIndex\n }\n }\n }\n": typeof types.EventIndexMetadataDocument,
|
||||||
"\n query futureEvents {\n index: eventIndex {\n ... on EventIndex {\n ...EventIndex\n }\n }\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n eventCategories: eventCategories(limit: 5000) {\n ... on EventCategory {\n ...EventCategory\n }\n }\n eventOrganizers: eventOrganizers(limit: 5000) {\n ... on EventOrganizer {\n ...EventOrganizer\n }\n }\n venues: pages(contentType: \"venues.VenuePage\") {\n ... on VenuePage {\n id\n title\n slug\n preposition\n }\n }\n }\n": typeof types.FutureEventsDocument,
|
"\n query futureEvents {\n index: eventIndex {\n ... on EventIndex {\n ...EventIndex\n }\n }\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n eventCategories: eventCategories(limit: 5000) {\n ... on EventCategory {\n ...EventCategory\n }\n }\n eventOrganizers: eventOrganizers(limit: 5000) {\n ... on EventOrganizer {\n ...EventOrganizer\n }\n }\n venues: pages(contentType: \"venues.VenuePage\") {\n ... on VenuePage {\n id\n title\n slug\n preposition\n }\n }\n }\n": typeof types.FutureEventsDocument,
|
||||||
|
"\n fragment NewsListItem on NewsPage {\n __typename\n id\n slug\n title\n firstPublishedAt\n excerpt\n featuredImage {\n ...Image\n }\n }\n": typeof types.NewsListItemFragmentDoc,
|
||||||
"\n fragment News on NewsPage {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n firstPublishedAt\n excerpt\n lead\n featuredImage {\n ...Image\n }\n body {\n ...Blocks\n }\n }\n": typeof types.NewsFragmentDoc,
|
"\n fragment News on NewsPage {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n firstPublishedAt\n excerpt\n lead\n featuredImage {\n ...Image\n }\n body {\n ...Blocks\n }\n }\n": typeof types.NewsFragmentDoc,
|
||||||
"\n fragment NewsIndex on NewsIndex {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n lead\n }\n": typeof types.NewsIndexFragmentDoc,
|
"\n fragment NewsIndex on NewsIndex {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n lead\n }\n": typeof types.NewsIndexFragmentDoc,
|
||||||
"\n query news {\n index: newsIndex {\n ... on NewsIndex {\n ...NewsIndex\n }\n }\n news: pages(contentType: \"news.NewsPage\", order: \"-first_published_at\", limit: 1000) {\n ... on NewsPage {\n ...News\n }\n }\n }\n": typeof types.NewsDocument,
|
"\n query news {\n index: newsIndex {\n ... on NewsIndex {\n ...NewsIndex\n }\n }\n news: pages(contentType: \"news.NewsPage\", order: \"-first_published_at\", limit: 1000) {\n ... on NewsPage {\n ...News\n }\n }\n }\n": typeof types.NewsDocument,
|
||||||
@@ -109,7 +111,7 @@ const documents: Documents = {
|
|||||||
"\n fragment Generic on GenericPage {\n __typename\n id\n urlPath\n seoTitle\n searchDescription\n title\n lead\n pig\n body {\n ...Blocks\n }\n }\n": types.GenericFragmentDoc,
|
"\n fragment Generic on GenericPage {\n __typename\n id\n urlPath\n seoTitle\n searchDescription\n title\n lead\n pig\n body {\n ...Blocks\n }\n }\n": types.GenericFragmentDoc,
|
||||||
"\n query genericPageByUrl($urlPath: String!) {\n page: page(contentType: \"generic.GenericPage\", urlPath: $urlPath) {\n ... on GenericPage {\n ...Generic\n }\n }\n }\n": types.GenericPageByUrlDocument,
|
"\n query genericPageByUrl($urlPath: String!) {\n page: page(contentType: \"generic.GenericPage\", urlPath: $urlPath) {\n ... on GenericPage {\n ...Generic\n }\n }\n }\n": types.GenericPageByUrlDocument,
|
||||||
"\n fragment Home on HomePage {\n __typename\n featuredEvents {\n id\n }\n }\n": types.HomeFragmentDoc,
|
"\n fragment Home on HomePage {\n __typename\n featuredEvents {\n id\n }\n }\n": types.HomeFragmentDoc,
|
||||||
"\n query home {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n home: page(contentType: \"home.HomePage\", urlPath: \"/home/\") {\n ... on HomePage {\n ...Home\n }\n }\n news: pages(contentType: \"news.newsPage\", order: \"-first_published_at\", limit: 4) {\n ... on NewsPage {\n ...News\n }\n }\n }\n": types.HomeDocument,
|
"\n query home {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...EventListItem\n }\n }\n }\n }\n home: page(contentType: \"home.HomePage\", urlPath: \"/home/\") {\n ... on HomePage {\n ...Home\n }\n }\n news: pages(contentType: \"news.newsPage\", order: \"-first_published_at\", limit: 4) {\n ... on NewsPage {\n ...NewsListItem\n }\n }\n }\n": types.HomeDocument,
|
||||||
"\n query newsBySlug($slug: String!) {\n news: page(contentType: \"news.NewsPage\", slug: $slug) {\n ... on NewsPage {\n ...News\n }\n }\n }\n": types.NewsBySlugDocument,
|
"\n query newsBySlug($slug: String!) {\n news: page(contentType: \"news.NewsPage\", slug: $slug) {\n ... on NewsPage {\n ...News\n }\n }\n }\n": types.NewsBySlugDocument,
|
||||||
"\n fragment Sponsor on SponsorBlock {\n id\n name\n logo {\n ...Image\n }\n text\n website\n }\n": types.SponsorFragmentDoc,
|
"\n fragment Sponsor on SponsorBlock {\n id\n name\n logo {\n ...Image\n }\n text\n website\n }\n": types.SponsorFragmentDoc,
|
||||||
"\n fragment SponsorsPage on SponsorsPage {\n __typename\n title\n seoTitle\n searchDescription\n lead\n body {\n ...Blocks\n }\n sponsors {\n ... on SponsorBlock {\n ...Sponsor\n }\n }\n }\n": types.SponsorsPageFragmentDoc,
|
"\n fragment SponsorsPage on SponsorsPage {\n __typename\n title\n seoTitle\n searchDescription\n lead\n body {\n ...Blocks\n }\n sponsors {\n ... on SponsorBlock {\n ...Sponsor\n }\n }\n }\n": types.SponsorsPageFragmentDoc,
|
||||||
@@ -129,10 +131,12 @@ const documents: Documents = {
|
|||||||
"\n fragment ContactEntity on ContactEntity {\n id\n name\n contactType\n title\n email\n phoneNumber\n image {\n ...Image\n }\n }\n": types.ContactEntityFragmentDoc,
|
"\n fragment ContactEntity on ContactEntity {\n id\n name\n contactType\n title\n email\n phoneNumber\n image {\n ...Image\n }\n }\n": types.ContactEntityFragmentDoc,
|
||||||
"\n fragment EventCategory on EventCategory {\n __typename\n name\n slug\n pig\n showInFilters\n }\n": types.EventCategoryFragmentDoc,
|
"\n fragment EventCategory on EventCategory {\n __typename\n name\n slug\n pig\n showInFilters\n }\n": types.EventCategoryFragmentDoc,
|
||||||
"\n fragment EventOrganizer on EventOrganizer {\n __typename\n id\n name\n slug\n externalUrl\n association {\n ... on AssociationPage {\n url\n }\n }\n }\n": types.EventOrganizerFragmentDoc,
|
"\n fragment EventOrganizer on EventOrganizer {\n __typename\n id\n name\n slug\n externalUrl\n association {\n ... on AssociationPage {\n url\n }\n }\n }\n": types.EventOrganizerFragmentDoc,
|
||||||
|
"\n fragment EventListItem on EventPage {\n __typename\n id\n slug\n title\n subtitle\n featuredImage {\n ...Image\n }\n occurrences(limit: 5000) {\n ... on EventOccurrence {\n __typename\n id\n start\n end\n }\n }\n }\n": types.EventListItemFragmentDoc,
|
||||||
"\n fragment Event on EventPage {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n subtitle\n lead\n body {\n ...OneLevelOfBlocks\n }\n featuredImage {\n ...Image\n }\n pig\n facebookUrl\n ticketUrl\n free\n priceRegular\n priceMember\n priceStudent\n categories {\n ... on EventCategory {\n ...EventCategory\n }\n }\n occurrences(limit: 5000) {\n ... on EventOccurrence {\n __typename\n id\n start\n end\n venue {\n __typename\n id\n slug\n title\n preposition\n url\n }\n venueCustom\n }\n }\n organizers {\n ... on EventOrganizer {\n ...EventOrganizer\n }\n }\n }\n": types.EventFragmentDoc,
|
"\n fragment Event on EventPage {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n subtitle\n lead\n body {\n ...OneLevelOfBlocks\n }\n featuredImage {\n ...Image\n }\n pig\n facebookUrl\n ticketUrl\n free\n priceRegular\n priceMember\n priceStudent\n categories {\n ... on EventCategory {\n ...EventCategory\n }\n }\n occurrences(limit: 5000) {\n ... on EventOccurrence {\n __typename\n id\n start\n end\n venue {\n __typename\n id\n slug\n title\n preposition\n url\n }\n venueCustom\n }\n }\n organizers {\n ... on EventOrganizer {\n ...EventOrganizer\n }\n }\n }\n": types.EventFragmentDoc,
|
||||||
"\n fragment EventIndex on EventIndex {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n }\n": types.EventIndexFragmentDoc,
|
"\n fragment EventIndex on EventIndex {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n }\n": types.EventIndexFragmentDoc,
|
||||||
"\n query eventIndexMetadata {\n index: eventIndex {\n ... on EventIndex {\n ...EventIndex\n }\n }\n }\n": types.EventIndexMetadataDocument,
|
"\n query eventIndexMetadata {\n index: eventIndex {\n ... on EventIndex {\n ...EventIndex\n }\n }\n }\n": types.EventIndexMetadataDocument,
|
||||||
"\n query futureEvents {\n index: eventIndex {\n ... on EventIndex {\n ...EventIndex\n }\n }\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n eventCategories: eventCategories(limit: 5000) {\n ... on EventCategory {\n ...EventCategory\n }\n }\n eventOrganizers: eventOrganizers(limit: 5000) {\n ... on EventOrganizer {\n ...EventOrganizer\n }\n }\n venues: pages(contentType: \"venues.VenuePage\") {\n ... on VenuePage {\n id\n title\n slug\n preposition\n }\n }\n }\n": types.FutureEventsDocument,
|
"\n query futureEvents {\n index: eventIndex {\n ... on EventIndex {\n ...EventIndex\n }\n }\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n eventCategories: eventCategories(limit: 5000) {\n ... on EventCategory {\n ...EventCategory\n }\n }\n eventOrganizers: eventOrganizers(limit: 5000) {\n ... on EventOrganizer {\n ...EventOrganizer\n }\n }\n venues: pages(contentType: \"venues.VenuePage\") {\n ... on VenuePage {\n id\n title\n slug\n preposition\n }\n }\n }\n": types.FutureEventsDocument,
|
||||||
|
"\n fragment NewsListItem on NewsPage {\n __typename\n id\n slug\n title\n firstPublishedAt\n excerpt\n featuredImage {\n ...Image\n }\n }\n": types.NewsListItemFragmentDoc,
|
||||||
"\n fragment News on NewsPage {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n firstPublishedAt\n excerpt\n lead\n featuredImage {\n ...Image\n }\n body {\n ...Blocks\n }\n }\n": types.NewsFragmentDoc,
|
"\n fragment News on NewsPage {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n firstPublishedAt\n excerpt\n lead\n featuredImage {\n ...Image\n }\n body {\n ...Blocks\n }\n }\n": types.NewsFragmentDoc,
|
||||||
"\n fragment NewsIndex on NewsIndex {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n lead\n }\n": types.NewsIndexFragmentDoc,
|
"\n fragment NewsIndex on NewsIndex {\n __typename\n id\n slug\n seoTitle\n searchDescription\n title\n lead\n }\n": types.NewsIndexFragmentDoc,
|
||||||
"\n query news {\n index: newsIndex {\n ... on NewsIndex {\n ...NewsIndex\n }\n }\n news: pages(contentType: \"news.NewsPage\", order: \"-first_published_at\", limit: 1000) {\n ... on NewsPage {\n ...News\n }\n }\n }\n": types.NewsDocument,
|
"\n query news {\n index: newsIndex {\n ... on NewsIndex {\n ...NewsIndex\n }\n }\n news: pages(contentType: \"news.NewsPage\", order: \"-first_published_at\", limit: 1000) {\n ... on NewsPage {\n ...News\n }\n }\n }\n": types.NewsDocument,
|
||||||
@@ -283,7 +287,7 @@ export function graphql(source: "\n fragment Home on HomePage {\n __typename
|
|||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
export function graphql(source: "\n query home {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n home: page(contentType: \"home.HomePage\", urlPath: \"/home/\") {\n ... on HomePage {\n ...Home\n }\n }\n news: pages(contentType: \"news.newsPage\", order: \"-first_published_at\", limit: 4) {\n ... on NewsPage {\n ...News\n }\n }\n }\n"): (typeof documents)["\n query home {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n home: page(contentType: \"home.HomePage\", urlPath: \"/home/\") {\n ... on HomePage {\n ...Home\n }\n }\n news: pages(contentType: \"news.newsPage\", order: \"-first_published_at\", limit: 4) {\n ... on NewsPage {\n ...News\n }\n }\n }\n"];
|
export function graphql(source: "\n query home {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...EventListItem\n }\n }\n }\n }\n home: page(contentType: \"home.HomePage\", urlPath: \"/home/\") {\n ... on HomePage {\n ...Home\n }\n }\n news: pages(contentType: \"news.newsPage\", order: \"-first_published_at\", limit: 4) {\n ... on NewsPage {\n ...NewsListItem\n }\n }\n }\n"): (typeof documents)["\n query home {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...EventListItem\n }\n }\n }\n }\n home: page(contentType: \"home.HomePage\", urlPath: \"/home/\") {\n ... on HomePage {\n ...Home\n }\n }\n news: pages(contentType: \"news.newsPage\", order: \"-first_published_at\", limit: 4) {\n ... on NewsPage {\n ...NewsListItem\n }\n }\n }\n"];
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
@@ -360,6 +364,10 @@ export function graphql(source: "\n fragment EventCategory on EventCategory {\n
|
|||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
export function graphql(source: "\n fragment EventOrganizer on EventOrganizer {\n __typename\n id\n name\n slug\n externalUrl\n association {\n ... on AssociationPage {\n url\n }\n }\n }\n"): (typeof documents)["\n fragment EventOrganizer on EventOrganizer {\n __typename\n id\n name\n slug\n externalUrl\n association {\n ... on AssociationPage {\n url\n }\n }\n }\n"];
|
export function graphql(source: "\n fragment EventOrganizer on EventOrganizer {\n __typename\n id\n name\n slug\n externalUrl\n association {\n ... on AssociationPage {\n url\n }\n }\n }\n"): (typeof documents)["\n fragment EventOrganizer on EventOrganizer {\n __typename\n id\n name\n slug\n externalUrl\n association {\n ... on AssociationPage {\n url\n }\n }\n }\n"];
|
||||||
|
/**
|
||||||
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
|
*/
|
||||||
|
export function graphql(source: "\n fragment EventListItem on EventPage {\n __typename\n id\n slug\n title\n subtitle\n featuredImage {\n ...Image\n }\n occurrences(limit: 5000) {\n ... on EventOccurrence {\n __typename\n id\n start\n end\n }\n }\n }\n"): (typeof documents)["\n fragment EventListItem on EventPage {\n __typename\n id\n slug\n title\n subtitle\n featuredImage {\n ...Image\n }\n occurrences(limit: 5000) {\n ... on EventOccurrence {\n __typename\n id\n start\n end\n }\n }\n }\n"];
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
@@ -376,6 +384,10 @@ export function graphql(source: "\n query eventIndexMetadata {\n index: even
|
|||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
export function graphql(source: "\n query futureEvents {\n index: eventIndex {\n ... on EventIndex {\n ...EventIndex\n }\n }\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n eventCategories: eventCategories(limit: 5000) {\n ... on EventCategory {\n ...EventCategory\n }\n }\n eventOrganizers: eventOrganizers(limit: 5000) {\n ... on EventOrganizer {\n ...EventOrganizer\n }\n }\n venues: pages(contentType: \"venues.VenuePage\") {\n ... on VenuePage {\n id\n title\n slug\n preposition\n }\n }\n }\n"): (typeof documents)["\n query futureEvents {\n index: eventIndex {\n ... on EventIndex {\n ...EventIndex\n }\n }\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n eventCategories: eventCategories(limit: 5000) {\n ... on EventCategory {\n ...EventCategory\n }\n }\n eventOrganizers: eventOrganizers(limit: 5000) {\n ... on EventOrganizer {\n ...EventOrganizer\n }\n }\n venues: pages(contentType: \"venues.VenuePage\") {\n ... on VenuePage {\n id\n title\n slug\n preposition\n }\n }\n }\n"];
|
export function graphql(source: "\n query futureEvents {\n index: eventIndex {\n ... on EventIndex {\n ...EventIndex\n }\n }\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n eventCategories: eventCategories(limit: 5000) {\n ... on EventCategory {\n ...EventCategory\n }\n }\n eventOrganizers: eventOrganizers(limit: 5000) {\n ... on EventOrganizer {\n ...EventOrganizer\n }\n }\n venues: pages(contentType: \"venues.VenuePage\") {\n ... on VenuePage {\n id\n title\n slug\n preposition\n }\n }\n }\n"): (typeof documents)["\n query futureEvents {\n index: eventIndex {\n ... on EventIndex {\n ...EventIndex\n }\n }\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n eventCategories: eventCategories(limit: 5000) {\n ... on EventCategory {\n ...EventCategory\n }\n }\n eventOrganizers: eventOrganizers(limit: 5000) {\n ... on EventOrganizer {\n ...EventOrganizer\n }\n }\n venues: pages(contentType: \"venues.VenuePage\") {\n ... on VenuePage {\n id\n title\n slug\n preposition\n }\n }\n }\n"];
|
||||||
|
/**
|
||||||
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
|
*/
|
||||||
|
export function graphql(source: "\n fragment NewsListItem on NewsPage {\n __typename\n id\n slug\n title\n firstPublishedAt\n excerpt\n featuredImage {\n ...Image\n }\n }\n"): (typeof documents)["\n fragment NewsListItem on NewsPage {\n __typename\n id\n slug\n title\n firstPublishedAt\n excerpt\n featuredImage {\n ...Image\n }\n }\n"];
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+56
-23
@@ -12,17 +12,23 @@ import { graphql, unmaskFragment } from "@/gql";
|
|||||||
import {
|
import {
|
||||||
type EventCategoryFragment,
|
type EventCategoryFragment,
|
||||||
type EventFragment,
|
type EventFragment,
|
||||||
|
type EventListItemFragment,
|
||||||
type EventOrganizerFragment,
|
type EventOrganizerFragment,
|
||||||
} from "@/gql/graphql";
|
} from "@/gql/graphql";
|
||||||
import { PIG_NAMES, randomElement } from "@/lib/common";
|
import { PIG_NAMES, randomElement } from "@/lib/common";
|
||||||
|
|
||||||
export type EventOccurrence = EventFragment["occurrences"][number];
|
export type EventOccurrence = EventFragment["occurrences"][number];
|
||||||
|
export type EventListItemOccurrence = EventListItemFragment["occurrences"][number];
|
||||||
export type EventCategory = EventCategoryFragment;
|
export type EventCategory = EventCategoryFragment;
|
||||||
export type EventOrganizer = EventOrganizerFragment;
|
export type EventOrganizer = EventOrganizerFragment;
|
||||||
export type { EventFragment };
|
export type { EventFragment, EventListItemFragment };
|
||||||
|
|
||||||
export type SingularEvent = EventFragment & {
|
type EventListable = {
|
||||||
occurrence: EventOccurrence;
|
occurrences: ReadonlyArray<{ id: string | null; start: string; end: string | null }>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SingularEvent<E extends EventListable = EventFragment> = E & {
|
||||||
|
occurrence: E["occurrences"][number];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const EventCategoryFragmentDefinition = graphql(`
|
export const EventCategoryFragmentDefinition = graphql(`
|
||||||
@@ -50,6 +56,27 @@ export const EventOrganizerFragmentDefinition = graphql(`
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
const EventListItemFragmentDefinition = graphql(`
|
||||||
|
fragment EventListItem on EventPage {
|
||||||
|
__typename
|
||||||
|
id
|
||||||
|
slug
|
||||||
|
title
|
||||||
|
subtitle
|
||||||
|
featuredImage {
|
||||||
|
...Image
|
||||||
|
}
|
||||||
|
occurrences(limit: 5000) {
|
||||||
|
... on EventOccurrence {
|
||||||
|
__typename
|
||||||
|
id
|
||||||
|
start
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
const EventFragmentDefinition = graphql(`
|
const EventFragmentDefinition = graphql(`
|
||||||
fragment Event on EventPage {
|
fragment Event on EventPage {
|
||||||
__typename
|
__typename
|
||||||
@@ -161,37 +188,39 @@ export const eventsOverviewQuery = graphql(`
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
export function getSingularEvents(events: EventFragment[]): SingularEvent[] {
|
export function getSingularEvents<E extends EventListable>(
|
||||||
return events
|
events: E[]
|
||||||
.map((event) => {
|
): SingularEvent<E>[] {
|
||||||
return event.occurrences.map((occurrence) => {
|
return events.flatMap((event) =>
|
||||||
const eventOccurrence: any = structuredClone(event);
|
event.occurrences.map((occurrence) => {
|
||||||
|
const eventOccurrence = structuredClone(event) as SingularEvent<E>;
|
||||||
eventOccurrence.occurrence = occurrence;
|
eventOccurrence.occurrence = occurrence;
|
||||||
return eventOccurrence;
|
return eventOccurrence;
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.flat();
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sortSingularEvents(events: SingularEvent[]) {
|
export function sortSingularEvents<E extends EventListable>(
|
||||||
|
events: SingularEvent<E>[]
|
||||||
|
) {
|
||||||
return events.sort((a, b) =>
|
return events.sort((a, b) =>
|
||||||
compareDates(a.occurrence.start, b.occurrence.start)
|
compareDates(a.occurrence.start, b.occurrence.start)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
interface EventCalendar {
|
interface EventCalendar<E extends EventListable = EventFragment> {
|
||||||
[yearMonth: string]: {
|
[yearMonth: string]: {
|
||||||
[week: string]: {
|
[week: string]: {
|
||||||
[day: string]: SingularEvent[];
|
[day: string]: SingularEvent<E>[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function organizeEventsInCalendar(
|
export function organizeEventsInCalendar<E extends EventListable>(
|
||||||
events: SingularEvent[]
|
events: SingularEvent<E>[]
|
||||||
): EventCalendar {
|
): EventCalendar<E> {
|
||||||
const sortedEvents = sortSingularEvents(events);
|
const sortedEvents = sortSingularEvents(events);
|
||||||
|
|
||||||
const calendar: EventCalendar = {};
|
const calendar: EventCalendar<E> = {};
|
||||||
|
|
||||||
const minDate = new Date(sortedEvents[0]?.occurrence.start);
|
const minDate = new Date(sortedEvents[0]?.occurrence.start);
|
||||||
const maxDate = new Date(
|
const maxDate = new Date(
|
||||||
@@ -243,13 +272,15 @@ export function organizeEventsInCalendar(
|
|||||||
return calendar;
|
return calendar;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EventsByDate {
|
interface EventsByDate<E extends EventListable = EventFragment> {
|
||||||
[day: string]: SingularEvent[];
|
[day: string]: SingularEvent<E>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function organizeEventsByDate(events: SingularEvent[]): EventsByDate {
|
export function organizeEventsByDate<E extends EventListable>(
|
||||||
|
events: SingularEvent<E>[]
|
||||||
|
): EventsByDate<E> {
|
||||||
const sortedEvents = sortSingularEvents(events);
|
const sortedEvents = sortSingularEvents(events);
|
||||||
const eventsByDate: EventsByDate = {};
|
const eventsByDate: EventsByDate<E> = {};
|
||||||
|
|
||||||
sortedEvents.forEach((event) => {
|
sortedEvents.forEach((event) => {
|
||||||
const start = toLocalTime(event.occurrence.start);
|
const start = toLocalTime(event.occurrence.start);
|
||||||
@@ -263,7 +294,9 @@ export function organizeEventsByDate(events: SingularEvent[]): EventsByDate {
|
|||||||
return eventsByDate;
|
return eventsByDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFutureOccurrences(event: EventFragment): EventOccurrence[] {
|
export function getFutureOccurrences<E extends EventListable>(
|
||||||
|
event: E
|
||||||
|
): E["occurrences"][number][] {
|
||||||
const today = startOfToday();
|
const today = startOfToday();
|
||||||
const occurrences = event?.occurrences ?? [];
|
const occurrences = event?.occurrences ?? [];
|
||||||
const futureOccurrences = occurrences.filter((occurrence) =>
|
const futureOccurrences = occurrences.filter((occurrence) =>
|
||||||
@@ -272,7 +305,7 @@ export function getFutureOccurrences(event: EventFragment): EventOccurrence[] {
|
|||||||
futureOccurrences.sort(
|
futureOccurrences.sort(
|
||||||
(a, b) => parseISO(a.start).getTime() - parseISO(b.start).getTime()
|
(a, b) => parseISO(a.start).getTime() - parseISO(b.start).getTime()
|
||||||
);
|
);
|
||||||
return futureOccurrences as EventOccurrence[];
|
return futureOccurrences as E["occurrences"][number][];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getEventPig(event: EventFragment): string | null {
|
export function getEventPig(event: EventFragment): string | null {
|
||||||
|
|||||||
+15
-1
@@ -1,7 +1,21 @@
|
|||||||
import { graphql } from "@/gql";
|
import { graphql } from "@/gql";
|
||||||
import { NewsFragment } from "@/gql/graphql";
|
import { NewsFragment } from "@/gql/graphql";
|
||||||
|
|
||||||
export type { NewsFragment, NewsIndexFragment } from "@/gql/graphql";
|
export type { NewsFragment, NewsIndexFragment, NewsListItemFragment } from "@/gql/graphql";
|
||||||
|
|
||||||
|
const NewsListItemFragmentDefinition = graphql(`
|
||||||
|
fragment NewsListItem on NewsPage {
|
||||||
|
__typename
|
||||||
|
id
|
||||||
|
slug
|
||||||
|
title
|
||||||
|
firstPublishedAt
|
||||||
|
excerpt
|
||||||
|
featuredImage {
|
||||||
|
...Image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
const NewsFragmentDefinition = graphql(`
|
const NewsFragmentDefinition = graphql(`
|
||||||
fragment News on NewsPage {
|
fragment News on NewsPage {
|
||||||
|
|||||||
Reference in New Issue
Block a user