Skip to content

Commit 7ead65e

Browse files
KianNHRebeccaTamachiro
authored andcommitted
[Docs Site] Add product filter to /search/ (#21462)
1 parent 5bb8e38 commit 7ead65e

File tree

1 file changed

+117
-4
lines changed

1 file changed

+117
-4
lines changed

src/components/search/InstantSearch.tsx

Lines changed: 117 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { liteClient as algoliasearch } from "algoliasearch/lite";
2-
import { useEffect } from "react";
2+
import { useEffect, useState } from "react";
33
import {
44
InstantSearch,
55
Highlight,
@@ -8,7 +8,19 @@ import {
88
type UseSearchBoxProps,
99
useInfiniteHits,
1010
type UseInfiniteHitsProps,
11+
useRefinementList,
1112
} from "react-instantsearch";
13+
import {
14+
useFloating,
15+
useInteractions,
16+
useClick,
17+
useDismiss,
18+
shift,
19+
offset,
20+
autoUpdate,
21+
FloatingPortal,
22+
} from "@floating-ui/react";
23+
import { PiCaretDownBold } from "react-icons/pi";
1224

1325
function SearchBox(props: UseSearchBoxProps) {
1426
const { query, refine } = useSearchBox(props);
@@ -75,6 +87,102 @@ function InfiniteHits(props: UseInfiniteHitsProps) {
7587
);
7688
}
7789

90+
function FilterDropdown({
91+
attribute,
92+
label,
93+
}: {
94+
attribute: string;
95+
label: string;
96+
}) {
97+
const [isOpen, setIsOpen] = useState(false);
98+
const { items, refine } = useRefinementList({ attribute });
99+
100+
useEffect(() => {
101+
const params = new URLSearchParams(window.location.search);
102+
const values = params.get(attribute)?.split(",");
103+
104+
if (values && values.length !== 0) {
105+
for (const value of values) {
106+
refine(value);
107+
}
108+
}
109+
}, []);
110+
111+
useEffect(() => {
112+
const refined = items
113+
.filter((item) => item.isRefined)
114+
.map((item) => item.value);
115+
if (refined.length === 0) return;
116+
117+
history.pushState(
118+
null,
119+
"",
120+
`${window.location.pathname}?${attribute}=${refined.join(",")}`,
121+
);
122+
}, [items]);
123+
124+
const { refs, floatingStyles, context } = useFloating({
125+
open: isOpen,
126+
onOpenChange: setIsOpen,
127+
middleware: [shift(), offset(5)],
128+
whileElementsMounted: autoUpdate,
129+
});
130+
131+
const click = useClick(context);
132+
const dismiss = useDismiss(context);
133+
134+
const { getReferenceProps, getFloatingProps } = useInteractions([
135+
click,
136+
dismiss,
137+
]);
138+
139+
const selectedItems = items.filter((item) => item.isRefined);
140+
141+
return (
142+
<>
143+
<button
144+
ref={refs.setReference}
145+
{...getReferenceProps()}
146+
className="flex cursor-pointer items-center justify-center gap-2 rounded border border-cl1-gray-8 bg-transparent p-2 dark:border-cl1-gray-2"
147+
>
148+
<span>
149+
{label}
150+
{selectedItems.length > 0 && ` (${selectedItems.length})`}
151+
</span>
152+
<PiCaretDownBold />
153+
</button>
154+
{isOpen && (
155+
<FloatingPortal>
156+
<div
157+
ref={refs.setFloating}
158+
style={floatingStyles}
159+
{...getFloatingProps()}
160+
className="rounded border border-cl1-gray-8 bg-cl1-white p-4 shadow-md dark:border-cl1-gray-1 dark:bg-cl1-gray-0"
161+
>
162+
<div className="max-h-60 space-y-2 overflow-y-auto">
163+
{items.map((item) => (
164+
<label
165+
key={item.value}
166+
className="flex items-center gap-2 text-sm"
167+
>
168+
<input
169+
type="checkbox"
170+
checked={item.isRefined}
171+
onChange={() => refine(item.value)}
172+
/>
173+
<span>
174+
{item.label} ({item.count})
175+
</span>
176+
</label>
177+
))}
178+
</div>
179+
</div>
180+
</FloatingPortal>
181+
)}
182+
</>
183+
);
184+
}
185+
78186
export default function InstantSearchComponent() {
79187
return (
80188
<InstantSearch
@@ -87,9 +195,14 @@ export default function InstantSearchComponent() {
87195
preserveSharedStateOnUnmount: true,
88196
}}
89197
>
90-
<Configure facetFilters={["type:content"]} />
91-
<SearchBox />
92-
<InfiniteHits />
198+
<Configure filters="type:content" />
199+
<div className="space-y-4">
200+
<SearchBox />
201+
<div className="flex gap-2">
202+
<FilterDropdown attribute="product" label="Products" />
203+
</div>
204+
<InfiniteHits />
205+
</div>
93206
</InstantSearch>
94207
);
95208
}

0 commit comments

Comments
 (0)