Incorporate titles into the search.
parent
eb812d8366
commit
75e915e71c
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>
|
||||||
|
)
|
||||||
|
})
|
|
@ -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
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue