web: extract event filter logic to lib, add tz/DST and year-boundary tests
This commit is contained in:
5 files changed
+414
-83
No files matched your search
@@ -9,10 +9,7 @@ import {
|
||||
} from "nuqs";
|
||||
import { EventItem } from "./EventItem";
|
||||
import { EventFilter, EventFilterExplained } from "./EventFilter";
|
||||
import { unmaskFragment } from "@/gql";
|
||||
import {
|
||||
EventCategoryFragmentDefinition,
|
||||
EventOrganizerFragmentDefinition,
|
||||
EventOverviewItemFragment,
|
||||
EventCategory,
|
||||
SingularEvent,
|
||||
@@ -20,6 +17,12 @@ import {
|
||||
organizeEventsInCalendar,
|
||||
EventOrganizer,
|
||||
} from "@/lib/event";
|
||||
import {
|
||||
filterEvents,
|
||||
getFilterableCategories,
|
||||
getFilterableOrganizers,
|
||||
getFilterableVenues,
|
||||
} from "@/lib/eventFilter";
|
||||
import { isTodayOrFuture } from "@/lib/date";
|
||||
import styles from "./eventContainer.module.scss";
|
||||
import { formatDate, formatYearMonth } from "@/lib/date";
|
||||
@@ -29,7 +32,6 @@ import {
|
||||
differenceInCalendarDays,
|
||||
parse,
|
||||
} from "date-fns";
|
||||
import { unique } from "@/lib/common";
|
||||
import { Icon } from "../general/Icon";
|
||||
import { useState } from "react";
|
||||
import { VenueFragment } from "@/gql/graphql";
|
||||
@@ -70,40 +72,13 @@ export const EventContainer = ({
|
||||
resetFilters();
|
||||
};
|
||||
|
||||
/* Allow filtering on all categories that are configured to be shown */
|
||||
const filterableCategories = eventCategories.filter((x) => x.showInFilters);
|
||||
|
||||
/*
|
||||
Allow filtering on all organizers that have upcoming events
|
||||
Filtering on an organizer with no upcoming events will work,
|
||||
and in that case it's included in the dropdown
|
||||
*/
|
||||
const allOrganizers = unmaskFragment(
|
||||
EventOrganizerFragmentDefinition,
|
||||
events.flatMap((x) => x.organizers),
|
||||
const filterableCategories = getFilterableCategories(eventCategories);
|
||||
const filterableOrganizers = getFilterableOrganizers(
|
||||
events,
|
||||
eventOrganizers,
|
||||
organizer,
|
||||
);
|
||||
const uniqueOrganizers: string[] = unique(
|
||||
allOrganizers
|
||||
.filter((x) => x.__typename === "EventOrganizer")
|
||||
.map((x) => x.slug)
|
||||
.filter((x) => typeof x === "string" && x !== ""),
|
||||
);
|
||||
const filterableOrganizers = uniqueOrganizers
|
||||
.map((slug) => eventOrganizers.find((haystack) => haystack.slug === slug))
|
||||
.filter((x) => x !== undefined) as EventOrganizer[];
|
||||
|
||||
// If an organizer is selected that's not in the upcoming list, add it
|
||||
if (
|
||||
organizer &&
|
||||
!filterableOrganizers.some((org) => org.slug === organizer)
|
||||
) {
|
||||
const selectedOrganizer = eventOrganizers.find(
|
||||
(org) => org.slug === organizer,
|
||||
);
|
||||
if (selectedOrganizer) {
|
||||
filterableOrganizers.push(selectedOrganizer);
|
||||
}
|
||||
}
|
||||
const filterableVenues = getFilterableVenues(events, venues, venue);
|
||||
|
||||
/* Reset organizer if slug is invalid */
|
||||
useEffect(() => {
|
||||
@@ -112,26 +87,6 @@ export const EventContainer = ({
|
||||
}
|
||||
}, [eventOrganizers, organizer]);
|
||||
|
||||
/*
|
||||
Allow filtering on all venues that have upcoming events
|
||||
Filtering on a venue with no upcoming events will work,
|
||||
and in that case it's included in the dropdown
|
||||
*/
|
||||
const venueSlugsWithUpcomingEvents = unique(
|
||||
events
|
||||
.map((x) => x.occurrences)
|
||||
.flat()
|
||||
.filter((x) => x.venue?.__typename === "VenuePage")
|
||||
.map((x) => x.venue?.slug)
|
||||
.filter((x) => typeof x === "string"),
|
||||
);
|
||||
const filterableVenues = venues
|
||||
.filter(
|
||||
(x) => venueSlugsWithUpcomingEvents.includes(x.slug) || x.slug === venue,
|
||||
)
|
||||
.map((x) => venues.find((haystack) => haystack.slug === x.slug))
|
||||
.filter((x) => x !== undefined) as VenueFragment[];
|
||||
|
||||
/* Reset venue if slug is invalid */
|
||||
useEffect(() => {
|
||||
if (!venues.find((haystack) => haystack.slug === venue)) {
|
||||
@@ -139,32 +94,7 @@ export const EventContainer = ({
|
||||
}
|
||||
}, [venues, venue]);
|
||||
|
||||
const filteredEvents = events.filter((event) => {
|
||||
if (organizer) {
|
||||
const organizers = unmaskFragment(
|
||||
EventOrganizerFragmentDefinition,
|
||||
event.organizers,
|
||||
);
|
||||
if (!organizers.some((o) => o.slug === organizer)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (categories) {
|
||||
const eventCategories = unmaskFragment(
|
||||
EventCategoryFragmentDefinition,
|
||||
event.categories,
|
||||
);
|
||||
if (!eventCategories.some((c) => categories.includes(c.slug))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (venue) {
|
||||
if (!event.occurrences.some((occ) => occ.venue?.slug === venue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
const filteredEvents = filterEvents(events, { categories, organizer, venue });
|
||||
|
||||
const [showFilter, setShowFilter] = useState(false);
|
||||
function toggleFilter() {
|
||||
|
||||
Reference in new issue
Block a user