From 5391ba98c5131f0a74813e456e7ecafa92b46424 Mon Sep 17 00:00:00 2001 From: Jonas Braathen Date: Sun, 18 Aug 2024 02:37:04 +0200 Subject: [PATCH] support filtering multiple categories --- web/src/components/events/EventContainer.tsx | 30 ++++++----- web/src/components/events/EventFilter.tsx | 52 +++++++++++--------- web/src/lib/common.ts | 15 ++++++ 3 files changed, 62 insertions(+), 35 deletions(-) diff --git a/web/src/components/events/EventContainer.tsx b/web/src/components/events/EventContainer.tsx index 8429d16..31a86c7 100644 --- a/web/src/components/events/EventContainer.tsx +++ b/web/src/components/events/EventContainer.tsx @@ -1,6 +1,11 @@ "use client"; -import { useQueryState, parseAsStringLiteral, parseAsString } from "nuqs"; +import { + useQueryState, + parseAsStringLiteral, + parseAsString, + parseAsArrayOf, +} from "nuqs"; import { EventItem } from "./EventItem"; import { EventFilter, EventFilterExplained } from "./EventFilter"; import { @@ -44,12 +49,15 @@ export const EventContainer = ({ "mode", parseAsStringLiteral(["list", "calendar"]).withDefault("list") ); - const [category, setCategory] = useQueryState("category", parseAsString); + const [categories, setCategories] = useQueryState( + "category", + parseAsArrayOf(parseAsString, ",") + ); const [organizer, setOrganizer] = useQueryState("organizer", parseAsString); const [venue, setVenue] = useQueryState("venue", parseAsString); const resetFilters = () => { - setCategory(null); + setCategories(null); setOrganizer(null); setVenue(null); }; @@ -105,10 +113,10 @@ export const EventContainer = ({ ) .filter( (x) => - !category || + !categories || x.categories .map((eventCategory) => eventCategory.slug) - .includes(category) + .filter((x) => categories.includes(x)).length !== 0 ) .filter( (x) => @@ -147,7 +155,7 @@ export const EventContainer = ({
- {(category || organizer || venue) && ( + {(categories || organizer || venue) && (
{ if (events.length === 0) { - return ( -
Ingen kommende arrangementer.
- ); + return
Ingen kommende arrangementer.
; } return (
    diff --git a/web/src/components/events/EventFilter.tsx b/web/src/components/events/EventFilter.tsx index 362be5a..e46ac99 100644 --- a/web/src/components/events/EventFilter.tsx +++ b/web/src/components/events/EventFilter.tsx @@ -2,12 +2,12 @@ import { EventCategory, EventOrganizer } from "@/lib/event"; import styles from "./eventFilter.module.scss"; import { VenueFragment } from "@/gql/graphql"; -import { Icon } from "../general/Icon"; +import { formatHumanReadableList } from "@/lib/common"; export const EventFilter = ({ eventCategories, - setCategory, - activeCategory, + setCategories, + activeCategories, eventOrganizers, setOrganizer, activeOrganizer, @@ -17,8 +17,8 @@ export const EventFilter = ({ isVisible, }: { eventCategories: EventCategory[]; - setCategory: (slug: string | null) => void; - activeCategory: string | null; + setCategories: (slug: string[] | null) => void; + activeCategories: string[] | null; eventOrganizers: EventOrganizer[]; setOrganizer: (slug: string | null) => void; activeOrganizer: string | null; @@ -35,6 +35,12 @@ export const EventFilter = ({ const venue = e.target.value; setVenue(venue === "" ? null : venue); }; + const toggleCategory = (category: string) => { + const newCategories = activeCategories?.includes(category) + ? activeCategories?.filter((x) => x !== category) + : [...(activeCategories ?? []), category]; + setCategories(newCategories.length === 0 ? null : newCategories); + }; return (
    @@ -48,12 +54,8 @@ export const EventFilter = ({
  • @@ -102,34 +104,38 @@ export const EventFilter = ({ export const EventFilterExplained = ({ eventCategories, - activeCategory, + activeCategories, eventOrganizers, activeOrganizer, venues, activeVenue, }: { eventCategories: EventCategory[]; - activeCategory: string | null; + activeCategories: string[] | null; eventOrganizers: EventOrganizer[]; activeOrganizer: string | null; venues: VenueFragment[]; activeVenue: string | null; }) => { - const category = - activeCategory && eventCategories.find((x) => x.slug === activeCategory); + const categories = eventCategories.filter((x) => + activeCategories?.includes(x.slug) + ); const organizer = activeOrganizer && eventOrganizers.find((x) => x.slug === activeOrganizer); const venue = activeVenue && venues.find((x) => x.slug === activeVenue); + const categoryList = formatHumanReadableList(categories.map((x) => x.name)); + const hasCategories = categoryList.length !== 0; + let text = ""; - if (category && organizer && venue) { - text = `${category.name} av ${organizer.name} ${venue.preposition} ${venue.title}`; - } else if (category && organizer) { - text = `${category.name} av ${organizer.name}`; - } else if (category && venue) { - text = `${category.name} ${venue.preposition} ${venue.title}`; - } else if (category) { - text = `${category.name}`; + if (hasCategories && organizer && venue) { + text = `${categoryList} av ${organizer.name} ${venue.preposition} ${venue.title}`; + } else if (hasCategories && organizer) { + text = `${categoryList} av ${organizer.name}`; + } else if (hasCategories && venue) { + text = `${categoryList} ${venue.preposition} ${venue.title}`; + } else if (hasCategories) { + text = `${categoryList}`; } else if (organizer && venue) { text = `Arrangeres av ${organizer.name} ${venue.preposition} ${venue.title}`; } else if (organizer) { diff --git a/web/src/lib/common.ts b/web/src/lib/common.ts index 72265af..6111bed 100644 --- a/web/src/lib/common.ts +++ b/web/src/lib/common.ts @@ -76,6 +76,21 @@ export function formatNorwegianPhoneNumber(phone: string): string { return phone; } +export function formatHumanReadableList(array: (string | number)[]): string { + const length = array.length; + + if (length === 0) { + return ""; + } + if (length === 1) { + return array[0].toString(); + } + if (length === 2) { + return array.join(" og "); + } + return array.slice(0, -1).join(", ") + " og " + array[length - 1]; +} + const OneLevelOfBlocksFragmentDefinition = graphql(` fragment OneLevelOfBlocks on StreamFieldInterface { id