mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-27 10:11:48 +01:00
refactored search bar url shenanigans
This commit is contained in:
parent
9f99049ba1
commit
7222abf567
@ -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}
|
||||||
/>
|
/>
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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];
|
||||||
|
@ -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);
|
||||||
|
@ -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 />;
|
||||||
|
Loading…
Reference in New Issue
Block a user