Skip to content

Commit b62a85e

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

File tree

3 files changed

+96
-19
lines changed

3 files changed

+96
-19
lines changed

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

Lines changed: 88 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,118 @@
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'
810

11+
const SearchOption = styled(TextField)(() => ({
12+
width: '100%',
13+
}))
14+
15+
const NoOption = styled('div')(({ theme }) => ({
16+
color: '#AA0000',
17+
backgroundColor: '#FFEEEE',
18+
marginBottom: theme.spacing(1),
19+
padding: theme.spacing(1),
20+
}))
21+
922
interface IProps {
1023
filter: IGraphqlAggregation
1124
id: string
12-
loadMore: (filter: IGraphqlAggregation) => void
25+
loadMore: (filter: IGraphqlAggregation, optionSearch?: string) => void
1326
moreOptions?: IFetch<IGraphqlViewMoreFacetOption[]>
1427
renderOption: (option: IGraphqlAggregationOption) => JSX.Element
1528
}
1629

30+
function getFirstLabelsString(items: IGraphqlAggregationOption[]): string {
31+
const labels = items.slice(0, 2).map((i) => i.label)
32+
if (items.length > 2) {
33+
labels.push('...')
34+
}
35+
return labels.join(', ')
36+
}
37+
1738
function FacetLoadMore(props: IProps): JSX.Element {
1839
const { filter, id, loadMore, moreOptions, renderOption } = props
19-
const open = moreOptions?.data?.length > 0
2040

21-
function handleToggleMore(): void {
22-
loadMore(filter)
41+
const [optionSearch, setOptionSearch] = useState<string>('')
42+
const [showMore, setShowMore] = useState<boolean>(false)
43+
44+
const searchOptionLabel = useMemo(() => {
45+
const labels = getFirstLabelsString(filter.options)
46+
return labels ? `Search (${labels})` : 'Search'
47+
}, [filter.options])
48+
49+
function handleToggleMore(showMoreEnabled: boolean): void {
50+
setShowMore(showMoreEnabled)
51+
if (showMoreEnabled) {
52+
loadMore(filter, optionSearch)
53+
}
2354
}
2455

56+
function handleOptionSearchChange(value: string): void {
57+
setOptionSearch(value)
58+
if (!value) {
59+
setShowMore(false)
60+
} else {
61+
setShowMore(true)
62+
}
63+
loadMore(filter, value)
64+
}
65+
66+
const options =
67+
showMore &&
68+
!moreOptions?.error &&
69+
moreOptions?.status === LoadStatus.SUCCEEDED
70+
? moreOptions?.data
71+
: filter.options
72+
73+
const showShowMore = !showMore || options === filter.options
74+
const canShowToggleButtons = Boolean(filter.hasMore) && !optionSearch
75+
2576
return (
2677
<>
27-
{!moreOptions?.data && (
28-
<FormGroup aria-labelledby={id}>
29-
{filter.options.map(renderOption)}
30-
</FormGroup>
78+
{Boolean(filter.hasMore) && (
79+
<>
80+
<SearchOption
81+
id="outlined-basic"
82+
label={searchOptionLabel}
83+
variant="outlined"
84+
name="searchOption"
85+
value={optionSearch}
86+
onChange={(e: ChangeEvent<HTMLInputElement>): void =>
87+
handleOptionSearchChange(e.target.value)
88+
}
89+
size="small"
90+
/>
91+
{Boolean(optionSearch) &&
92+
((moreOptions?.status === LoadStatus.SUCCEEDED &&
93+
moreOptions?.data?.length < 1) ||
94+
Boolean(moreOptions?.error)) && (
95+
<NoOption>
96+
{moreOptions?.error
97+
? 'An error occured'
98+
: `No value matching the search "${optionSearch}"`}
99+
</NoOption>
100+
)}
101+
</>
31102
)}
32-
<Collapse in={open}>
33-
<FormGroup aria-labelledby={id}>
34-
{moreOptions?.data?.map(renderOption)}
35-
</FormGroup>
36-
</Collapse>
37-
{Boolean(filter.hasMore) && !open && (
103+
<FormGroup aria-labelledby={id}>{options?.map(renderOption)}</FormGroup>
104+
{canShowToggleButtons && (showShowMore || Boolean(moreOptions?.error)) ? (
38105
<Button
39106
disabled={Boolean(moreOptions?.error)}
40-
onClick={handleToggleMore}
107+
onClick={(): void => handleToggleMore(true)}
41108
>
42109
{moreOptions?.error ? 'An error occured' : 'Show more'}
43110
</Button>
44-
)}
111+
) : null}
112+
113+
{canShowToggleButtons && !showShowMore && !moreOptions?.error ? (
114+
<Button onClick={(): void => handleToggleMore(false)}>Show less</Button>
115+
) : null}
45116
</>
46117
)
47118
}

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)