Skip to content

Commit

Permalink
Refactor "location" and "sublocation" fields to support multiple valu…
Browse files Browse the repository at this point in the history
…es in advanced search (CQL)

This allow users to search across several locations or sublocations by using a comma-separated string in the input fields.
  • Loading branch information
kasperbirch1 committed Sep 18, 2024
1 parent c397e64 commit 53f4fb7
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 14 deletions.
15 changes: 10 additions & 5 deletions src/apps/advanced-search/AdvancedSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import React, { useEffect, useState } from "react";
import { useEffectOnce } from "react-use";
import AdvancedSearchHeader from "./AdvancedSearchHeader";
import AdvancedSearchResult from "./AdvancedSearchResults";
import { translateSearchObjectToCql } from "./helpers";
import {
commaSeparatedStringToArray,
translateSearchObjectToCql
} from "./helpers";
import { AdvancedSearchQuery } from "./types";
import {
getUrlQueryParam,
Expand Down Expand Up @@ -30,21 +33,23 @@ const AdvancedSearch: React.FC<AdvancedSearchProps> = ({ pageSize }) => {
const [executedQuery, setExecutedQuery] = useState<string | null>(null);

const [locationFilter, setLocationFilter] = useState<LocationFilter>({});

const handleLocationChange = (location: string) => {
setLocationFilter((prevFilter) => ({
...prevFilter,
location: [location]
location: commaSeparatedStringToArray(location)
}));
if (location) {
setQueryParametersInUrl({ location });
} else {
removeQueryParametersFromUrl("location");
}
};

const handleSublocationChange = (sublocation: string) => {
setLocationFilter((prevFilter) => ({
...prevFilter,
sublocation: [sublocation]
sublocation: commaSeparatedStringToArray(sublocation)
}));
if (sublocation) {
setQueryParametersInUrl({ sublocation });
Expand Down Expand Up @@ -98,15 +103,15 @@ const AdvancedSearch: React.FC<AdvancedSearchProps> = ({ pageSize }) => {
if (locationParam) {
setLocationFilter((prevFilter) => ({
...prevFilter,
location: [locationParam]
location: commaSeparatedStringToArray(locationParam)
}));
}

const sublocationParam = getUrlQueryParam("sublocation");
if (sublocationParam) {
setLocationFilter((prevFilter) => ({
...prevFilter,
sublocation: [sublocationParam]
sublocation: commaSeparatedStringToArray(sublocationParam)
}));
}
});
Expand Down
6 changes: 4 additions & 2 deletions src/apps/advanced-search/AdvancedSearchResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ const AdvancedSearchResult: React.FC<AdvancedSearchResultProps> = ({
filters: {
branchId: cleanBranches,
status: onShelf ? [HoldingsStatus.OnShelf] : [],
...(locationFilter?.location && { location: locationFilter.location }),
...(locationFilter?.sublocation && {
...(locationFilter?.location?.length && {
location: locationFilter.location
}),
...(locationFilter?.sublocation?.length && {
sublocation: locationFilter.sublocation
})
}
Expand Down
37 changes: 32 additions & 5 deletions src/apps/advanced-search/CqlSearchHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import React, { useEffect, useState } from "react";
import { useText } from "../../core/utils/text";
import CheckBox from "../../components/checkbox/Checkbox";
import TextInput from "../../components/atoms/input/TextInput";
Expand Down Expand Up @@ -33,6 +33,31 @@ const CqlSearchHeader: React.FC<CqlSearchHeaderProps> = ({
}
}, [initialCql, setCql]);

// Local state is needed to track input values as plain strings,
// since onLocationChange expects a comma-separated string,
// while locationFilter location and sublocation are provided as arrays.
const [inputValues, setInputValues] = useState({
location: locationFilter?.location?.join(", ") ?? "",
sublocation: locationFilter?.sublocation?.join(", ") ?? ""
});

const handleInputChange = (
name: "location" | "sublocation",
value: string
) => {
setInputValues((prevValues) => ({
...prevValues,
[name]: value
}));

if (name === "location") {
onLocationChange(value);
}
if (name === "sublocation") {
onSublocationChange(value);
}
};

return (
<>
<h1
Expand All @@ -54,15 +79,17 @@ const CqlSearchHeader: React.FC<CqlSearchHeaderProps> = ({
id="location"
label="Location"
type="text"
onChange={(location) => onLocationChange(location)}
value={locationFilter?.location?.[0] ?? ""}
onChange={(location) => handleInputChange("location", location)}
value={inputValues.location}
/>
<TextInput
id="Sublocation"
label="Sublocation"
type="text"
onChange={(sublocation) => onSublocationChange(sublocation)}
value={locationFilter?.sublocation?.[0] ?? ""}
onChange={(sublocation) =>
handleInputChange("sublocation", sublocation)
}
value={inputValues.sublocation}
/>
<CheckBox
id="on-shelf"
Expand Down
4 changes: 2 additions & 2 deletions src/apps/advanced-search/LocationFilter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export interface LocationFilter {
location?: [string];
sublocation?: [string];
location?: string[];
sublocation?: string[];
}
7 changes: 7 additions & 0 deletions src/apps/advanced-search/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,11 @@ export const shouldAdvancedSearchButtonBeDisabled = (
}
};

export const commaSeparatedStringToArray = (input: string): string[] => {
return input
.split(",")
.map((s) => s.trim())
.filter((s) => s.length > 0);
};

export default {};

0 comments on commit 53f4fb7

Please sign in to comment.