memorium/islands/Search.tsx

97 lines
2.9 KiB
TypeScript
Raw Normal View History

2023-08-06 00:33:06 +02:00
import { useEffect, useRef, useState } from "preact/hooks";
import useDebouncedCallback from "@lib/hooks/useDebouncedCallback.ts";
import { IconSearch } from "@components/icons.tsx";
import { useEventListener } from "@lib/hooks/useEventListener.ts";
export const RedirectSearchHandler = () => {
useEventListener("keydown", (e: KeyboardEvent) => {
if (e?.target?.nodeName == "INPUT") return;
if (
e.key === "?" &&
window.location.search === ""
) {
window.location.href += "?q=";
}
});
return <></>;
};
const SearchComponent = (
{ q, type }: { q: string; type?: string },
) => {
const [searchQuery, setSearchQuery] = useState(q);
const [data, setData] = useState<any[]>([]);
const [isLoading, setIsLoading] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
if ("history" in globalThis) {
const u = new URL(window.location.href);
if (u.searchParams.get("q") !== searchQuery) {
u.searchParams.set("q", searchQuery);
window.history.replaceState({}, "", u);
}
}
const fetchData = async (query: string) => {
try {
setIsLoading(true);
const fetchUrl = new URL(window.location.href);
fetchUrl.pathname = "/api/resources";
if (searchQuery) {
fetchUrl.searchParams.set("q", encodeURIComponent(searchQuery));
} else {
return;
}
if (type) {
fetchUrl.searchParams.set("type", type);
}
const response = await fetch(fetchUrl);
const jsonData = await response.json();
setData(jsonData);
setIsLoading(false);
} catch (error) {
console.error("Error fetching data:", error);
setIsLoading(false);
}
};
useEffect(() => {
if (inputRef.current && searchQuery?.length === 0) {
inputRef.current?.focus();
}
}, [inputRef.current, searchQuery]);
const debouncedFetchData = useDebouncedCallback(fetchData, 500); // Debounce the fetchData function with a delay of 500ms
const handleInputChange = (event: Event) => {
const target = event.target as HTMLInputElement;
setSearchQuery(target.value);
debouncedFetchData(target.value); // Call the debounced fetch function with the updated search query
};
return (
<div class="max-w-full">
<div class="bg-white flex items-center gap-1 w-full py-3 px-4 pr-12 rounded-xl border border-gray-300 placeholder-gray-400 focus:outline-none focus:ring-1 focus:ring-blue-600 focus:border-blue-600">
<IconSearch class="w-4 h-4" />
<input
type="text"
class=""
ref={inputRef}
value={searchQuery}
onInput={handleInputChange}
/>
</div>
{isLoading ? <div>Loading...</div> : (
<div>
{data.map((d) => (
<pre class="text-white">{JSON.stringify(d.document, null, 2)}</pre>
))}
</div>
)}
</div>
);
};
export default SearchComponent;