Skip to content

Commit

Permalink
Allows strings in queryParams hook. Cleans up Results logic. Implemen…
Browse files Browse the repository at this point in the history
…ts FE "document type" filter.
  • Loading branch information
gdbarnes committed Nov 20, 2024
1 parent 1b0abce commit cf3e78d
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 80 deletions.
41 changes: 16 additions & 25 deletions react_front_end/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ import { NoResultsContent } from "./components/NoResultsContent"
const generateCheckedState = (checkboxes, queryValues) => checkboxes.map(({ name }) => queryValues.includes(name))

function App() {
const [searchInput, setSearchInput] = useState(useQueryParams("search")[0] || "")
const [searchQuery, setSearchQuery] = useQueryParams("search", [])
const [searchQuery, setSearchQuery] = useQueryParams("search", "")
const [docTypeQuery, setDocTypeQuery] = useQueryParams("document_type", [])
const [publisherQuery, setPublisherQuery] = useQueryParams("publisher", [])
const [sortQuery, setSortQuery] = useQueryParams("sort", ["recent"])
const [pageQuery, setPageQuery] = useQueryParams("page", [1])
const [sortQuery, setSortQuery] = useQueryParams("sort", "recent")
const [pageQuery, setPageQuery] = useQueryParams("page", 1)

const [searchInput, setSearchInput] = useState(searchQuery) // Set initial state to query parameter value
const [data, setData] = useState([])
const [isLoading, setIsLoading] = useState(true)
const [isSearchSubmitted, setIsSearchSubmitted] = useState(false)
Expand Down Expand Up @@ -80,15 +81,15 @@ function App() {

const handleSearchSubmit = useCallback(() => {
setIsSearchSubmitted(true)
setSearchQuery([searchInput])
setPageQuery([1])
setSearchQuery(searchInput)
setPageQuery(1) // Set the page to 1 when a new search is made

const filterParams = {
...(searchInput.length > 0 && { search: searchInput }),
...(docTypeQuery.length > 0 && { document_type: docTypeQuery }),
...(publisherQuery.length > 0 && { publisher: publisherQuery }),
sort: sortQuery.join(","),
page: 1,
sort: sortQuery,
page: 1, // Set page to 1 for new search
}

fetchDataWithLoading(filterParams)
Expand All @@ -101,22 +102,12 @@ function App() {
}

const handler = setTimeout(() => {
// This version is to send to the Django backend
// const queryString = new URLSearchParams({
// ...(searchQuery.length > 2 && { search: searchQuery.join(",") }),
// ...(docTypeQuery.length > 0 && { document_type: docTypeQuery.join(",") }),
// ...(publisherQuery.length > 0 && { publisher: publisherQuery.join(",") }),
// sort: sortQuery,
// page: pageQuery,
// }).toString()

// This version is for the S3 query
const filterParams = {
...(searchQuery.length > 0 && { search: searchQuery.join(",") }),
...(searchQuery.length > 0 && { search: searchQuery }),
...(docTypeQuery.length > 0 && { document_type: docTypeQuery }),
...(publisherQuery.length > 0 && { publisher: publisherQuery }),
sort: sortQuery.join(","),
page: pageQuery.join(","),
sort: sortQuery,
page: pageQuery,
}

fetchDataWithLoading(filterParams)
Expand All @@ -125,7 +116,7 @@ function App() {
return () => {
clearTimeout(handler)
}
}, [docTypeQuery, publisherQuery, sortQuery, pageQuery])
}, [searchQuery, docTypeQuery, publisherQuery, sortQuery, pageQuery])

return (
<div className="govuk-grid-row search-form">
Expand Down Expand Up @@ -170,11 +161,11 @@ function App() {
<a
id="download-csv-link"
href={`download_csv/?${new URLSearchParams({
search: searchQuery.join(","),
search: searchQuery,
document_type: docTypeQuery.join(","),
publisher: publisherQuery.join(","),
sort: sortQuery.join(","),
page: pageQuery.join(","),
sort: sortQuery,
page: pageQuery,
}).toString()}`}
className="govuk-link govuk-link--no-visited-state govuk-!-float-right"
>
Expand Down
4 changes: 2 additions & 2 deletions react_front_end/src/components/Pagination.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
function Pagination({ pageData, pageQuery, setPageQuery }) {
const handlePreviousPage = (e) => {
e.preventDefault()
setPageQuery([parseInt(pageQuery[0]) - 1])
setPageQuery([parseInt(pageQuery) - 1])
}

const handleNextPage = (e) => {
e.preventDefault()
setPageQuery([parseInt(pageQuery[0]) + 1])
setPageQuery([parseInt(pageQuery) + 1])
}

const { current_page, is_paginated, results_page_total } = pageData
Expand Down
38 changes: 17 additions & 21 deletions react_front_end/src/components/Results.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,35 @@ function Results({ results, isLoading, searchQuery }) {
}

const highlight = (text) => {
const searchWords = searchQuery.join("|")
const regex = new RegExp(searchWords, "gi")
const regex = new RegExp(searchQuery, "gi")
const highlightedText = text.replace(regex, (match) => `<mark class="orp-marked-text">${match}</mark>`)
return { __html: highlightedText }
}

const truncateDescription = (description, matchIndex) => {
const truncateAndHighlightDescription = (description) => {
const regex = new RegExp(searchQuery, "gi")
const matchIndex = description.search(regex)

let truncatedDescription
if (matchIndex === -1 || matchIndex <= 200) {
return description.length > 200 ? description.substring(0, 200) + "..." : description
truncatedDescription = description.length > 200 ? description.substring(0, 200) + "..." : description
} else {
const start = 0 // Always start from the beginning
const end = Math.min(description.length, matchIndex + 150) // Include some context after the match
return description.substring(start, end) + "..."
truncatedDescription = description.substring(start, end) + "..."
}

return <span dangerouslySetInnerHTML={highlight(truncatedDescription)} />
}

const renderRegulatoryTopics = (topics, searchQuery) => {
return topics.map((topic, index) => {
const highlightedTopic = topic.toLowerCase().includes(searchQuery[0].toLowerCase()) ? (
<span dangerouslySetInnerHTML={highlight(topic)} />
) : (
topic
)
const highlightedTopic =
searchQuery.length && topic.toLowerCase().includes(searchQuery.toLowerCase()) ? (
<span dangerouslySetInnerHTML={highlight(topic)} />
) : (
topic
)

return (
<li key={index} className="govuk-body-s orp-secondary-text-colour">
Expand All @@ -46,18 +52,8 @@ function Results({ results, isLoading, searchQuery }) {
{results.map((result) => {
const { id, type, title, description, publisher, date_modified, date_valid, regulatory_topics } = result

// Check if the search term appears within the first 200 characters
const searchWords = searchQuery.join("|")
const regex = new RegExp(searchWords, "gi")
const matchIndex = description.search(regex)

const truncatedDescription = truncateDescription(description, matchIndex)
// const highlightedTitle = title ? <span dangerouslySetInnerHTML={highlight(title)} /> : ""
const highlightedDescription = description ? (
<span dangerouslySetInnerHTML={highlight(truncatedDescription)} />
) : (
""
)
const highlightedDescription = description ? truncateAndHighlightDescription(description) : ""

// Format the date to the GOV.UK style
// We're now using the date_valid field instead of date_modified
Expand Down
2 changes: 1 addition & 1 deletion react_front_end/src/components/SortSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function SortSelect({ sortQuery, setSortQuery }) {
</label>
<select
className="govuk-select"
value={sortQuery[0]}
value={sortQuery}
onChange={handleSortChange}
id="sort-select"
aria-label="Sort by"
Expand Down
26 changes: 18 additions & 8 deletions react_front_end/src/hooks/useQueryParams.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ const getQuery = () => {
}

const getQueryStringVal = (key) => {
return getQuery().getAll(key)
const values = getQuery().getAll(key)
return values.length > 1 ? values : values[0] || ""
}

const useQueryParams = (key, defaultVal = []) => {
const [query, setQuery] = useState(getQueryStringVal(key).length ? getQueryStringVal(key) : defaultVal)
const initialQuery = getQueryStringVal(key)
const [query, setQuery] = useState(initialQuery.length ? initialQuery : defaultVal)

const updateUrl = (newVals) => {
setQuery(newVals)
Expand All @@ -23,13 +25,21 @@ const useQueryParams = (key, defaultVal = []) => {
query.delete(key)

// Set new values for the key
newVals.map((val) => {
if (typeof val === "string" && val.trim() !== "") {
query.append(key, val)
} else if (typeof val === "number") {
query.append(key, val.toString())
if (Array.isArray(newVals)) {
newVals.forEach((val) => {
if (typeof val === "string" && val.trim() !== "") {
query.append(key, val)
} else if (typeof val === "number") {
query.append(key, val.toString())
}
})
} else {
if (typeof newVals === "string" && newVals.trim() !== "") {
query.append(key, newVals)
} else if (typeof newVals === "number") {
query.append(key, newVals.toString())
}
})
}

if (typeof window !== "undefined") {
const { protocol, pathname, host } = window.location
Expand Down
16 changes: 4 additions & 12 deletions react_front_end/src/utils/constants.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
const DATA_API_URL = "http://localhost:8081/api/v1/search/"
// const DATA_API_URL = "https://data.api.trade.gov.uk/v1/"
// const DATASET = "orp-regulations"
// const VERSION = "v1.0.1" // latest causes a redirect which adds latency
// const FORMAT = "json"
// export const S3_QUERY = buildQuery(filters)
// export const ENCODED_S3_QUERY = encodeURI(S3_QUERY)

// export const DATASET_OBJECT_NAME = "uk_regulatory_documents"
// export const URL = `${DATA_API_URL}datasets/${DATASET}/versions/${VERSION}/data?format=${FORMAT}`
export const URL = `${DATA_API_URL}`
const DRF_API_URL = "http://localhost:8081/api/v1"
export const SEARCH_URL = `${DRF_API_URL}/search`
// export const PUBLISHERS_URL = `${DRF_API_URL}/retrieve/publishers/`

// These should come from the API/Django backend, but for now they are hardcoded
export const DOCUMENT_TYPES = [
Expand All @@ -21,7 +13,7 @@ export const DOCUMENT_TYPES = [
label: "Guidance",
},
{
name: "standards",
name: "standard",
label: "Standards",
},
]
Expand Down
21 changes: 10 additions & 11 deletions react_front_end/src/utils/fetch-drf.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import { URL, PUBLISHERS } from "./constants"
import { SEARCH_URL, PUBLISHERS } from "./constants"

function buildQuery(filters) {
const { search, document_type, publisher, sort, page } = filters
let query = ""

if (search && search.length > 2) {
query += `${search}`
}
console.log("Search/filter data from React: ", filters)

if (page) {
query += `&page=${page}`
}
const searchQuery = search && search.length > 2 ? `query=${search}` : ""
const documentTypeQuery = document_type ? document_type.map((type) => `document_type=${type}`).join("&") : ""
const pageQuery = page ? `page=${page}` : ""

let query = [searchQuery, documentTypeQuery, pageQuery].filter((q) => q.length > 0).join("&")

return query
}

export async function fetchData(filters) {
const query = buildQuery(filters)
console.log("Searching for: ", query)

// const encodedQuery = encodeURI(query)
const url = `${URL}?query=${query}`
const url = `${SEARCH_URL}?${query}`

console.log("Fetching data: ", url)

try {
const response = await fetch(url)
Expand Down

0 comments on commit cf3e78d

Please sign in to comment.