diff --git a/src/components/BookGrid/BookGrid.tsx b/src/components/BookGrid/BookGrid.tsx
index b13a909..26c8444 100644
--- a/src/components/BookGrid/BookGrid.tsx
+++ b/src/components/BookGrid/BookGrid.tsx
@@ -1,6 +1,9 @@
+import { useState } from "react";
import { BookCard } from "../BookCard/BookCard";
+import { SearchBar } from "../SearchBar/SearchBar";
import styles from "./BookGrid.module.css";
import { useBooks } from "../../api/useBooks";
+import { useDebounce } from "./useDebounce";
import type { Book } from "../../api/types";
import { Pagination } from "../Pagination/Pagination";
import { SEARCH_LIMIT } from "../../api/openLibrary";
@@ -12,44 +15,66 @@ interface BookGridProps {
}
function BookGrid({ page, onBookSelect, onPageChange }: BookGridProps) {
+ const [searchQuery, setSearchQuery] = useState("");
+
+ const debouncedSearch = useDebounce(searchQuery, 500);
+ const query = debouncedSearch.trim() || "subject:fantasy";
+
const { data, isPending, isError, error } = useBooks({
- query: "subject:fantasy",
+ query,
page,
});
+ const searchBar = (
+
+ );
+
if (isPending) {
return (
-
- Loading books...
-
+ <>
+ {searchBar}
+
+ Loading books...
+
+ >
);
}
if (isError) {
return (
-
- Error: {error.message}
-
+ <>
+ {searchBar}
+
+ Error: {error.message}
+
+ >
);
}
if (!data || data.books.length === 0) {
return (
-
- No books found for this search
-
+ <>
+ {searchBar}
+
+ No books found for this search
+
+ >
);
}
return (
<>
-
- {data.books.map((book) => (
- -
-
-
- ))}
-
+ {searchBar}
+
+ <>
+
+ {data.books.map((book) => (
+ -
+
+
+ ))}
+
+ >
(value: T, delay: number): T {
+ const [debouncedValue, setDebouncedValue] = useState(value);
+
+ useEffect(() => {
+ const timeoutId = window.setTimeout(() => {
+ setDebouncedValue(value);
+ }, delay);
+
+ return () => {
+ window.clearTimeout(timeoutId);
+ };
+ }, [value, delay]);
+
+ return debouncedValue;
+}
+
+export { useDebounce };
diff --git a/src/components/SearchBar/SearchBar.module.css b/src/components/SearchBar/SearchBar.module.css
new file mode 100644
index 0000000..ea27572
--- /dev/null
+++ b/src/components/SearchBar/SearchBar.module.css
@@ -0,0 +1,22 @@
+.search-bar {
+ display: block;
+ width: 100%;
+ max-width: 500px;
+ padding: 10px 16px;
+ margin: 80px auto 0 auto;
+
+ border: 1px solid var(--border-color);
+ border-radius: var(--border-radius);
+ font-size: 1rem;
+ font-family: inherit;
+
+ &:hover {
+ border-color: var(--theme-color);
+ }
+
+ @media only screen and (max-width: 600px) {
+ width: calc(100% - 80px); /* Adjust width to account for the margins*/
+ margin: 40px 40px 0 40px;
+ max-width: none;
+ }
+}
diff --git a/src/components/SearchBar/SearchBar.tsx b/src/components/SearchBar/SearchBar.tsx
new file mode 100644
index 0000000..549df0b
--- /dev/null
+++ b/src/components/SearchBar/SearchBar.tsx
@@ -0,0 +1,22 @@
+import styles from "./SearchBar.module.css";
+
+interface SearchBarProps {
+ query: string;
+ onQueryChange: (newQuery: string) => void;
+}
+
+function SearchBar({ query, onQueryChange }: SearchBarProps) {
+ return (
+ onQueryChange(e.target.value)}
+ />
+ );
+}
+
+export { SearchBar };