Skip to content

Commit

Permalink
Merge pull request #36 from NYPL/SCC-3802/search-form-controlled-2
Browse files Browse the repository at this point in the history
Make search form controlled component
  • Loading branch information
charmingduchess authored Oct 25, 2023
2 parents 982abf2 + 88cf912 commit aff8222
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 6 deletions.
4 changes: 3 additions & 1 deletion pages/search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ export default function Search({ results }) {
{totalResults ? (
<>
<Heading level="three">
{`Displaying 1-50 of ${totalResults.toLocaleString()} results for keyword "${
{`Displaying ${
totalResults > 50 ? "1-50" : totalResults.toLocaleString()
} of ${totalResults.toLocaleString()} results for keyword "${
searchParams.q
}"`}
</Heading>
Expand Down
51 changes: 51 additions & 0 deletions src/components/SearchForm/SearchForm.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from "react"
import { render, screen, fireEvent, act } from "@testing-library/react"
import mockRouter from "next-router-mock"

import SearchForm from "./SearchForm"
import userEvent from "@testing-library/user-event"

jest.mock("next/router", () => jest.requireActual("next-router-mock"))

describe("SearchForm", () => {
const submit = () =>
fireEvent(
screen.getByRole("button", { name: "Search" }),
new MouseEvent("click")
)
beforeEach(() => {
mockRouter.query.q = ""
})
afterEach(async () => {
const input = screen.getByRole("textbox")
await userEvent.clear(input)
})
it("submits a keyword query by default", async () => {
render(<SearchForm />)
const input = screen.getByRole("textbox")
await act(async () => {
await userEvent.type(input, "spaghetti")
submit()
expect(mockRouter.asPath).toBe("/search?q=spaghetti")
})
})
it("submits a journal_title query", async () => {
render(<SearchForm />)
const input = screen.getByRole("textbox")
const searchScopeSelect = screen.getByRole("combobox")
await act(async () => {
await userEvent.type(input, "spaghetti")
await userEvent.selectOptions(searchScopeSelect, "journal_title")
submit()
expect(mockRouter.asPath).toBe(
"/search?q=spaghetti&search_scope=journal_title"
)
})
})
it("gets keyword from url", () => {
mockRouter.query.q = "spaghetti"
render(<SearchForm />)
const input = screen.getByDisplayValue("spaghetti")
expect(input).toBeTruthy()
})
})
25 changes: 20 additions & 5 deletions src/components/SearchForm/SearchForm.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { SearchBar } from "@nypl/design-system-react-components"
import { useRouter } from "next/router"
import type { SyntheticEvent } from "react"
import type { SyntheticEvent, Dispatch, SetStateAction } from "react"
import { useState } from "react"

import styles from "../../../styles/components/Search.module.scss"
import RCLink from "../RCLink/RCLink"
import { getQueryString } from "../../utils/searchUtils"
import type { SearchFormEvent } from "../../types/searchTypes"
import { BASE_URL, PATHS } from "../../config/constants"

/**
Expand All @@ -14,19 +14,30 @@ import { BASE_URL, PATHS } from "../../config/constants"
*/
const SearchForm = () => {
const router = useRouter()
const [searchTerm, setSearchTerm] = useState(
(router?.query?.q as string) || ""
)
const [searchScope, setSearchScope] = useState("all")

const handleSubmit = async (e: SyntheticEvent) => {
e.preventDefault()
const target = e.target as typeof e.target & SearchFormEvent
const searchParams = {
q: target.q.value,
field: target.search_scope.value,
q: searchTerm,
field: searchScope,
}
const queryString = getQueryString(searchParams)

await router.push(`${PATHS.SEARCH}${queryString}`)
}

const handleChange = (
e: SyntheticEvent,
setValue: Dispatch<SetStateAction<string>>
) => {
const target = e.target as HTMLInputElement
setValue(target.value)
}

return (
<div className={styles.searchContainer}>
<div className={styles.searchContainerInner}>
Expand All @@ -38,6 +49,8 @@ const SearchForm = () => {
onSubmit={handleSubmit}
labelText="Search Bar Label"
selectProps={{
value: searchScope,
onChange: (e) => handleChange(e, setSearchScope),
labelText: "Select a category",
name: "search_scope",
optionsData: [
Expand All @@ -50,6 +63,8 @@ const SearchForm = () => {
],
}}
textInputProps={{
onChange: (e) => handleChange(e, setSearchTerm),
value: searchTerm,
labelText:
"Search by keyword, title, journal title, or author/contributor",
name: "q",
Expand Down

0 comments on commit aff8222

Please sign in to comment.