Skip to content

Commit e7d461b

Browse files
committed
feat: add custom ValueContainer for PluginTagSelect
1 parent a7a5798 commit e7d461b

File tree

6 files changed

+85
-17
lines changed

6 files changed

+85
-17
lines changed

src/Assets/Icon/ic-filter-applied.svg

Lines changed: 4 additions & 0 deletions
Loading

src/Assets/Icon/ic-filter.svg

Lines changed: 3 additions & 0 deletions
Loading

src/Shared/Components/Plugin/PluginListContainer.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ const PluginListContainer = ({
4646
parentFilters || structuredClone(DEFAULT_PLUGIN_LIST_FILTERS),
4747
)
4848
// Have to make a state to trigger clear filters, since filters are not on URL
49-
const [clearFiltersTrigger, setClearFiltersTrigger] = useState<boolean>(false)
49+
// TODO: Ask should it be number since in case of large state it can be a problem
50+
const [clearSearchTrigger, setClearSearchTrigger] = useState<boolean>(false)
51+
const [clearTagFilterTrigger, setClearTagFiltersTrigger] = useState<boolean>(false)
5052

5153
const handlePluginListUpdate = (updatedPluginList: PluginListItemType[]) => {
5254
setPluginList(updatedPluginList)
@@ -148,7 +150,8 @@ const PluginListContainer = ({
148150
showSelectedPlugins: false,
149151
})
150152

151-
setClearFiltersTrigger((prev) => !prev)
153+
setClearSearchTrigger((prev) => !prev)
154+
setClearTagFiltersTrigger((prev) => !prev)
152155
handlePersistFiltersChange()
153156
}
154157

@@ -176,6 +179,7 @@ const PluginListContainer = ({
176179
selectedTags: filterConfig.selectedTags,
177180
})
178181

182+
setClearTagFiltersTrigger((prev) => !prev)
179183
handlePersistFiltersChange()
180184
}
181185

