import * as React from "react" import { Controller, useForm } from "react-hook-form" import { Button } from "./Button" import { CheckBox } from "./CheckBox" import { Field, FieldSet } from "./FieldSet" import { Input } from "./Input" import { Label } from "./Label" import { Modal } from "./Modal" import { Mode, getModeName } from "../types/Mode" import { SelectLanguage, SelectLanguageProps } from "./SelectLanguage" import { SelectTitle, SelectTitleProps } from "./SelectTitle" import { Site, getSiteName } from "../types/Site" import { Slider } from "./Slider" import { Title } from "../types/Title" import { RATING_MIN, RATING_MAX, SearchParams } from "../types/SearchParams" const computeStepLabels = ( min: number, max: number, // The number of labels (+ 1) that should be produced. steps: number, // To which value numbers should be rounded to. round: number ) => { let labels = [] const delta = Math.floor((max - min) / steps) for (let i = min; i <= max; i += delta) { if (i % round <= round / 2) { labels.push(i - (i % round)) } else { labels.push(i + round - (i % round)) } } labels[labels.length - 1] = max return labels } interface SortModalProps { open: boolean defaultValues: SearchParams onClose: () => void onSubmit: (p: SearchParams) => void } export function SortModal({ open, defaultValues, onClose, onSubmit, }: SortModalProps) { const idPrefix = React.useId() const { watch, reset, control, register, setValue, handleSubmit, formState: { errors }, } = useForm({ mode: "onChange", defaultValues, }) // Default values are processed immediately despite the modal not being open // at the start. Furthermore, values are preserved after closing and // re-opening the modal, but we want closing the modal to signify canceling. // A simple workaround is to reset everytime we open the modal. React.useEffect(() => reset(defaultValues), [open]) // Registration const registerSites = register("sites", { required: "Please select at least one site.", }) const proxyLanguages = register("languages") const registerLanguages: Pick< SelectLanguageProps, "defaultValue" | "onChange" > = { ...proxyLanguages, defaultValue: defaultValues.languages, onChange: (event, value) => { event && proxyLanguages.onChange(event) setValue("languages", (value ?? []) as string[]) }, } const registerRating = register("rating") const registerModes = register("modes", { required: "Please select at least one mode.", }) const proxyTitles = register("titles") const registerTitles: Pick = { ...proxyTitles, defaultValue: defaultValues.titles, onChange: (event, value) => { event && proxyTitles.onChange(event) setValue("titles", (value ?? []) as Title[]) }, } return ( 0} > Submit ), onSubmit: handleSubmit(onSubmit), }} >

Prioritize coaches from the selected site(s).

{(Object.values(Site) as Site[]).map((s) => (
{getSiteName(s)}
))}

Select languages you prefer communicating in. We{"'"}ll prioritize finding coaches that can speak fluently in at least one of your selections.

Prioritize coaches with one or more of the following titles. That said, this is usually not an aspect of a coach that is important to focus on.

Prefer a specific game mode? We{"'"}ll prioritize coaches that specialize in the modes selected.

{(Object.values(Mode) as Mode[]).map((m) => (
{getModeName(m)}
))}

Find coaches that have a rating within the specified range. A higher rating does not necessarily correspond to a better coach. If you are unsure of this or do not have any preference, leave as is.

( { event && onChange(event) setValue("rating.0", newValue[0]) setValue("rating.1", newValue[1]) }} step={10} min={RATING_MIN} max={RATING_MAX} marks={computeStepLabels(RATING_MIN, RATING_MAX, 7, 50).map( (s) => ({ value: s, label: `${s}` }) )} /> )} />
) }