Incorporate titles into the search.

main
Joshua Potter 2023-12-07 05:45:40 -07:00
parent eb812d8366
commit 75e915e71c
9 changed files with 128 additions and 7 deletions

View File

@ -9,8 +9,9 @@ import { Label } from "./Label"
import { Modal } from "./Modal" import { Modal } from "./Modal"
import { Mode, getModeName } from "../types/Mode" import { Mode, getModeName } from "../types/Mode"
import { SelectLanguage, SelectLanguageProps } from "./SelectLanguage" import { SelectLanguage, SelectLanguageProps } from "./SelectLanguage"
import { SelectTitle, SelectTitleProps } from "./SelectTitle"
import { Slider } from "./Slider" import { Slider } from "./Slider"
import { Title } from "../types/Title"
import { import {
FIDE_RATING_MIN as RATING_MIN, FIDE_RATING_MIN as RATING_MIN,
FIDE_RATING_MAX as RATING_MAX, FIDE_RATING_MAX as RATING_MAX,
@ -94,6 +95,16 @@ export function FilterModal({
required: "Please select at least one mode.", required: "Please select at least one mode.",
}) })
const proxyTitles = register("titles")
const registerTitles: Pick<SelectTitleProps, "defaultValue" | "onChange"> = {
...proxyTitles,
defaultValue: defaultValues.titles,
onChange: (event, value) => {
event && proxyTitles.onChange(event)
setValue("titles", (value ?? []) as Title[])
},
}
return ( return (
<Modal <Modal
open={open} open={open}
@ -134,13 +145,29 @@ export function FilterModal({
/> />
</Field> </Field>
<Field>
<Label htmlFor={`${idPrefix}-titles`}>Titles:</Label>
<p className="py-2 text-sm">
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.
</p>
<SelectTitle
id={`${idPrefix}-titles`}
slotProps={{
root: { className: "w-full" },
}}
{...registerTitles}
multiple
/>
</Field>
<Field> <Field>
<Label htmlFor={`${idPrefix}-rating`}>Rating:</Label> <Label htmlFor={`${idPrefix}-rating`}>Rating:</Label>
<p className="py-2 text-sm"> <p className="py-2 text-sm">
Find coaches that have a rating within the specified range. Keep in Find coaches that have a rating within the specified range. A higher
mind, a higher rating does not necessarily mean a better coach{" "} rating does not necessarily correspond to a better coach. If you are
<i>for you</i>. If you are unsure of this or do not have any unsure of this or do not have any preference, leave as is.
preference, leave as is.
</p> </p>
<div id={`${idPrefix}-rating`} className="mt-2 w-full px-4"> <div id={`${idPrefix}-rating`} className="mt-2 w-full px-4">
<Controller <Controller

View File

@ -10,8 +10,10 @@ import LightningIcon from "../icons/Lightning"
import RabbitIcon from "../icons/Rabbit" import RabbitIcon from "../icons/Rabbit"
import RightArrowIcon from "../icons/RightArrow" import RightArrowIcon from "../icons/RightArrow"
import RisingGraphIcon from "../icons/RisingGraph" import RisingGraphIcon from "../icons/RisingGraph"
import TrophyIcon from "../icons/Trophy"
import { Button } from "./Button" import { Button } from "./Button"
import { Mode } from "../types/Mode" import { Mode } from "../types/Mode"
import { Title } from "../types/Title"
interface FilterOption { interface FilterOption {
title: string title: string
@ -73,6 +75,15 @@ const filters: FilterOption[] = [
}, },
isEnabled: (p) => p.modes.length === 1 && p.modes.includes(Mode.BULLET), isEnabled: (p) => p.modes.length === 1 && p.modes.includes(Mode.BULLET),
}, },
{
title: "Titled Player",
Icon: TrophyIcon,
enable: (p) => {
p.titles = Object.keys(Title)
return p
},
isEnabled: (p) => p.titles.length > 0,
},
] ]
enum Direction { enum Direction {

View File

@ -0,0 +1,42 @@
import * as React from "react"
import { SelectProps } from "@mui/base/Select"
import { Select, Option } from "./Select"
import { Title } from "../types/Title"
interface TitleOption {
value: Title | ""
label: string
}
const options: TitleOption[] = [
{ value: Title.GM, label: "Grandmaster" },
{ value: Title.IM, label: "International Master" },
{ value: Title.FM, label: "FIDE Master" },
{ value: Title.CM, label: "Candidate Master" },
{ value: Title.NM, label: "National Master" },
{ value: Title.WGM, label: "Woman Grandmaster" },
{ value: Title.WIM, label: "Woman International Master" },
{ value: Title.WFM, label: "Woman FIDE Master" },
{ value: Title.WCM, label: "Woman Candidate Master" },
{ value: Title.WNM, label: "Woman National Master" },
]
export type SelectTitleProps = SelectProps<{}, boolean>
export const SelectTitle = React.forwardRef(function SelectTitle(
props: SelectTitleProps,
ref: React.ForwardedRef<HTMLButtonElement>
) {
return (
<Select ref={ref} {...props}>
{options.map((entry, index) => {
return (
<Option key={index} value={entry.value}>
{entry.label}
</Option>
)
})}
</Select>
)
})

View File

@ -0,0 +1,16 @@
import * as React from "react"
const SvgComponet = ({ ...props }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
xmlSpace="preserve"
width={800}
height={800}
viewBox="0 0 100 100"
{...props}
>
<path d="M82.296 23.931a1.918 1.918 0 0 0-1.918-1.918h-8.074v-6.998c.004-.061.018-.118.018-.179a2.935 2.935 0 0 0-2.934-2.935c-.036 0-.07.009-.106.011v-.011H30.365v.054a2.925 2.925 0 0 0-2.696 2.911c0 .062.014.119.018.179v6.967H19.62a1.914 1.914 0 0 0-1.909 1.839h-.007v.073l-.001.007.001.007v26.038l-.001.004.001.009V50h.001c.01 1.051.863 1.9 1.916 1.9h8.328c1.354 9.109 8.197 16.422 17.069 18.449v12.746h-9.969a2.493 2.493 0 0 0 0 4.988v.017h29.894v-.017a2.493 2.493 0 0 0 0-4.988h-9.969V70.353c8.881-2.02 15.733-9.337 17.087-18.453h8.318c1.028 0 1.86-.81 1.909-1.825h.011V23.931h-.003zM27.687 46.913H22.69V27h4.997v19.913zm49.623 0h-5.007V27h5.007v19.913z" />
</svg>
)
export default SvgComponet

View File

@ -1,9 +1,11 @@
import { Mode } from "./Mode" import { Mode } from "./Mode"
import { Title } from "./Title"
export type SearchParams = { export type SearchParams = {
rating: [number, number] rating: [number, number]
modes: Mode[] modes: Mode[]
languages: string[] languages: string[]
titles: Title[]
} }
export const FIDE_RATING_MIN = 1500 export const FIDE_RATING_MIN = 1500
@ -13,6 +15,7 @@ export const defaultSearchParams: SearchParams = {
rating: [FIDE_RATING_MIN, FIDE_RATING_MAX], rating: [FIDE_RATING_MIN, FIDE_RATING_MAX],
modes: [Mode.RAPID, Mode.BLITZ, Mode.BULLET], modes: [Mode.RAPID, Mode.BLITZ, Mode.BULLET],
languages: [], languages: [],
titles: [],
} }
export function toQueryParams(p: SearchParams) { export function toQueryParams(p: SearchParams) {
@ -27,5 +30,9 @@ export function toQueryParams(p: SearchParams) {
queryParams["languages"] = p.languages.join(",") queryParams["languages"] = p.languages.join(",")
} }
if (p.titles) {
queryParams["titles"] = p.titles.join(",")
}
return queryParams return queryParams
} }

View File

@ -0,0 +1,12 @@
export enum Title {
GM = "GM",
IM = "IM",
FM = "FM",
CM = "CM",
NM = "NM",
WGM = "WGM",
WIM = "WIM",
WFM = "WFM",
WCM = "WCM",
WNM = "WNM",
}

View File

@ -49,6 +49,7 @@ defmodule BoardWise.Coaches do
:bullet_gte => bullet_gte, :bullet_gte => bullet_gte,
:bullet_lte => bullet_lte, :bullet_lte => bullet_lte,
:languages => languages, :languages => languages,
:titles => titles,
:page_no => page_no, :page_no => page_no,
:page_size => page_size :page_size => page_size
}) do }) do
@ -65,7 +66,8 @@ defmodule BoardWise.Coaches do
? + ? +
? + ? +
? + ? +
(5 * (SELECT COUNT(*) FROM UNNEST(?) WHERE UNNEST = ANY(?))) (5 * (SELECT COUNT(*) FROM UNNEST(?) WHERE UNNEST = ANY(?))) +
CASE WHEN ? = ANY(?) THEN 5 ELSE 0 END
""", """,
c.name, c.name,
c.image_url, c.image_url,
@ -73,7 +75,9 @@ defmodule BoardWise.Coaches do
rating_fragment(c.blitz, ^blitz_gte, ^blitz_lte), rating_fragment(c.blitz, ^blitz_gte, ^blitz_lte),
rating_fragment(c.bullet, ^bullet_gte, ^bullet_lte), rating_fragment(c.bullet, ^bullet_gte, ^bullet_lte),
type(^languages, {:array, :string}), type(^languages, {:array, :string}),
c.languages c.languages,
c.title,
type(^titles, {:array, :string})
) )
|> selected_as(:score) |> selected_as(:score)
} }

View File

@ -6,6 +6,7 @@ defmodule BoardWise.Coaches.QueryParams do
:blitz_lte, :blitz_lte,
:bullet_gte, :bullet_gte,
:bullet_lte, :bullet_lte,
:titles,
:languages, :languages,
page_no: 1, page_no: 1,
page_size: 15 page_size: 15

View File

@ -14,6 +14,7 @@ defmodule BoardWiseWeb.CoachController do
|> override_param(:bullet_gte, params, :integer) |> override_param(:bullet_gte, params, :integer)
|> override_param(:bullet_lte, params, :integer) |> override_param(:bullet_lte, params, :integer)
|> override_param(:languages, params, :strlist) |> override_param(:languages, params, :strlist)
|> override_param(:titles, params, :strlist)
|> override_param(:page_no, params, :integer) |> override_param(:page_no, params, :integer)
|> override_param(:page_size, params, :integer) |> override_param(:page_size, params, :integer)