diff --git a/client/src/data/searchBooks.ts b/client/src/data/searchBooks.ts new file mode 100644 index 0000000..3ba79a1 --- /dev/null +++ b/client/src/data/searchBooks.ts @@ -0,0 +1,12 @@ +import type { Book } from '../types/book'; + +export function searchBooks(books: Book[], query: string): Book[] { + const term = query.trim().toLowerCase(); + if (term === '') return books; //if the seach is empty, show everything + + return books.filter( + (book) => + book.title.toLowerCase().includes(term) || + book.authors.some((author) => author.toLowerCase().includes(term)), + ); +} diff --git a/client/src/pages/BrowsePage/BrowsePage.tsx b/client/src/pages/BrowsePage/BrowsePage.tsx index aa86efc..069c856 100644 --- a/client/src/pages/BrowsePage/BrowsePage.tsx +++ b/client/src/pages/BrowsePage/BrowsePage.tsx @@ -1,11 +1,27 @@ import { useState } from 'react'; +import { useSearchParams } from 'react-router'; import type { Book } from '../../types/book'; import { BookGrid } from '../../components/BookGrid/BookGrid'; +import { EmptyState } from '../../components/EmptyState/EmptyState'; +import { LoadingState } from '../../components/LoadingState/LoadingState'; import { mockBooks, mockShelfEntries, type ShelfEntry } from '../../data/mockBooks'; +import { searchBooks } from '../../data/searchBooks'; import styles from './BrowsePage.module.css'; -import { LoadingState } from '../../components/LoadingState/LoadingState'; export function BrowsePage() { + const [searchParams, setSearchParams] = useSearchParams(); + const query = searchParams.get('q') ?? ''; + + function handleSearch(next: string) { + setSearchParams((prev) => { + const params = new URLSearchParams(prev); + if (next) params.set('q', next); + else params.delete('q'); //empty search = clean URL + return params; + }); + } + //shelf + const [shelf, setShelf] = useState>( () => new Map(mockShelfEntries.map((entry) => [entry.bookId, entry])), ); @@ -22,21 +38,41 @@ export function BrowsePage() { }); } - const books = mockBooks; - + //temporary: search the mock data, replaced by the apollo query + const books = searchBooks(mockBooks, query); // ===== TEMPORARY: fake loading state, replace with the query's `loading` ===== const isLoading = false; + const noResults = !isLoading && query !== '' && books.length === 0; return (

- browse + Browse

-

{books.length} books

+

+ {resultLabel(books.length, query)} +

+ {isLoading && } - + + {noResults ? ( + handleSearch('') }} + /> + ) : ( + + )}
); } + +//resultLabel: the count next to the heading +function resultLabel(count: number, query: string) { + if (!query) return count === 1 ? '1book' : `${count} books`; + const results = count === 1 ? 'result' : 'results'; + return `Searchword: "${query}" gave ${count} ${results}`; +}