import { alias, romanize, SEARCH_KEYS } from "@blitzkit/core"; import { literals } from "@blitzkit/i18n"; import { TankDefinition } from "@blitzkit/protos"; import { ArrowRightIcon, EyeOpenIcon, MagnifyingGlassIcon, MixerVerticalIcon, PaperPlaneIcon, StarFilledIcon, TrashIcon, } from "@radix-ui/react-icons"; import { AlertDialog, Box, Button, Card, DropdownMenu, Flex, IconButton, Spinner, Text, TextField, } from "@radix-ui/themes"; import fuzzysort from "fuzzysort"; import { debounce } from "lodash-es"; import { useCallback, useEffect, useRef, useState } from "react"; import { api } from "../api/dynamic"; import { awaitableTankNames } from "../core/awaitables/tankNames"; import { awaitableTiers } from "../core/awaitables/tiers"; import { api } from "../core/blitzkit/api"; import { useLocale } from "../hooks/useLocale"; import { Guess, GuessState } from "../stores/guess"; import { classIcons } from "./ClassIcon"; import { SearchResults } from "./SearchResults"; const { go } = fuzzysort; const [tankNames, tankDefinitions, TIERS] = await Promise.all([ awaitableTankNames, api.tankDefinitions(), awaitableTiers, ]); const ids = Object.keys(tankDefinitions.tanks); export function Guesser() { const tank = Guess.use((state) => state.tank); const guessState = Guess.use((state) => state.guessState); const correctGuesses = Guess.use((state) => state.correctGuesses); const totalGuesses = Guess.use((state) => state.totalGuesses); const helpingReveal = Guess.use((state) => state.helpingReveal); const streak = Guess.use((state) => state.streak); const { strings, unwrap } = useLocale(); const input = useRef(null); const [searching, setSearching] = useState(false); const [results, setResults] = useState(null); const [selected, setSelected] = useState(null); const tiers = Guess.use((state) => state.tiers); const status = useRef(null); const requestSearch = useCallback(() => { setSelected(null); setSearching(true); search(); }, []); const search = useCallback( debounce(() => { if (!input.current) return; setSearching(false); const trimmed = input.current.value.trim(); if (trimmed.length === 0) { setResults(null); return; } const searchResults = go(trimmed, tankNames, { keys: SEARCH_KEYS, limit: 6, }); setResults( searchResults.map((result) => tankDefinitions.tanks[result.obj.id]), ); }, 500), [], ); useEffect(() => { if (guessState !== GuessState.NotGuessed) setSelected(null); }, [guessState]); useEffect(() => { const interval = setInterval(() => { if (!status.current) return; status.current.innerText = literals(strings.website.tools.guess.stats, { correct: correctGuesses, total: totalGuesses, streak: streak, }); }, 1000 / 200); return () => clearInterval(interval); }, [correctGuesses, totalGuesses, streak]); return ( {results !== null && ( {results.length === 0 && ( {strings.website.tools.guess.search.no_results} )} {results.map((result) => { const Icon = classIcons[result.class]; return ( { if (!input.current) return; input.current.value = unwrap(result.name!); setSelected(result); setResults(null); }} text={unwrap(result.name!)} prefix={ } discriminator={ {romanize(result.tier)} } /> ); })} )} {TIERS.map((tier) => { const isSelected = tiers.includes(tier); return ( { event.preventDefault(); Guess.mutate((draft) => { if (isSelected) { if (draft.tiers.length === 1) return; draft.tiers = draft.tiers.filter((t) => t !== tier); } else { draft.tiers = [...draft.tiers, tier]; } draft.streak = 0; }); }} > {literals(strings.website.tools.guess.tier, { tier: romanize(tier), })} ); })} { event.preventDefault(); Guess.mutate((draft) => { draft.tiers = Guess.initial.tiers; }); }} > {strings.website.tools.guess.select_all} { event.preventDefault(); Guess.mutate((draft) => { draft.tiers = []; }); }} > {strings.website.tools.guess.clear} {searching ? : } {strings.website.tools.guess.help.title} {strings.website.tools.guess.help.description} ); }