filter on future events when fetching for home page / event index

This commit is contained in:
2024-05-20 22:00:02 +02:00
parent 10227ff8e3
commit 856f39bb58
6 changed files with 83 additions and 43 deletions

View File

@ -1,7 +1,9 @@
from django import forms from django import forms
from django.db import models from django.db import models
from django.db.models import Min, Q
from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from grapple.helpers import register_query_field from grapple.helpers import register_query_field, register_singular_query_field
from grapple.models import ( from grapple.models import (
GraphQLBoolean, GraphQLBoolean,
GraphQLCollection, GraphQLCollection,
@ -25,17 +27,31 @@ from wagtail.admin.panels import (
) )
from wagtail.fields import StreamField from wagtail.fields import StreamField
from wagtail.images.blocks import ImageChooserBlock from wagtail.images.blocks import ImageChooserBlock
from wagtail.models import Orderable, Page from wagtail.models import Orderable, Page, PageManager, PageQuerySet
from wagtail.snippets.models import register_snippet from wagtail.snippets.models import register_snippet
from venues.models import VenuePage from venues.models import VenuePage
@register_singular_query_field("eventIndex")
class EventIndex(Page): class EventIndex(Page):
# there can only be one event index page
max_count = 1 max_count = 1
subpage_types = ["events.EventPage"] subpage_types = ["events.EventPage"]
def future_events(self, info, **kwargs):
return EventPage.objects.future().order_by("next_occurrence")
graphql_fields = [
GraphQLCollection(
GraphQLForeignKey,
"future_events",
"events.EventPage",
required=True,
item_required=True,
is_queryset=True,
),
]
@register_snippet @register_snippet
@register_query_field("eventCategory", "eventCategories") @register_query_field("eventCategory", "eventCategories")
@ -108,23 +124,22 @@ class EventOrganizer(ClusterableModel):
return self.name return self.name
class EventPageQuerySet(PageQuerySet):
def future(self):
today = timezone.localtime(timezone.now()).date()
next_occurrence = Min("occurrences__start", filter=Q(occurrences__start__gte=today))
return self.filter(occurrences__start__gte=today).annotate(next_occurrence=next_occurrence)
EventPageManager = PageManager.from_queryset(EventPageQuerySet)
class EventPage(Page): class EventPage(Page):
# no children
subpage_types = [] subpage_types = []
parent_page_types = ["events.EventIndex"] parent_page_types = ["events.EventIndex"]
# should not be able to be shown in menus
show_in_menus = False show_in_menus = False
# inherited from Page: objects = EventPageManager()
# title = text
# slug = text (in promote panel)
# content_type = points to this model
# live = bool
# owner = page creator
# first_published_at = datetime
# last_published_at = datetime
# seo_title: text (in promote panel)
# search_description: text (in promote panel)
featured_image = models.ForeignKey( featured_image = models.ForeignKey(
"images.CustomImage", "images.CustomImage",
@ -167,8 +182,6 @@ class EventPage(Page):
help_text="Lenke direkte til arrangementet på Facebook", help_text="Lenke direkte til arrangementet på Facebook",
) )
# "event_organizers": [390, 322],
price_regular = models.IntegerField(null=True, blank=True) price_regular = models.IntegerField(null=True, blank=True)
price_student = models.IntegerField(null=True, blank=True) price_student = models.IntegerField(null=True, blank=True)
price_member = models.IntegerField(null=True, blank=True) price_member = models.IntegerField(null=True, blank=True)

View File

@ -1,7 +1,7 @@
import { getClient } from "@/app/client"; import { getClient } from "@/app/client";
import { EventContainer } from "@/components/events/EventContainer"; import { EventContainer } from "@/components/events/EventContainer";
import { import {
allEventsQuery, futureEventsQuery,
EventFragment, EventFragment,
EventCategory, EventCategory,
EventOccurrence, EventOccurrence,
@ -10,8 +10,8 @@ import { PageHeader } from "@/components/general/PageHeader";
import { Suspense } from "react"; import { Suspense } from "react";
export default async function Page() { export default async function Page() {
const { data, error } = await getClient().query(allEventsQuery, {}); const { data, error } = await getClient().query(futureEventsQuery, {});
const events = (data?.events ?? []) as EventFragment[]; const events = (data?.events?.futureEvents ?? []) as EventFragment[];
const eventCategories = (data?.eventCategories ?? []) as EventCategory[]; const eventCategories = (data?.eventCategories ?? []) as EventCategory[];
return ( return (

View File

@ -19,8 +19,14 @@ const HomeFragmentDefinition = graphql(`
export default async function Home() { export default async function Home() {
const homeQuery = graphql(` const homeQuery = graphql(`
query home { query home {
events: pages(contentType: "events.EventPage") { events: eventIndex {
...Event ... on EventIndex {
futureEvents {
... on EventPage {
...Event
}
}
}
} }
home: page(contentType: "home.HomePage", urlPath: "/home/") { home: page(contentType: "home.HomePage", urlPath: "/home/") {
... on HomePage { ... on HomePage {
@ -30,7 +36,7 @@ export default async function Home() {
} }
`); `);
const { data, error } = await getClient().query(homeQuery, {}); const { data, error } = await getClient().query(homeQuery, {});
const events = (data?.events ?? []) as EventFragment[]; const events = (data?.events?.futureEvents ?? []) as EventFragment[];
const home = (data?.home ?? []) as HomeFragment; const home = (data?.home ?? []) as HomeFragment;
const featuredEventIds = home.featuredEvents.map((x) => x.id); const featuredEventIds = home.featuredEvents.map((x) => x.id);

View File

@ -28,11 +28,11 @@ const documents = {
"\n fragment Venue on VenuePage {\n __typename\n id\n slug\n title\n body {\n id\n blockType\n field\n ... on RichTextBlock {\n rawValue\n value\n }\n }\n featuredImage {\n ...Image\n }\n showAsBookable\n floor\n preposition\n capabilityAudio\n capabilityAudioVideo\n capabilityBar\n capabilityLighting\n capacityLegal\n capacityStanding\n capacitySitting\n }\n": types.VenueFragmentDoc, "\n fragment Venue on VenuePage {\n __typename\n id\n slug\n title\n body {\n id\n blockType\n field\n ... on RichTextBlock {\n rawValue\n value\n }\n }\n featuredImage {\n ...Image\n }\n showAsBookable\n floor\n preposition\n capabilityAudio\n capabilityAudioVideo\n capabilityBar\n capabilityLighting\n capacityLegal\n capacityStanding\n capacitySitting\n }\n": types.VenueFragmentDoc,
"\n query allVenues {\n venues: pages(contentType: \"venues.VenuePage\") {\n ... on VenuePage {\n ...Venue\n }\n }\n }\n ": types.AllVenuesDocument, "\n query allVenues {\n venues: pages(contentType: \"venues.VenuePage\") {\n ... on VenuePage {\n ...Venue\n }\n }\n }\n ": types.AllVenuesDocument,
"\n fragment Home on HomePage {\n ... on HomePage {\n featuredEvents {\n id\n }\n }\n }\n": types.HomeFragmentDoc, "\n fragment Home on HomePage {\n ... on HomePage {\n featuredEvents {\n id\n }\n }\n }\n": types.HomeFragmentDoc,
"\n query home {\n events: pages(contentType: \"events.EventPage\") {\n ...Event\n }\n home: page(contentType: \"home.HomePage\", urlPath: \"/home/\") {\n ... on HomePage {\n ...Home\n }\n }\n }\n ": types.HomeDocument, "\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 }\n ": types.HomeDocument,
"\n fragment Blocks on StreamFieldInterface {\n id\n blockType\n field\n ... on RichTextBlock {\n rawValue\n value\n }\n ... on ImageWithTextBlock {\n image {\n ...Image\n }\n imageFormat\n text\n }\n ... on ImageSliderBlock {\n images {\n ... on ImageSliderItemBlock {\n image {\n ...Image\n }\n text\n }\n }\n }\n }\n": types.BlocksFragmentDoc, "\n fragment Blocks on StreamFieldInterface {\n id\n blockType\n field\n ... on RichTextBlock {\n rawValue\n value\n }\n ... on ImageWithTextBlock {\n image {\n ...Image\n }\n imageFormat\n text\n }\n ... on ImageSliderBlock {\n images {\n ... on ImageSliderItemBlock {\n image {\n ...Image\n }\n text\n }\n }\n }\n }\n": types.BlocksFragmentDoc,
"\n fragment Image on CustomImage {\n id\n url\n width\n height\n alt\n attribution\n }\n": types.ImageFragmentDoc, "\n fragment Image on CustomImage {\n id\n url\n width\n height\n alt\n attribution\n }\n": types.ImageFragmentDoc,
"\n fragment Event on EventPage {\n __typename\n id\n slug\n title\n body {\n id\n blockType\n field\n ... on RichTextBlock {\n rawValue\n value\n }\n }\n featuredImage {\n ...Image\n }\n facebookUrl\n ticketUrl\n priceRegular\n priceMember\n priceStudent\n categories {\n ... on EventCategory {\n name\n slug\n }\n }\n occurrences {\n ... on EventOccurrence {\n __typename\n id\n start\n end\n venue {\n __typename\n id\n slug\n title\n }\n }\n }\n }\n": types.EventFragmentDoc, "\n fragment Event on EventPage {\n __typename\n id\n slug\n title\n body {\n id\n blockType\n field\n ... on RichTextBlock {\n rawValue\n value\n }\n }\n featuredImage {\n ...Image\n }\n facebookUrl\n ticketUrl\n priceRegular\n priceMember\n priceStudent\n categories {\n ... on EventCategory {\n name\n slug\n }\n }\n occurrences {\n ... on EventOccurrence {\n __typename\n id\n start\n end\n venue {\n __typename\n id\n slug\n title\n }\n }\n }\n }\n": types.EventFragmentDoc,
"\n query allEvents {\n events: pages(contentType: \"events.EventPage\") {\n ... on EventPage {\n ...Event\n }\n }\n eventCategories: eventCategories {\n ... on EventCategory {\n name\n slug\n showInFilters\n }\n }\n }\n": types.AllEventsDocument, "\n query futureEvents {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n eventCategories: eventCategories {\n ... on EventCategory {\n name\n slug\n showInFilters\n }\n }\n }\n": types.FutureEventsDocument,
}; };
/** /**
@ -112,7 +112,7 @@ export function graphql(source: "\n fragment Home on HomePage {\n ... on Hom
/** /**
* 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: pages(contentType: \"events.EventPage\") {\n ...Event\n }\n home: page(contentType: \"home.HomePage\", urlPath: \"/home/\") {\n ... on HomePage {\n ...Home\n }\n }\n }\n "): (typeof documents)["\n query home {\n events: pages(contentType: \"events.EventPage\") {\n ...Event\n }\n home: page(contentType: \"home.HomePage\", urlPath: \"/home/\") {\n ... on HomePage {\n ...Home\n }\n }\n }\n "]; 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 }\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 }\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.
*/ */
@ -128,7 +128,7 @@ export function graphql(source: "\n fragment Event on EventPage {\n __typena
/** /**
* 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 allEvents {\n events: pages(contentType: \"events.EventPage\") {\n ... on EventPage {\n ...Event\n }\n }\n eventCategories: eventCategories {\n ... on EventCategory {\n name\n slug\n showInFilters\n }\n }\n }\n"): (typeof documents)["\n query allEvents {\n events: pages(contentType: \"events.EventPage\") {\n ... on EventPage {\n ...Event\n }\n }\n eventCategories: eventCategories {\n ... on EventCategory {\n name\n slug\n showInFilters\n }\n }\n }\n"]; export function graphql(source: "\n query futureEvents {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n eventCategories: eventCategories {\n ... on EventCategory {\n name\n slug\n showInFilters\n }\n }\n }\n"): (typeof documents)["\n query futureEvents {\n events: eventIndex {\n ... on EventIndex {\n futureEvents {\n ... on EventPage {\n ...Event\n }\n }\n }\n }\n eventCategories: eventCategories {\n ... on EventCategory {\n name\n slug\n showInFilters\n }\n }\n }\n"];
export function graphql(source: string) { export function graphql(source: string) {
return (documents as any)[source] ?? {}; return (documents as any)[source] ?? {};

File diff suppressed because one or more lines are too long

View File

@ -68,11 +68,15 @@ const EventFragmentDefinition = graphql(`
} }
`); `);
export const allEventsQuery = graphql(` export const futureEventsQuery = graphql(`
query allEvents { query futureEvents {
events: pages(contentType: "events.EventPage") { events: eventIndex {
... on EventPage { ... on EventIndex {
...Event futureEvents {
... on EventPage {
...Event
}
}
} }
} }
eventCategories: eventCategories { eventCategories: eventCategories {