2025-09-01 19:13:08 -05:00
|
|
|
import type { TankDefinition } from "@blitzkit/core";
|
|
|
|
|
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
|
|
|
|
|
import { Flex, Spinner, TextField } from "@radix-ui/themes";
|
|
|
|
|
import { debounce } from "lodash-es";
|
|
|
|
|
import { type KeyboardEventHandler, useCallback, useRef } from "react";
|
|
|
|
|
import { useLocale } from "../../../hooks/useLocale";
|
|
|
|
|
import { TankFilters } from "../../../stores/tankFilters";
|
|
|
|
|
import type { MaybeSkeletonComponentProps } from "../../../types/maybeSkeletonComponentProps";
|
|
|
|
|
import { QuickLink } from "./QuickLink";
|
|
|
|
|
import { Sort } from "./Sort";
|
2024-06-21 19:04:34 -05:00
|
|
|
|
2025-04-14 23:28:35 -05:00
|
|
|
type SearchBarProps = MaybeSkeletonComponentProps & {
|
2024-06-21 19:04:34 -05:00
|
|
|
topResult?: TankDefinition;
|
2024-06-28 20:17:47 -05:00
|
|
|
onSelect?: (tank: TankDefinition) => void;
|
2025-04-14 23:28:35 -05:00
|
|
|
};
|
2024-06-21 19:04:34 -05:00
|
|
|
|
2025-04-14 23:28:35 -05:00
|
|
|
export function SearchBar({ topResult, skeleton, onSelect }: SearchBarProps) {
|
2025-01-07 13:50:06 -06:00
|
|
|
const { strings } = useLocale();
|
2025-09-01 19:13:08 -05:00
|
|
|
const search = TankFilters.use((state) => state.search);
|
|
|
|
|
const searching = TankFilters.use((state) => state.searching);
|
2024-06-21 19:04:34 -05:00
|
|
|
const input = useRef<HTMLInputElement>(null);
|
2024-06-24 21:06:37 -05:00
|
|
|
const performSearch = useCallback(
|
2024-06-21 19:04:34 -05:00
|
|
|
debounce(() => {
|
2025-09-01 19:13:08 -05:00
|
|
|
TankFilters.mutate((draft) => {
|
|
|
|
|
draft.searching = false;
|
|
|
|
|
});
|
2024-06-21 19:04:34 -05:00
|
|
|
|
|
|
|
|
if (!input.current) return;
|
|
|
|
|
|
|
|
|
|
const sanitized = input.current.value.trim();
|
|
|
|
|
|
2025-09-01 19:13:08 -05:00
|
|
|
TankFilters.mutate((draft) => {
|
|
|
|
|
draft.search = sanitized.length === 0 ? null : sanitized;
|
|
|
|
|
});
|
2024-06-21 19:04:34 -05:00
|
|
|
}, 500),
|
2025-09-01 19:13:08 -05:00
|
|
|
[]
|
2024-06-21 19:04:34 -05:00
|
|
|
);
|
|
|
|
|
const handleChange = useCallback(() => {
|
2025-09-01 19:13:08 -05:00
|
|
|
if (!searching) {
|
|
|
|
|
TankFilters.mutate((draft) => {
|
|
|
|
|
draft.searching = true;
|
|
|
|
|
});
|
2024-06-24 21:06:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
performSearch();
|
2025-09-01 19:13:08 -05:00
|
|
|
}, [searching]);
|
2024-06-21 19:04:34 -05:00
|
|
|
const handleKeyDown = useCallback<KeyboardEventHandler>(
|
|
|
|
|
(event) => {
|
2025-09-01 19:13:08 -05:00
|
|
|
if (event.key !== "Enter" || !topResult || searching) return;
|
2024-06-21 19:04:34 -05:00
|
|
|
|
|
|
|
|
event.preventDefault();
|
2024-06-28 20:17:47 -05:00
|
|
|
|
|
|
|
|
if (onSelect) {
|
|
|
|
|
onSelect(topResult);
|
|
|
|
|
} else {
|
2025-05-15 23:44:20 -05:00
|
|
|
window.location.href = `/tanks/${topResult.slug}`;
|
2024-06-28 20:17:47 -05:00
|
|
|
}
|
2024-06-21 19:04:34 -05:00
|
|
|
},
|
2025-09-01 19:13:08 -05:00
|
|
|
[topResult]
|
2024-06-21 19:04:34 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
2024-10-24 17:32:46 -05:00
|
|
|
<Flex justify="center">
|
2024-06-24 13:54:08 -05:00
|
|
|
<Flex gap="2" flexGrow="1">
|
|
|
|
|
<TextField.Root
|
2025-04-21 17:01:32 -05:00
|
|
|
variant="classic"
|
2025-04-14 23:28:35 -05:00
|
|
|
disabled={skeleton}
|
2025-09-01 19:13:08 -05:00
|
|
|
defaultValue={search ?? undefined}
|
2024-06-24 13:54:08 -05:00
|
|
|
style={{ flex: 1 }}
|
|
|
|
|
ref={input}
|
2025-01-07 13:50:06 -06:00
|
|
|
placeholder={strings.website.common.tank_search.search_bar_hint}
|
2024-06-24 13:54:08 -05:00
|
|
|
onChange={handleChange}
|
|
|
|
|
onKeyDown={handleKeyDown}
|
|
|
|
|
>
|
2024-06-22 16:39:31 -05:00
|
|
|
<TextField.Slot>
|
2025-09-01 19:13:08 -05:00
|
|
|
{searching ? <Spinner /> : <MagnifyingGlassIcon />}
|
2024-06-22 16:39:31 -05:00
|
|
|
</TextField.Slot>
|
|
|
|
|
|
2024-06-24 21:06:37 -05:00
|
|
|
<QuickLink topResult={topResult} />
|
2024-06-24 13:54:08 -05:00
|
|
|
</TextField.Root>
|
|
|
|
|
|
|
|
|
|
<Sort />
|
|
|
|
|
</Flex>
|
2024-06-22 16:39:31 -05:00
|
|
|
</Flex>
|
2024-06-21 19:04:34 -05:00
|
|
|
);
|
|
|
|
|
}
|