@@ -212,7 +216,7 @@ const PluginListContainer = ({
212216
{/* Filters section */}
213217
<div className="w-100 flexbox dc__gap-12 py-12 dc__position-sticky dc__top-0 bcn-0 dc__zi-1">
214218
<SearchBar
215-
key={`search-bar-key-${Number(clearFiltersTrigger)}`}
219+
key={`search-bar-key-${Number(clearSearchTrigger)}`}
216220
containerClassName="flex-grow-1"
217221
handleEnter={handleSearch}
218222
inputProps={{
@@ -221,7 +225,7 @@ const PluginListContainer = ({
221225
/>
222226

223227
<PluginTagSelect
224-
key={`plugin-tag-select-key-${Number(clearFiltersTrigger)}`}
228+
key={`plugin-tag-select-key-${Number(clearTagFilterTrigger)}`}
225229
availableTags={availableTags}
226230
handleUpdateSelectedTags={handleUpdateSelectedTags}
227231
selectedTags={selectedTags}
@@ -232,7 +236,7 @@ const PluginListContainer = ({
232236

233237
{showSelectedPluginFilter && (
234238
<button
235-
className={`py-6 px-8 dc__gap-12 flex dc__outline-none-imp dc__tab-focus dc__tab-focus ${
239+
className={`py-6 px-8 dc__gap-12 flex dc__outline-none-imp dc__tab-focus dc__tab-focus dc__no-shrink ${
236240
showSelectedPlugins ? 'bc-n50 dc__border-n1' : 'dc__no-border dc__no-background'
237241
}`}
238242
data-testid="view-only-selected"

src/Shared/Components/Plugin/PluginTagSelect.tsx

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { useMemo, useState } from 'react'
1+
import { useCallback, useMemo, useState } from 'react'
22
import ReactSelect, { MenuListProps } from 'react-select'
33
import { Option, OptionType } from '../../../Common'
44
import { commonSelectStyles, LoadingIndicator, MenuListWithApplyButton } from '../ReactSelect'
55
import { GenericSectionErrorState } from '../GenericSectionErrorState'
66
import { PluginTagSelectProps } from './types'
7+
import { PluginTagSelectValueContainer } from './utils'
78

89
const PluginTagSelect = ({
910
availableTags,
@@ -26,24 +27,28 @@ const PluginTagSelect = ({
2627
setLocalSelectedOptions(selectedOptions)
2728
}
2829

29-
const handleApplyFilters = () => {
30-
handleUpdateSelectedTags(localSelectedOptions.map((option) => option.label))
31-
}
32-
3330
const handleMenuClose = () => {
3431
setLocalSelectedOptions(selectedTags?.map((tag) => ({ label: tag, value: tag })) ?? [])
3532
}
3633

3734
const renderNoOptionsMessage = () => {
3835
if (hasError) {
39-
return <GenericSectionErrorState withBorder reload={reloadTags} />
36+
return <GenericSectionErrorState reload={reloadTags} />
4037
}
4138
return <p className="m-0 cn-7 fs-13 fw-4 lh-20 py-6 px-8">No tags found</p>
4239
}
4340

44-
const renderMenuList = (props: MenuListProps) => (
45-
<MenuListWithApplyButton {...props} handleApplyFilter={handleApplyFilters} />
46-
)
41+
// TODO: Should i add handleUpdateSelectedTags as dependency?
42+
const renderMenuList = useCallback((props: MenuListProps) => {
43+
const selectedOptions: any = props.selectProps.value
44+
45+
// TODO: Should we create function here or inside MenuListWithApplyButton?
46+
const handleApplyFilters = () => {
47+
handleUpdateSelectedTags(selectedOptions.map((option) => option.value))
48+
}
49+
50+
return <MenuListWithApplyButton {...props} handleApplyFilter={handleApplyFilters} />
51+
}, [])
4752

4853
// TODO: Look if should close menu on apply
4954
return (
@@ -59,18 +64,20 @@ const PluginTagSelect = ({
5964
NoOptionsMessage: renderNoOptionsMessage,
6065
MenuList: renderMenuList,
6166
Option,
67+
ValueContainer: PluginTagSelectValueContainer,
6268
}}
6369
isLoading={isLoading}
6470
onChange={handleLocalSelection}
65-
escapeClearsValue={false}
71+
backspaceRemovesValue={false}
6672
closeMenuOnSelect={false}
6773
controlShouldRenderValue={false}
6874
hideSelectedOptions={false}
6975
blurInputOnSelect={false}
7076
maxMenuHeight={250}
7177
onMenuClose={handleMenuClose}
78+
placeholder="Select tags"
7279
inputId="plugin-tag-select"
73-
className="w-200"
80+
className="w-150"
7481
/>
7582
)
7683
}

src/Shared/Components/Plugin/utils.ts renamed to src/Shared/Components/Plugin/utils.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1+
import { cloneElement } from 'react'
2+
import { components, ValueContainerProps } from 'react-select'
13
import { ParentPluginDTO, PluginCreationType, PluginDataStoreType } from './types'
4+
import { ReactComponent as ICSearch } from '../../../Assets/Icon/ic-search.svg'
5+
import { ReactComponent as ICFilter } from '../../../Assets/Icon/ic-filter.svg'
6+
import { ReactComponent as ICFilterApplied } from '../../../Assets/Icon/ic-filter-applied.svg'
7+
import { OptionType } from '../../../Common'
28

39
const parseMinimalPluginVersionsDTO = (
410
pluginVersionData: ParentPluginDTO['pluginVersions']['minimalPluginVersionData'],
@@ -67,3 +73,47 @@ export const parsePluginDetailsDTOIntoPluginStore = (pluginData: ParentPluginDTO
6773
pluginVersionStore,
6874
}
6975
}
76+
77+
export const PluginTagSelectValueContainer = (props: ValueContainerProps<OptionType[]>) => {
78+
const { children, selectProps } = props
79+
80+
const renderContainer = () => {
81+
if (selectProps.menuIsOpen) {
82+
if (!selectProps.inputValue) {
83+
return (
84+
<>
85+
<ICSearch className="icon-dim-16 dc__no-shrink mr-4 mw-18" />
86+
<span className="dc__position-abs dc__left-35 cn-5 ml-2">{selectProps.placeholder}</span>
87+
</>
88+
)
89+
}
90+
91+
return <ICSearch className="icon-dim-16 dc__no-shrink mr-4 mw-18" />
92+
}
93+
94+
if (selectProps.value.length) {
95+
return (
96+
<>
97+
<ICFilterApplied className="icon-dim-16 dc__no-shrink mr-4 mw-18" />
98+
<span className="dc__position-abs dc__left-35 cn-9 fs-13 fw-4 lh-20">Category</span>
99+
</>
100+
)
101+
}
102+
103+
return (
104+
<>
105+
<ICFilter className="icon-dim-16 dc__no-shrink mr-4 mw-18" />
106+
<span className="dc__position-abs dc__left-35 cn-5 fs-13 fw-4 lh-20">Category</span>
107+
</>
108+
)
109+
}
110+
111+
return (
112+
<components.ValueContainer {...props}>
113+
<div className="flexbox dc__align-items-center">
114+
{renderContainer()}
115+
{cloneElement(children[1])}
116+
</div>
117+
</components.ValueContainer>
118+
)
119+
}

src/Shared/Components/ReactSelect/utils.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ export const MenuListWithApplyButton = ({
191191
}: MenuListProps & { handleApplyFilter: () => void }) => (
192192
<>
193193
<components.MenuList {...props} />
194-
<div className="p-8 dc__position-sticky dc__bottom-0 dc__border-top-n1 bcn-0">
194+
<div className="p-8 dc__position-sticky dc__bottom-0 dc__border-top-n1 bcn-0 dc__bottom-radius-4">
195195
<button
196196
type="button"
197197
className="dc__unset-button-styles w-100 br-4 h-28 flex bcb-5 cn-0 fw-6 lh-28 fs-12 h-28 br-4 pt-5 pr-12 pb-5 pl-12"

0 commit comments

Comments
 (0)