diff --git a/assets/js/react/components/FilterModal.tsx b/assets/js/react/components/FilterModal.tsx index 3c133fb..a1aa10f 100644 --- a/assets/js/react/components/FilterModal.tsx +++ b/assets/js/react/components/FilterModal.tsx @@ -9,8 +9,9 @@ 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 { Slider } from "./Slider" - +import { Title } from "../types/Title" import { FIDE_RATING_MIN as RATING_MIN, FIDE_RATING_MAX as RATING_MAX, @@ -94,6 +95,16 @@ export function FilterModal({ 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 ( + + +

+ 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. +

+ +
+

- Find coaches that have a rating within the specified range. Keep in - mind, a higher rating does not necessarily mean a better coach{" "} - for you. If you are unsure of this or do not have any - preference, leave as is. + 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.

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 { diff --git a/assets/js/react/components/SelectTitle.tsx b/assets/js/react/components/SelectTitle.tsx new file mode 100644 index 0000000..ca1ce9b --- /dev/null +++ b/assets/js/react/components/SelectTitle.tsx @@ -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 +) { + return ( + + ) +}) diff --git a/assets/js/react/icons/Trophy.tsx b/assets/js/react/icons/Trophy.tsx new file mode 100644 index 0000000..2b31d22 --- /dev/null +++ b/assets/js/react/icons/Trophy.tsx @@ -0,0 +1,16 @@ +import * as React from "react" + +const SvgComponet = ({ ...props }) => ( + + + +) + +export default SvgComponet diff --git a/assets/js/react/types/SearchParams.ts b/assets/js/react/types/SearchParams.ts index 6323703..a9dbf01 100644 --- a/assets/js/react/types/SearchParams.ts +++ b/assets/js/react/types/SearchParams.ts @@ -1,9 +1,11 @@ import { Mode } from "./Mode" +import { Title } from "./Title" export type SearchParams = { rating: [number, number] modes: Mode[] languages: string[] + titles: Title[] } export const FIDE_RATING_MIN = 1500 @@ -13,6 +15,7 @@ export const defaultSearchParams: SearchParams = { rating: [FIDE_RATING_MIN, FIDE_RATING_MAX], modes: [Mode.RAPID, Mode.BLITZ, Mode.BULLET], languages: [], + titles: [], } export function toQueryParams(p: SearchParams) { @@ -27,5 +30,9 @@ export function toQueryParams(p: SearchParams) { queryParams["languages"] = p.languages.join(",") } + if (p.titles) { + queryParams["titles"] = p.titles.join(",") + } + return queryParams } diff --git a/assets/js/react/types/Title.ts b/assets/js/react/types/Title.ts new file mode 100644 index 0000000..536d847 --- /dev/null +++ b/assets/js/react/types/Title.ts @@ -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", +} diff --git a/lib/boardwise/coaches.ex b/lib/boardwise/coaches.ex index d02669e..9103200 100644 --- a/lib/boardwise/coaches.ex +++ b/lib/boardwise/coaches.ex @@ -49,6 +49,7 @@ defmodule BoardWise.Coaches do :bullet_gte => bullet_gte, :bullet_lte => bullet_lte, :languages => languages, + :titles => titles, :page_no => page_no, :page_size => page_size }) 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.image_url, @@ -73,7 +75,9 @@ defmodule BoardWise.Coaches do rating_fragment(c.blitz, ^blitz_gte, ^blitz_lte), rating_fragment(c.bullet, ^bullet_gte, ^bullet_lte), type(^languages, {:array, :string}), - c.languages + c.languages, + c.title, + type(^titles, {:array, :string}) ) |> selected_as(:score) } diff --git a/lib/boardwise/coaches/query_params.ex b/lib/boardwise/coaches/query_params.ex index 5a277cf..d32762c 100644 --- a/lib/boardwise/coaches/query_params.ex +++ b/lib/boardwise/coaches/query_params.ex @@ -6,6 +6,7 @@ defmodule BoardWise.Coaches.QueryParams do :blitz_lte, :bullet_gte, :bullet_lte, + :titles, :languages, page_no: 1, page_size: 15 diff --git a/lib/boardwise_web/controllers/coach_controller.ex b/lib/boardwise_web/controllers/coach_controller.ex index d2697d4..7b05bd8 100644 --- a/lib/boardwise_web/controllers/coach_controller.ex +++ b/lib/boardwise_web/controllers/coach_controller.ex @@ -14,6 +14,7 @@ defmodule BoardWiseWeb.CoachController do |> override_param(:bullet_gte, params, :integer) |> override_param(:bullet_lte, params, :integer) |> override_param(:languages, params, :strlist) + |> override_param(:titles, params, :strlist) |> override_param(:page_no, params, :integer) |> override_param(:page_size, params, :integer)