1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00

Merge pull request #400 from oceanprotocol/feature/issue392

Search filter bar
This commit is contained in:
Matthias Kretschmann 2021-03-02 16:16:39 +01:00 committed by GitHub
commit feef24ddd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 204 additions and 77 deletions

View File

@ -1,17 +1,27 @@
.filterList,
div.filterList {
white-space: normal;
margin-bottom: 0;
}
.filter {
display: inline-block;
}
.filter,
button.filter,
.filter:hover,
.filter:active,
.filter:focus {
border: 1px solid var(--border-color);
text-transform: uppercase;
border-radius: var(--border-radius);
margin-right: calc(var(--spacer) / 6);
margin-bottom: calc(var(--spacer) / 6);
color: var(--color-secondary);
background: var(--background-content);
/* the only thing not possible to overwrite button style="text" with more specifity of selectors, so sledgehammer */
padding: calc(var(--spacer) / 5) !important;
padding: calc(var(--spacer) / 6) !important;
}
.filter:hover,
@ -27,6 +37,20 @@ button.filter,
border-color: var(--background-body);
}
.filterList:first-of-type {
margin-bottom: calc(var(--spacer) / 6);
.filter.selected::after {
content: '✕';
margin-left: calc(var(--spacer) / 6);
color: var(--background-body);
}
.showClear {
display: inline-flex;
text-transform: capitalize;
color: var(--color-secondary);
font-weight: var(--font-weight-base);
margin-left: calc(var(--spacer) / 6);
}
.hideClear {
display: none !important;
}

View File

@ -1,4 +1,4 @@
import React, { ReactElement } from 'react'
import React, { ReactElement, useEffect, useState } from 'react'
import { useNavigate } from '@reach/router'
import styles from './filterPrice.module.css'
import classNames from 'classnames/bind'
@ -11,22 +11,22 @@ import Button from '../../atoms/Button'
const cx = classNames.bind(styles)
const filterItemsPrice = [
{ display: 'all', value: undefined },
const clearFilters = [{ display: 'Clear', value: '' }]
const priceFilterItems = [
{ display: 'fixed price', value: FilterByPriceOptions.Fixed },
{ display: 'dynamic price', value: FilterByPriceOptions.Dynamic }
]
const filterItemsType = [
{ display: 'all', value: undefined },
{ display: 'algorithms', value: FilterByTypeOptions.Algorithm },
{ display: 'data sets', value: FilterByTypeOptions.Data }
const serviceFilterItems = [
{ display: 'data sets', value: FilterByTypeOptions.Data },
{ display: 'algorithms', value: FilterByTypeOptions.Algorithm }
]
export default function FilterPrice({
priceType,
setPriceType,
serviceType,
setPriceType,
setServiceType
}: {
priceType: string
@ -36,7 +36,10 @@ export default function FilterPrice({
}): ReactElement {
const navigate = useNavigate()
async function applyFilter(filterBy: string) {
const [priceSelections, setPriceSelections] = useState<string[]>([])
const [serviceSelections, setServiceSelections] = useState<string[]>([])
async function applyPriceFilter(filterBy: string) {
let urlLocation = await addExistingParamsToUrl(location, 'priceType')
if (filterBy) {
urlLocation = `${urlLocation}&priceType=${filterBy}`
@ -45,59 +48,141 @@ export default function FilterPrice({
navigate(urlLocation)
}
async function applyTypeFilter(filterBy: string) {
async function applyServiceFilter(filterBy: string) {
let urlLocation = await addExistingParamsToUrl(location, 'serviceType')
if (filterBy) {
if (filterBy && location.search.indexOf('&serviceType') === -1) {
urlLocation = `${urlLocation}&serviceType=${filterBy}`
}
setServiceType(filterBy)
navigate(urlLocation)
}
async function handleSelectedFilter(isSelected: boolean, value: string) {
if (
value === FilterByPriceOptions.Fixed ||
value === FilterByPriceOptions.Dynamic
) {
if (isSelected) {
if (priceSelections.length > 1) {
// both selected -> select the other one
const otherValue = priceFilterItems.find((p) => p.value !== value)
.value
await applyPriceFilter(otherValue)
} else {
// only the current one selected -> deselect it
await applyPriceFilter(undefined)
}
} else {
if (priceSelections.length > 0) {
// one already selected -> both selected
await applyPriceFilter(FilterByPriceOptions.All)
setPriceSelections(priceFilterItems.map((p) => p.value))
} else {
// none selected -> select
await applyPriceFilter(value)
setPriceSelections([value])
}
}
} else {
if (isSelected) {
if (serviceSelections.length > 1) {
const otherValue = serviceFilterItems.find((p) => p.value !== value)
.value
await applyServiceFilter(otherValue)
setServiceSelections([otherValue])
} else {
await applyServiceFilter(undefined)
}
} else {
if (serviceSelections.length) {
await applyServiceFilter(undefined)
setServiceSelections(serviceFilterItems.map((p) => p.value))
} else {
await applyServiceFilter(value)
setServiceSelections([value])
}
}
}
}
async function applyClearFilter() {
let urlLocation = await addExistingParamsToUrl(
location,
'priceType',
'serviceType'
)
urlLocation = `${urlLocation}`
setServiceSelections([])
setPriceSelections([])
setPriceType(undefined)
setServiceType(undefined)
navigate(urlLocation)
}
return (
<div>
<div className={styles.filterList}>
{filterItemsType.map((e, index) => {
const filter = cx({
[styles.selected]: e.value === serviceType,
[styles.filter]: true
})
return (
<Button
size="small"
style="text"
key={index}
className={filter}
onClick={async () => {
await applyTypeFilter(e.value)
}}
>
{e.display}
</Button>
)
})}
</div>
<div className={styles.filterList}>
{filterItemsPrice.map((e, index) => {
const filter = cx({
[styles.selected]: e.value === priceType,
[styles.filter]: true
})
return (
<Button
size="small"
style="text"
key={index}
className={filter}
onClick={async () => {
await applyFilter(e.value)
}}
>
{e.display}
</Button>
)
})}
</div>
<div className={styles.filterList}>
{priceFilterItems.map((e, index) => {
const isPriceSelected =
e.value === priceType || priceSelections.includes(e.value)
const selectFilter = cx({
[styles.selected]: isPriceSelected,
[styles.filter]: true
})
return (
<Button
size="small"
style="text"
key={index}
className={selectFilter}
onClick={async () => {
handleSelectedFilter(isPriceSelected, e.value)
}}
>
{e.display}
</Button>
)
})}
{serviceFilterItems.map((e, index) => {
const isServiceSelected =
e.value === serviceType || serviceSelections.includes(e.value)
const selectFilter = cx({
[styles.selected]: isServiceSelected,
[styles.filter]: true
})
return (
<Button
size="small"
style="text"
key={index}
className={selectFilter}
onClick={async () => {
handleSelectedFilter(isServiceSelected, e.value)
}}
>
{e.display}
</Button>
)
})}
{clearFilters.map((e, index) => {
const showClear =
priceSelections.length > 0 || serviceSelections.length > 0
return (
<Button
size="small"
style="text"
key={index}
className={showClear ? styles.showClear : styles.hideClear}
onClick={async () => {
applyClearFilter()
}}
>
{e.display}
</Button>
)
})}
</div>
)
}

View File

@ -34,7 +34,7 @@ export default function SearchPage({
const [queryResult, setQueryResult] = useState<QueryResult>()
const [loading, setLoading] = useState<boolean>()
const [price, setPriceType] = useState<string>(priceType as string)
const [type, setType] = useState<string>(serviceType as string)
const [service, setServiceType] = useState<string>(serviceType as string)
const [sortType, setSortType] = useState<string>(sort as string)
const [sortDirection, setSortDirection] = useState<string>(
sortOrder as string
@ -82,9 +82,9 @@ export default function SearchPage({
<div className={styles.row}>
<PriceFilter
priceType={price}
serviceType={service}
setPriceType={setPriceType}
serviceType={type}
setServiceType={setType}
setServiceType={setServiceType}
/>
<Sort
sortType={sortType}
@ -92,6 +92,7 @@ export default function SearchPage({
setSortType={setSortType}
setSortDirection={setSortDirection}
setPriceType={setPriceType}
setServiceType={setServiceType}
/>
</div>
</div>

View File

@ -1,11 +1,18 @@
.sortList {
align-self: flex-end;
padding: calc(var(--spacer) / 10);
padding: 0 calc(var(--spacer) / 10);
display: flex;
align-items: center;
border-radius: var(--border-radius);
border: 1px solid var(--border-color);
background: var(--background-content);
overflow-y: auto;
}
@media (min-width: 40rem) {
.sortList {
align-self: flex-end;
overflow-y: unset;
}
}
.sortLabel {
@ -15,6 +22,7 @@
margin-right: calc(var(--spacer) / 1.5);
text-transform: uppercase;
color: var(--color-secondary);
font-size: var(--font-size-small);
}
.sorted {
@ -25,7 +33,7 @@
text-transform: capitalize;
border-radius: 0;
font-weight: var(--font-weight-base);
background: var(--background-body);
background: var(--background-content);
box-shadow: none;
}

View File

@ -24,13 +24,15 @@ export default function Sort({
setSortType,
sortDirection,
setSortDirection,
setPriceType
setPriceType,
setServiceType
}: {
sortType: string
setSortType: React.Dispatch<React.SetStateAction<string>>
sortDirection: string
setSortDirection: React.Dispatch<React.SetStateAction<string>>
setPriceType: React.Dispatch<React.SetStateAction<string>>
setServiceType: React.Dispatch<React.SetStateAction<string>>
}): ReactElement {
const navigate = useNavigate()
const directionArrow = String.fromCharCode(
@ -44,8 +46,6 @@ export default function Sort({
if (sortBy === SortTermOptions.Liquidity) {
urlLocation = `${urlLocation}&priceType=${FilterByPriceOptions.Dynamic}`
setPriceType(FilterByPriceOptions.Dynamic)
} else {
setPriceType(undefined)
}
setSortType(sortBy)
} else if (direction) {

View File

@ -28,7 +28,8 @@ type SortValueOptions = typeof SortValueOptions[keyof typeof SortValueOptions]
export const FilterByPriceOptions = {
Fixed: 'exchange',
Dynamic: 'pool'
Dynamic: 'pool',
All: 'all'
} as const
type FilterByPriceOptions = typeof FilterByPriceOptions[keyof typeof FilterByPriceOptions]
@ -38,12 +39,20 @@ export const FilterByTypeOptions = {
} as const
type FilterByTypeOptions = typeof FilterByTypeOptions[keyof typeof FilterByTypeOptions]
function addPriceFilterToQuerry(sortTerm: string, priceFilter: string): string {
sortTerm = priceFilter
? sortTerm === ''
? `price.type:${priceFilter}`
: `${sortTerm} AND price.type:${priceFilter}`
: sortTerm
function addPriceFilterToQuery(sortTerm: string, priceFilter: string): string {
if (priceFilter === FilterByPriceOptions.All) {
sortTerm = priceFilter
? sortTerm === ''
? `(price.type:${FilterByPriceOptions.Fixed} OR price.type:${FilterByPriceOptions.Dynamic})`
: `${sortTerm} AND (price.type:${FilterByPriceOptions.Dynamic} OR price.type:${FilterByPriceOptions.Fixed})`
: sortTerm
} else {
sortTerm = priceFilter
? sortTerm === ''
? `price.type:${priceFilter}`
: `${sortTerm} AND price.type:${priceFilter}`
: sortTerm
}
return sortTerm
}
@ -89,9 +98,9 @@ export function getSearchQuery(
? // eslint-disable-next-line no-useless-escape
`(service.attributes.additionalInformation.categories:\"${categories}\")`
: text || ''
searchTerm = addPriceFilterToQuerry(searchTerm, priceType)
searchTerm = addTypeFilterToQuery(searchTerm, serviceType)
console.log('search', searchTerm, serviceType)
searchTerm = addPriceFilterToQuery(searchTerm, priceType)
return {
page: Number(page) || 1,
offset: Number(offset) || 21,

View File

@ -27,7 +27,7 @@ export default function PageGatsbySearch(props: PageProps): ReactElement {
(totalResults > 1 ? ' results' : ' result') +
' for ' +
searchValue
: totalResults + ' datasets'
: totalResults + ' results'
: 'Searching...'
}`