refactored search bar url shenanigans

This commit is contained in:
mrjvs 2023-10-13 21:41:44 +02:00
parent 9f99049ba1
commit 7222abf567
5 changed files with 25 additions and 53 deletions

View File

@ -1,7 +1,6 @@
import c from "classnames"; import c from "classnames";
import { useState } from "react"; import { useState } from "react";
import { MWQuery } from "@/backend/metadata/types/mw";
import { Flare } from "@/components/utils/Flare"; import { Flare } from "@/components/utils/Flare";
import { Icon, Icons } from "./Icon"; import { Icon, Icons } from "./Icon";
@ -9,22 +8,16 @@ import { TextInputControl } from "./text-inputs/TextInputControl";
export interface SearchBarProps { export interface SearchBarProps {
placeholder?: string; placeholder?: string;
onChange: (value: MWQuery, force: boolean) => void; onChange: (value: string, force: boolean) => void;
onUnFocus: () => void; onUnFocus: () => void;
value: MWQuery; value: string;
} }
export function SearchBarInput(props: SearchBarProps) { export function SearchBarInput(props: SearchBarProps) {
const [focused, setFocused] = useState(false); const [focused, setFocused] = useState(false);
function setSearch(value: string) { function setSearch(value: string) {
props.onChange( props.onChange(value, false);
{
...props.value,
searchQuery: value,
},
false
);
} }
return ( return (
@ -59,7 +52,7 @@ export function SearchBarInput(props: SearchBarProps) {
}} }}
onFocus={() => setFocused(true)} onFocus={() => setFocused(true)}
onChange={(val) => setSearch(val)} onChange={(val) => setSearch(val)}
value={props.value.searchQuery} value={props.value}
className="w-full flex-1 bg-transparent px-4 py-4 pl-12 text-search-text placeholder-search-placeholder focus:outline-none sm:py-4 sm:pr-2" className="w-full flex-1 bg-transparent px-4 py-4 pl-12 text-search-text placeholder-search-placeholder focus:outline-none sm:py-4 sm:pr-2"
placeholder={props.placeholder} placeholder={props.placeholder}
/> />

View File

@ -5,13 +5,12 @@ export function useQueryParams() {
const loc = useLocation(); const loc = useLocation();
const queryParams = useMemo(() => { const queryParams = useMemo(() => {
// Basic absolutely-not-fool-proof URL query param parser
const obj: Record<string, string> = Object.fromEntries( const obj: Record<string, string> = Object.fromEntries(
new URLSearchParams(loc.search).entries() new URLSearchParams(loc.search).entries()
); );
return obj; return obj;
}, [loc]); }, [loc.search]);
return queryParams; return queryParams;
} }

View File

@ -1,54 +1,35 @@
import { useState } from "react"; import { useEffect, useState } from "react";
import { generatePath, useHistory, useParams } from "react-router-dom"; import { generatePath, useHistory, useParams } from "react-router-dom";
import { MWQuery } from "@/backend/metadata/types/mw";
import { useQueryParams } from "@/hooks/useQueryParams";
function getInitialValue(
query: Record<string, string>,
params: Record<string, string>
) {
let searchQuery = decodeURIComponent(params.query || "");
if (query.q) searchQuery = query.q;
return { searchQuery };
}
export function useSearchQuery(): [ export function useSearchQuery(): [
MWQuery, string,
(inp: Partial<MWQuery>, force: boolean) => void, (inp: string, force?: boolean) => void,
() => void () => void
] { ] {
const history = useHistory(); const history = useHistory();
const query = useQueryParams();
const params = useParams<{ query: string }>(); const params = useParams<{ query: string }>();
const [search, setSearch] = useState<MWQuery>(getInitialValue(query, params)); const [search, setSearch] = useState(params.query ?? "");
const updateParams = (inp: Partial<MWQuery>, force: boolean) => { useEffect(() => {
const copySearch = { ...search }; setSearch(params.query ?? "");
Object.assign(copySearch, inp); }, [params.query]);
setSearch(copySearch);
if (!force) return; const updateParams = (inp: string, commitToUrl = false) => {
if (copySearch.searchQuery.length === 0) { setSearch(inp);
if (!commitToUrl) return;
if (inp.length === 0) {
history.replace("/"); history.replace("/");
return; return;
} }
history.replace( history.replace(
generatePath("/browse/:query", { generatePath("/browse/:query", {
query: copySearch.searchQuery, query: inp,
}) })
); );
}; };
const onUnFocus = () => { const onUnFocus = () => {
if (search.searchQuery.length === 0) { updateParams(search, true);
history.replace("/");
return;
}
history.replace(
generatePath("/browse/:query", {
query: search.searchQuery,
})
);
}; };
return [search, updateParams, onUnFocus]; return [search, updateParams, onUnFocus];

View File

@ -2,7 +2,6 @@ import { useEffect, useState } from "react";
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { MWQuery } from "@/backend/metadata/types/mw";
import { WideContainer } from "@/components/layout/WideContainer"; import { WideContainer } from "@/components/layout/WideContainer";
import { useDebounce } from "@/hooks/useDebounce"; import { useDebounce } from "@/hooks/useDebounce";
import { useSearchQuery } from "@/hooks/useSearchQuery"; import { useSearchQuery } from "@/hooks/useSearchQuery";
@ -13,14 +12,14 @@ import { WatchingPart } from "@/pages/parts/home/WatchingPart";
import { SearchListPart } from "@/pages/parts/search/SearchListPart"; import { SearchListPart } from "@/pages/parts/search/SearchListPart";
import { SearchLoadingPart } from "@/pages/parts/search/SearchLoadingPart"; import { SearchLoadingPart } from "@/pages/parts/search/SearchLoadingPart";
function useSearch(search: MWQuery) { function useSearch(search: string) {
const [searching, setSearching] = useState<boolean>(false); const [searching, setSearching] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
const debouncedSearch = useDebounce<MWQuery>(search, 500); const debouncedSearch = useDebounce<string>(search, 500);
useEffect(() => { useEffect(() => {
setSearching(search.searchQuery !== ""); setSearching(search !== "");
setLoading(search.searchQuery !== ""); setLoading(search !== "");
}, [search]); }, [search]);
useEffect(() => { useEffect(() => {
setLoading(false); setLoading(false);

View File

@ -44,7 +44,7 @@ function SearchSuffix(props: { failed?: boolean; results?: number }) {
); );
} }
export function SearchListPart({ searchQuery }: { searchQuery: MWQuery }) { export function SearchListPart({ searchQuery }: { searchQuery: string }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [results, setResults] = useState<MWMediaMeta[]>([]); const [results, setResults] = useState<MWMediaMeta[]>([]);
@ -59,7 +59,7 @@ export function SearchListPart({ searchQuery }: { searchQuery: MWQuery }) {
setResults(searchResults); setResults(searchResults);
} }
if (searchQuery.searchQuery !== "") runSearch(searchQuery); if (searchQuery !== "") runSearch({ searchQuery });
}, [searchQuery, runSearchQuery]); }, [searchQuery, runSearchQuery]);
if (loading) return <SearchLoadingPart />; if (loading) return <SearchLoadingPart />;