Skip to content

Commit ed0d05a

Browse files
committed
feat(#1349080): Add facet search bar in example app
1 parent def47de commit ed0d05a

File tree

4 files changed

+123
-27
lines changed

4 files changed

+123
-27
lines changed

front/example-app/src/components/Facets/Facet.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,13 @@ function Facet(props: IProps): JSX.Element {
8080
id={id}
8181
loadMore={loadMore}
8282
moreOptions={moreOptions}
83-
renderOption={(option): JSX.Element => (
83+
onOptionChange={onChange}
84+
renderOption={(option, onOptionChange): JSX.Element => (
8485
<FacetCategory
8586
key={String(option.value)}
8687
activeOptions={activeOptions}
8788
filter={filter}
88-
onChange={onChange}
89+
onChange={onOptionChange}
8990
option={option}
9091
/>
9192
)}
@@ -108,12 +109,13 @@ function Facet(props: IProps): JSX.Element {
108109
id={id}
109110
loadMore={loadMore}
110111
moreOptions={moreOptions}
111-
renderOption={(option): JSX.Element => (
112+
onOptionChange={onChange}
113+
renderOption={(option, onOptionChange): JSX.Element => (
112114
<FacetChoice
113115
key={String(option.value)}
114116
activeOptions={activeOptions}
115117
filter={filter}
116-
onChange={onChange}
118+
onChange={onOptionChange}
117119
option={option}
118120
/>
119121
)}
@@ -127,12 +129,13 @@ function Facet(props: IProps): JSX.Element {
127129
id={id}
128130
loadMore={loadMore}
129131
moreOptions={moreOptions}
130-
renderOption={(option): JSX.Element => (
132+
onOptionChange={onChange}
133+
renderOption={(option, onOptionChange): JSX.Element => (
131134
<FacetChoice
132135
key={String(option.value)}
133136
activeOptions={activeOptions}
134137
filter={filter}
135-
onChange={onChange}
138+
onChange={onOptionChange}
136139
option={option}
137140
/>
138141
)}

front/example-app/src/components/Facets/FacetLoadMore.tsx

Lines changed: 106 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,134 @@
1-
import { Button, Collapse, FormGroup } from '@mui/material'
1+
import React, { ChangeEvent, useMemo, useState } from 'react'
2+
import { Button, FormGroup, TextField, styled } from '@mui/material'
23
import {
34
IFetch,
45
IGraphqlAggregation,
56
IGraphqlAggregationOption,
67
IGraphqlViewMoreFacetOption,
8+
LoadStatus,
79
} from '@elastic-suite/gally-admin-shared'
10+
import { IFilterChange } from '../../types'
11+
12+
const SearchOption = styled(TextField)(() => ({
13+
width: '100%',
14+
}))
15+
16+
const NoOption = styled('div')(({ theme }) => ({
17+
color: '#AA0000',
18+
backgroundColor: '#FFEEEE',
19+
marginBottom: theme.spacing(1),
20+
padding: theme.spacing(1),
21+
}))
822

923
interface IProps {
1024
filter: IGraphqlAggregation
1125
id: string
12-
loadMore: (filter: IGraphqlAggregation) => void
26+
loadMore: (filter: IGraphqlAggregation, optionSearch?: string) => void
1327
moreOptions?: IFetch<IGraphqlViewMoreFacetOption[]>
14-
renderOption: (option: IGraphqlAggregationOption) => JSX.Element
28+
renderOption: (
29+
option: IGraphqlAggregationOption,
30+
onOptionChange: IFilterChange
31+
) => JSX.Element
32+
onOptionChange: IFilterChange
33+
}
34+
35+
function getFirstLabelsString(items: IGraphqlAggregationOption[]): string {
36+
const labels = items.slice(0, 2).map((i) => i.label)
37+
if (items.length > 2) {
38+
labels.push('...')
39+
}
40+
return labels.join(', ')
1541
}
1642

1743
function FacetLoadMore(props: IProps): JSX.Element {
18-
const { filter, id, loadMore, moreOptions, renderOption } = props
19-
const open = moreOptions?.data?.length > 0
44+
const { filter, id, loadMore, moreOptions, renderOption, onOptionChange } =
45+
props
46+
47+
const [optionSearch, setOptionSearch] = useState<string>('')
48+
const [showMore, setShowMore] = useState<boolean>(false)
2049

21-
function handleToggleMore(): void {
22-
loadMore(filter)
50+
const searchOptionLabel = useMemo(() => {
51+
const labels = getFirstLabelsString(filter.options)
52+
return labels ? `Search (${labels})` : 'Search'
53+
}, [filter.options])
54+
55+
function handleToggleMore(showMoreEnabled: boolean): void {
56+
setShowMore(showMoreEnabled)
57+
if (showMoreEnabled) {
58+
loadMore(filter, optionSearch)
59+
}
2360
}
2461

62+
function handleOptionSearchChange(value: string): void {
63+
setOptionSearch(value)
64+
if (!value) {
65+
setShowMore(false)
66+
} else {
67+
setShowMore(true)
68+
}
69+
loadMore(filter, value)
70+
}
71+
72+
function handleOptionChange(filter: IGraphqlAggregation, value: string) {
73+
return () => {
74+
// Empty the search facet field when a value is selected.
75+
setOptionSearch('')
76+
onOptionChange(filter, value)()
77+
}
78+
}
79+
80+
const options =
81+
showMore &&
82+
!moreOptions?.error &&
83+
moreOptions?.status === LoadStatus.SUCCEEDED
84+
? moreOptions?.data
85+
: filter.options
86+
87+
const showShowMore = !showMore || options === filter.options
88+
const canShowToggleButtons = Boolean(filter.hasMore) && !optionSearch
89+
2590
return (
2691
<>
27-
{!moreOptions?.data && (
28-
<FormGroup aria-labelledby={id}>
29-
{filter.options.map(renderOption)}
30-
</FormGroup>
92+
{Boolean(filter.hasMore) && (
93+
<>
94+
<SearchOption
95+
id="outlined-basic"
96+
label={searchOptionLabel}
97+
variant="outlined"
98+
name="searchOption"
99+
value={optionSearch}
100+
onChange={(e: ChangeEvent<HTMLInputElement>): void =>
101+
handleOptionSearchChange(e.target.value)
102+
}
103+
size="small"
104+
/>
105+
{Boolean(optionSearch) &&
106+
((moreOptions?.status === LoadStatus.SUCCEEDED &&
107+
moreOptions?.data?.length < 1) ||
108+
Boolean(moreOptions?.error)) && (
109+
<NoOption>
110+
{moreOptions?.error
111+
? 'An error occured'
112+
: `No value matching the search "${optionSearch}"`}
113+
</NoOption>
114+
)}
115+
</>
31116
)}
32-
<Collapse in={open}>
33-
<FormGroup aria-labelledby={id}>
34-
{moreOptions?.data?.map(renderOption)}
35-
</FormGroup>
36-
</Collapse>
37-
{Boolean(filter.hasMore) && !open && (
117+
<FormGroup aria-labelledby={id}>
118+
{options?.map((option) => renderOption(option, handleOptionChange))}
119+
</FormGroup>
120+
{canShowToggleButtons && (showShowMore || Boolean(moreOptions?.error)) ? (
38121
<Button
39122
disabled={Boolean(moreOptions?.error)}
40-
onClick={handleToggleMore}
123+
onClick={(): void => handleToggleMore(true)}
41124
>
42125
{moreOptions?.error ? 'An error occured' : 'Show more'}
43126
</Button>
44-
)}
127+
) : null}
128+
129+
{canShowToggleButtons && !showShowMore && !moreOptions?.error ? (
130+
<Button onClick={(): void => handleToggleMore(false)}>Show less</Button>
131+
) : null}
45132
</>
46133
)
47134
}

front/example-app/src/hooks/useDocuments.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export function useDocuments(
101101
)
102102

103103
const loadMore = useCallback(
104-
(filter: IGraphqlAggregation) => {
104+
(filter: IGraphqlAggregation, optionSearch?: string) => {
105105
const variables: IGraphqlViewMoreFacetOptionsVariables = {
106106
aggregation: filter.field,
107107
localizedCatalog: String(localizedCatalogId),
@@ -110,6 +110,9 @@ export function useDocuments(
110110
if (search) {
111111
variables.search = search
112112
}
113+
if (optionSearch) {
114+
variables.optionSearch = optionSearch
115+
}
113116
graphqlApi<IGraphqlViewMoreFacetOptions>(
114117
getMoreFacetOptionsQuery(queryFilters),
115118
variables as unknown as Record<string, unknown>

front/example-app/src/hooks/useProducts.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export function useProducts(
124124
)
125125

126126
const loadMore = useCallback(
127-
(filter: IGraphqlAggregation) => {
127+
(filter: IGraphqlAggregation, optionSearch?: string) => {
128128
const variables: IGraphqlViewMoreProductFacetOptionsVariables = {
129129
aggregation: filter.field,
130130
localizedCatalog: String(localizedCatalogId),
@@ -135,6 +135,9 @@ export function useProducts(
135135
if (search) {
136136
variables.search = search
137137
}
138+
if (optionSearch) {
139+
variables.optionSearch = optionSearch
140+
}
138141
if (currentCategoryId) {
139142
variables.currentCategoryId = currentCategoryId
140143
}

0 commit comments

Comments
 (0)