diff --git a/apps/map/src/app/_components/map/filters-all.tsx b/apps/map/src/app/_components/map/filters-all.tsx index 488452b2..47b16f77 100644 --- a/apps/map/src/app/_components/map/filters-all.tsx +++ b/apps/map/src/app/_components/map/filters-all.tsx @@ -1,7 +1,7 @@ "use client"; import type { ComponentProps } from "react"; -import Image from "next/image"; // Next.js Image component for optimized image rendering. +import { useMemo } from "react"; import { X } from "lucide-react"; @@ -9,19 +9,36 @@ import { SHORT_DAY_ORDER } from "@acme/shared/app/constants"; import { RERENDER_LOGS } from "@acme/shared/common/constants"; import { cn } from "@acme/ui"; import { Button } from "@acme/ui/button"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@acme/ui/select"; import { useTheme } from "@acme/ui/theme"; +import { VirtualizedCombobox } from "~/app/_components/virtualized-combobox"; +import { orpc, useQuery } from "~/orpc/react"; import type { FiltersType } from "~/utils/store/filter"; import { filterStore, initialFilterState, TimeSelection, } from "~/utils/store/filter"; -import BootSvgComponent from "../SVGs/boot-camp"; -import RuckSvgComponent from "../SVGs/ruck"; -import RunSvgComponent from "../SVGs/run"; -// Defining items for the filter options with their names and corresponding SVG components or image paths. +const TIME_OPTIONS = Object.values(TimeSelection) + .filter((v) => v !== TimeSelection.none) + .map((value) => { + const match = /^(\d{1,2})(am|pm)$/.exec(value); + return { + value, + label: + match?.[1] && match[2] + ? `${match[1]} ${match[2].toUpperCase()}` + : value, + }; + }); // The main component for the map drawer. export const FiltersAll = (props: ComponentProps<"div">) => { @@ -31,6 +48,28 @@ export const FiltersAll = (props: ComponentProps<"div">) => { const { resolvedTheme } = useTheme(); const isDark = resolvedTheme === "dark"; + const { data: nationalEventTypesResult, isLoading } = useQuery( + orpc.eventType.all.queryOptions({ + input: { + nationalOnly: true, + statuses: ["active"], + sorting: [{ id: "name", desc: false }], + }, + }), + ); + const nationalEventTypes = nationalEventTypesResult?.eventTypes; + + const eventTypeOptions = useMemo( + () => + nationalEventTypes?.map((et) => ({ + value: String(et.id), + label: et.name, + })) ?? [], + [nationalEventTypes], + ); + + const selectedIds = filters.nationalEventTypeIds; + // Function to toggle the state of a filter when clicked. const handleFilterClick = ( filterName: keyof FiltersType, @@ -45,47 +84,10 @@ export const FiltersAll = (props: ComponentProps<"div">) => { } }; - const handleTypeClick = ( - filterName: "Bootcamp" | "Ruck" | "Run" | "Swim", - newState?: boolean, - ) => { - filterStore.setState((s) => ({ - Bootcamp: false, - Ruck: false, - Run: false, - Swim: false, - [filterName]: newState ?? !s[filterName], - })); - }; - const handleResetFilters = () => { filterStore.setState(initialFilterState); }; - const workoutItems = [ - { - name: "Bootcamp" as const, - img: BootSvgComponent, - onClick: () => { - handleTypeClick("Bootcamp"); - }, - }, - { - name: "Ruck" as const, - img: RuckSvgComponent, - onClick: () => { - handleTypeClick("Ruck"); - }, - }, - { - name: "Run" as const, - img: RunSvgComponent, - onClick: () => { - handleTypeClick("Run"); - }, - }, - ]; - return (
) => {

Time of Workout

-
-
- - + filterStore.setState({ + beforeAfterDirection: v as "before" | "after", + }) + } + > + + + + + On or before + On or after + + + -
+ + + + -- + {TIME_OPTIONS.map((opt) => ( + + {opt.label} + + ))} + +

Type of Workout

-
- {workoutItems.map((item, index) => ( - - ))} +
+ 0 && + (isDark + ? "border-blue-500 bg-blue-950" + : "border-blue-500 bg-blue-100"), + )} + onSelect={(item) => { + const ids = Array.isArray(item) + ? item.map((id) => Number(id)) + : [Number(item)]; + filterStore.setState({ nationalEventTypeIds: ids }); + }} + />
+ {nationalEventTypes?.length === 0 && !isLoading ? ( +

+ No national event types found. +

+ ) : null}