mirror of
https://github.com/oceanprotocol/commons.git
synced 2023-03-15 18:03:00 +01:00
search page component reorder
This commit is contained in:
parent
921e8fe764
commit
ca6029b034
@ -22,7 +22,7 @@
|
|||||||
composes: inputWrap;
|
composes: inputWrap;
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
padding-left: $spacer * 1.5;
|
padding-left: $spacer;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
|
51
client/src/routes/Search/FilterItem.test.tsx
Normal file
51
client/src/routes/Search/FilterItem.test.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { render, fireEvent } from '@testing-library/react'
|
||||||
|
import FilterItem from './FilterItem'
|
||||||
|
|
||||||
|
describe('FilterItem', () => {
|
||||||
|
const filterByCategory = jest.fn()
|
||||||
|
const filterByLicense = jest.fn()
|
||||||
|
|
||||||
|
it('renders without crashing', () => {
|
||||||
|
const { container } = render(
|
||||||
|
<FilterItem
|
||||||
|
isActive={false}
|
||||||
|
filter={{ label: 'Category' }}
|
||||||
|
filterByCategory={filterByCategory}
|
||||||
|
filterByLicense={filterByLicense}
|
||||||
|
option="Hello"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('filterByCategory can be called', () => {
|
||||||
|
const { getByText, getByTitle } = render(
|
||||||
|
<FilterItem
|
||||||
|
isActive
|
||||||
|
filter={{ label: 'Category' }}
|
||||||
|
filterByCategory={filterByCategory}
|
||||||
|
filterByLicense={filterByLicense}
|
||||||
|
option="Hello"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
fireEvent.click(getByText(/Hello/))
|
||||||
|
expect(filterByCategory).toHaveBeenCalled()
|
||||||
|
fireEvent.click(getByTitle('Clear'))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('filterByLicense can be called', () => {
|
||||||
|
const { getByText, getByTitle } = render(
|
||||||
|
<FilterItem
|
||||||
|
isActive
|
||||||
|
filter={{ label: 'License' }}
|
||||||
|
filterByCategory={filterByCategory}
|
||||||
|
filterByLicense={filterByLicense}
|
||||||
|
option="Hello"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
fireEvent.click(getByText(/Hello/))
|
||||||
|
expect(filterByLicense).toHaveBeenCalled()
|
||||||
|
fireEvent.click(getByTitle('Clear'))
|
||||||
|
})
|
||||||
|
})
|
@ -1,5 +1,4 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import shortid from 'shortid'
|
|
||||||
import Button from '../../components/atoms/Button'
|
import Button from '../../components/atoms/Button'
|
||||||
import styles from './FilterItem.module.scss'
|
import styles from './FilterItem.module.scss'
|
||||||
|
|
||||||
@ -17,10 +16,7 @@ export default function FilterItem({
|
|||||||
filterByLicense(license: string): void
|
filterByLicense(license: string): void
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<li
|
<li className={isActive ? styles.active : styles.item}>
|
||||||
key={shortid.generate()}
|
|
||||||
className={isActive ? styles.active : styles.item}
|
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
link
|
link
|
||||||
className={styles.option}
|
className={styles.option}
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
@import '../../styles/variables';
|
|
||||||
|
|
||||||
.filter {
|
|
||||||
ul {
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.filterTitle {
|
|
||||||
font-size: $font-size-base;
|
|
||||||
color: $brand-grey-light;
|
|
||||||
margin-top: 0;
|
|
||||||
border-bottom: 1px solid $brand-grey-lighter;
|
|
||||||
padding-bottom: $spacer / 4;
|
|
||||||
margin-bottom: $spacer / 4;
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import shortid from 'shortid'
|
|
||||||
import styles from './Filters.module.scss'
|
|
||||||
import data from '../../data/form-publish.json'
|
|
||||||
import FilterItem from './FilterItem'
|
|
||||||
import { DDO } from '@oceanprotocol/squid'
|
|
||||||
|
|
||||||
const { steps } = data
|
|
||||||
|
|
||||||
const labelCategories =
|
|
||||||
steps &&
|
|
||||||
steps[1].fields &&
|
|
||||||
steps[1].fields.categories &&
|
|
||||||
steps[1].fields.categories.label
|
|
||||||
|
|
||||||
const labelLicense =
|
|
||||||
steps &&
|
|
||||||
steps[2].fields &&
|
|
||||||
steps[2].fields.license &&
|
|
||||||
steps[2].fields.license.label
|
|
||||||
|
|
||||||
function getFilterMetadata(results: any[]) {
|
|
||||||
let filterCategories: string[] = []
|
|
||||||
let filterLicenses: string[] = []
|
|
||||||
|
|
||||||
results.map((asset: DDO) => {
|
|
||||||
if (!asset.findServiceByType) return null
|
|
||||||
const { metadata } = asset.findServiceByType('Metadata')
|
|
||||||
const { categories, license } = metadata.base
|
|
||||||
categories && filterCategories.push(categories[0])
|
|
||||||
license && filterLicenses.push(license)
|
|
||||||
return null
|
|
||||||
})
|
|
||||||
|
|
||||||
// remove duplicates
|
|
||||||
filterCategories = Array.from(new Set(filterCategories))
|
|
||||||
filterLicenses = Array.from(new Set(filterLicenses))
|
|
||||||
|
|
||||||
return { filterCategories, filterLicenses }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Filters({
|
|
||||||
category,
|
|
||||||
license,
|
|
||||||
results,
|
|
||||||
filterByCategory,
|
|
||||||
filterByLicense
|
|
||||||
}: {
|
|
||||||
category: string
|
|
||||||
license: string
|
|
||||||
results: any[]
|
|
||||||
filterByCategory(category: string): void
|
|
||||||
filterByLicense(license: string): void
|
|
||||||
}) {
|
|
||||||
const { filterCategories, filterLicenses } = getFilterMetadata(results)
|
|
||||||
|
|
||||||
const filters = [
|
|
||||||
{ label: labelCategories, items: filterCategories },
|
|
||||||
{ label: labelLicense, items: filterLicenses }
|
|
||||||
]
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{filters.map(filter => (
|
|
||||||
<div key={shortid.generate()} className={styles.filter}>
|
|
||||||
<h3 className={styles.filterTitle}>{filter.label}</h3>
|
|
||||||
<ul className={styles.filter}>
|
|
||||||
{filter.items &&
|
|
||||||
filter.items
|
|
||||||
.sort((a: string, b: string) =>
|
|
||||||
a.localeCompare(b)
|
|
||||||
) // sort alphabetically
|
|
||||||
.map((option: string) => {
|
|
||||||
const isActive =
|
|
||||||
category === option ||
|
|
||||||
license === option
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FilterItem
|
|
||||||
key={shortid.generate()}
|
|
||||||
isActive={isActive}
|
|
||||||
filter={filter}
|
|
||||||
filterByCategory={filterByCategory}
|
|
||||||
filterByLicense={filterByLicense}
|
|
||||||
option={option}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
@ -11,3 +11,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter {
|
||||||
|
ul {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.filterTitle {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $brand-grey-light;
|
||||||
|
margin-top: 0;
|
||||||
|
border-bottom: 1px solid $brand-grey-lighter;
|
||||||
|
padding-bottom: $spacer / 4;
|
||||||
|
margin-bottom: $spacer / 4;
|
||||||
|
}
|
||||||
|
@ -3,13 +3,13 @@ import { render } from '@testing-library/react'
|
|||||||
import { User } from '../../context'
|
import { User } from '../../context'
|
||||||
import { userMockConnected } from '../../../__mocks__/user-mock'
|
import { userMockConnected } from '../../../__mocks__/user-mock'
|
||||||
import searchMock from '../../../__fixtures__/search.json'
|
import searchMock from '../../../__fixtures__/search.json'
|
||||||
import Filters from './Filters'
|
import Sidebar from './Sidebar'
|
||||||
|
|
||||||
describe('Filters', () => {
|
describe('Sidebar', () => {
|
||||||
it('renders without crashing', () => {
|
it('renders without crashing', () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<User.Provider value={userMockConnected}>
|
<User.Provider value={userMockConnected}>
|
||||||
<Filters
|
<Sidebar
|
||||||
category="Architecture"
|
category="Architecture"
|
||||||
license="Public"
|
license="Public"
|
||||||
results={searchMock.results}
|
results={searchMock.results}
|
@ -1,48 +1,94 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Input from '../../components/atoms/Form/Input'
|
import shortid from 'shortid'
|
||||||
import Filters from './Filters'
|
import { DDO } from '@oceanprotocol/squid'
|
||||||
|
import data from '../../data/form-publish.json'
|
||||||
|
import FilterItem from './FilterItem'
|
||||||
import styles from './Sidebar.module.scss'
|
import styles from './Sidebar.module.scss'
|
||||||
|
|
||||||
|
const { steps } = data
|
||||||
|
|
||||||
|
const labelCategories =
|
||||||
|
steps &&
|
||||||
|
steps[1].fields &&
|
||||||
|
steps[1].fields.categories &&
|
||||||
|
steps[1].fields.categories.label
|
||||||
|
|
||||||
|
const labelLicense =
|
||||||
|
steps &&
|
||||||
|
steps[2].fields &&
|
||||||
|
steps[2].fields.license &&
|
||||||
|
steps[2].fields.license.label
|
||||||
|
|
||||||
|
function getFilterMetadata(results: any[]) {
|
||||||
|
let filterCategories: string[] = []
|
||||||
|
let filterLicenses: string[] = []
|
||||||
|
|
||||||
|
results.map((asset: DDO) => {
|
||||||
|
if (!asset.findServiceByType) return null
|
||||||
|
const { metadata } = asset.findServiceByType('Metadata')
|
||||||
|
const { categories, license } = metadata.base
|
||||||
|
categories && filterCategories.push(categories[0])
|
||||||
|
license && filterLicenses.push(license)
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
// remove duplicates
|
||||||
|
filterCategories = Array.from(new Set(filterCategories))
|
||||||
|
filterLicenses = Array.from(new Set(filterLicenses))
|
||||||
|
|
||||||
|
return { filterCategories, filterLicenses }
|
||||||
|
}
|
||||||
|
|
||||||
export default function Sidebar({
|
export default function Sidebar({
|
||||||
search,
|
|
||||||
inputChange,
|
|
||||||
category,
|
category,
|
||||||
license,
|
license,
|
||||||
results,
|
results,
|
||||||
filterByCategory,
|
filterByCategory,
|
||||||
filterByLicense
|
filterByLicense
|
||||||
}: {
|
}: {
|
||||||
search: string
|
|
||||||
inputChange: any
|
|
||||||
category: string
|
category: string
|
||||||
license: string
|
license: string
|
||||||
results: any[]
|
results: any[]
|
||||||
filterByCategory(category: string): void
|
filterByCategory(category: string): void
|
||||||
filterByLicense(license: string): void
|
filterByLicense(license: string): void
|
||||||
}) {
|
}) {
|
||||||
|
const { filterCategories, filterLicenses } = getFilterMetadata(results)
|
||||||
|
|
||||||
|
const filters = [
|
||||||
|
{ label: labelCategories, items: filterCategories },
|
||||||
|
{ label: labelLicense, items: filterLicenses }
|
||||||
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className={styles.sidebar}>
|
<aside className={styles.sidebar}>
|
||||||
<Input
|
{filters.map(filter => (
|
||||||
type="search"
|
<div key={shortid.generate()} className={styles.filter}>
|
||||||
name="search"
|
<h3 className={styles.filterTitle}>{filter.label}</h3>
|
||||||
label="Search"
|
<ul className={styles.filter}>
|
||||||
placeholder="e.g. shapes of plants"
|
{filter.items &&
|
||||||
value={search}
|
filter.items
|
||||||
onChange={inputChange}
|
.sort((a: string, b: string) =>
|
||||||
// group={
|
a.localeCompare(b)
|
||||||
// <Button primary onClick={search}>
|
) // sort alphabetically
|
||||||
// Search
|
.map((option: string) => {
|
||||||
// </Button>
|
const isActive =
|
||||||
// }
|
category === option ||
|
||||||
/>
|
license === option
|
||||||
|
|
||||||
<Filters
|
return (
|
||||||
category={category}
|
<FilterItem
|
||||||
license={license}
|
key={shortid.generate()}
|
||||||
results={results}
|
isActive={isActive}
|
||||||
filterByCategory={filterByCategory}
|
filter={filter}
|
||||||
filterByLicense={filterByLicense}
|
filterByCategory={filterByCategory}
|
||||||
/>
|
filterByLicense={filterByLicense}
|
||||||
|
option={option}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</aside>
|
</aside>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: $spacer * 2;
|
grid-gap: $spacer * 2;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
margin-top: $spacer * 2;
|
||||||
|
|
||||||
@media (min-width: $break-point--medium) {
|
@media (min-width: $break-point--medium) {
|
||||||
grid-template-columns: 1fr 3fr;
|
grid-template-columns: 3fr 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import Spinner from '../../components/atoms/Spinner'
|
|||||||
import Route from '../../components/templates/Route'
|
import Route from '../../components/templates/Route'
|
||||||
import { User } from '../../context'
|
import { User } from '../../context'
|
||||||
import Content from '../../components/atoms/Content'
|
import Content from '../../components/atoms/Content'
|
||||||
|
import Input from '../../components/atoms/Form/Input'
|
||||||
import withTracker from '../../hoc/withTracker'
|
import withTracker from '../../hoc/withTracker'
|
||||||
import Sidebar from './Sidebar'
|
import Sidebar from './Sidebar'
|
||||||
import Results from './Results'
|
import Results from './Results'
|
||||||
@ -206,19 +207,24 @@ class Search extends PureComponent<SearchProps, SearchState> {
|
|||||||
} = this.state
|
} = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Route title="Search" wide>
|
<Route title="Search">
|
||||||
|
<Content>
|
||||||
|
<Input
|
||||||
|
type="search"
|
||||||
|
name="search"
|
||||||
|
label=""
|
||||||
|
placeholder="e.g. shapes of plants"
|
||||||
|
value={search}
|
||||||
|
onChange={this.inputChange}
|
||||||
|
// group={
|
||||||
|
// <Button primary onClick={this.executeSearch}>
|
||||||
|
// Search
|
||||||
|
// </Button>
|
||||||
|
// }
|
||||||
|
/>
|
||||||
|
</Content>
|
||||||
<Content wide>
|
<Content wide>
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<Sidebar
|
|
||||||
search={search}
|
|
||||||
inputChange={this.inputChange}
|
|
||||||
category={category}
|
|
||||||
results={results}
|
|
||||||
license={license}
|
|
||||||
filterByCategory={this.filterByCategory}
|
|
||||||
filterByLicense={this.filterByLicense}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<Spinner message="Searching..." />
|
<Spinner message="Searching..." />
|
||||||
@ -235,6 +241,14 @@ class Search extends PureComponent<SearchProps, SearchState> {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Sidebar
|
||||||
|
category={category}
|
||||||
|
license={license}
|
||||||
|
results={results}
|
||||||
|
filterByCategory={this.filterByCategory}
|
||||||
|
filterByLicense={this.filterByLicense}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Content>
|
</Content>
|
||||||
</Route>
|
</Route>
|
||||||
|
Loading…
Reference in New Issue
Block a user