mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
make the search work
This commit is contained in:
parent
829ec502a2
commit
4a35fd73d2
@ -65,6 +65,11 @@ module.exports = ({ config }) => {
|
||||
|
||||
config.resolve.extensions.push('.ts', '.tsx')
|
||||
|
||||
// 'fs' fix for squid.js
|
||||
config.node = {
|
||||
fs: 'empty'
|
||||
}
|
||||
|
||||
// Handle SVGs
|
||||
// Don't use Storybook's default SVG Configuration
|
||||
config.module.rules = config.module.rules.map((rule) => {
|
||||
|
53
package-lock.json
generated
53
package-lock.json
generated
@ -14100,6 +14100,18 @@
|
||||
"prepend-http": "^2.0.0",
|
||||
"query-string": "^5.0.1",
|
||||
"sort-keys": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"query-string": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
|
||||
"integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
|
||||
"requires": {
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"p-cancelable": {
|
||||
@ -23978,6 +23990,18 @@
|
||||
"prepend-http": "^2.0.0",
|
||||
"query-string": "^5.0.1",
|
||||
"sort-keys": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"query-string": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
|
||||
"integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
|
||||
"requires": {
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"p-cancelable": {
|
||||
@ -36070,13 +36094,20 @@
|
||||
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
|
||||
},
|
||||
"query-string": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
|
||||
"integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
|
||||
"version": "6.13.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-6.13.1.tgz",
|
||||
"integrity": "sha512-RfoButmcK+yCta1+FuU8REvisx1oEzhMKwhLUNcepQTPGcNMp1sIqjnfCtfnvGSQZQEhaBHvccujtWoUV3TTbA==",
|
||||
"requires": {
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
"split-on-first": "^1.0.0",
|
||||
"strict-uri-encode": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"strict-uri-encode": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
|
||||
}
|
||||
}
|
||||
},
|
||||
"querystring": {
|
||||
@ -44017,6 +44048,18 @@
|
||||
"timed-out": "^4.0.1",
|
||||
"url-set-query": "^1.0.0",
|
||||
"xhr": "^2.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"query-string": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
|
||||
"integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
|
||||
"requires": {
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"xhr-request-promise": {
|
||||
|
@ -49,6 +49,7 @@
|
||||
"intersection-observer": "^0.11.0",
|
||||
"is-url-superb": "^4.0.0",
|
||||
"numeral": "^2.0.6",
|
||||
"query-string": "^6.13.1",
|
||||
"react": "^16.13.1",
|
||||
"react-data-table-component": "^6.9.3",
|
||||
"react-datepicker": "^3.0.0",
|
||||
|
@ -2,7 +2,15 @@
|
||||
margin-bottom: var(--spacer);
|
||||
}
|
||||
|
||||
.inputGroup .input {
|
||||
.inputGroup > div {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.inputGroup label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.inputGroup input {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
@ -12,44 +20,23 @@
|
||||
border-top-right-radius: 0;
|
||||
margin-top: -1px;
|
||||
width: 100%;
|
||||
border-width: 1px;
|
||||
text-transform: uppercase;
|
||||
color: var(--brand-grey-lighter);
|
||||
background: var(--brand-gradient);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.inputGroup button:hover,
|
||||
.inputGroup button:focus,
|
||||
.inputGroup .input:focus + button:hover,
|
||||
.inputGroup .input:focus + button:focus {
|
||||
.inputGroup input:focus + button:hover,
|
||||
.inputGroup input:focus + button:focus {
|
||||
background: var(--brand-gradient);
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.inputGroup .input:focus + button {
|
||||
color: var(--brand-white);
|
||||
}
|
||||
|
||||
/* .inputGroup button:hover,
|
||||
.inputGroup button:focus,
|
||||
.inputGroup .input:focus + button {
|
||||
color: var(--brand-white);
|
||||
background-color: var(--brand-pink);
|
||||
}
|
||||
|
||||
.inputGroup .input:focus + button {
|
||||
border-color: var(--brand-pink);
|
||||
background-color: var(--brand-pink);
|
||||
} */
|
||||
|
||||
@media screen and (min-width: 30rem) {
|
||||
.inputGroup {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.inputGroup .input {
|
||||
.inputGroup input {
|
||||
border-bottom-left-radius: var(--border-radius);
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
@ -64,14 +51,3 @@
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.input {
|
||||
composes: input from './Form/FieldTemplate.module.css';
|
||||
}
|
||||
|
||||
.large {
|
||||
composes: large from './Form/FieldTemplate.module.css';
|
||||
}
|
||||
|
||||
.filters {
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { useNavigate } from '@reach/router'
|
||||
import styles from './SearchBar.module.css'
|
||||
import Loader from '../atoms/Loader'
|
||||
import Button from '../atoms/Button'
|
||||
import Input from '../atoms/Input'
|
||||
|
||||
export default function SearchBar({
|
||||
placeholder,
|
||||
@ -35,12 +36,12 @@ export default function SearchBar({
|
||||
return (
|
||||
<form className={styles.form}>
|
||||
<div className={styles.inputGroup}>
|
||||
<input
|
||||
<Input
|
||||
type="search"
|
||||
className={large ? `${styles.input} ${styles.large}` : styles.input}
|
||||
name="search"
|
||||
placeholder={placeholder || 'What are you looking for?'}
|
||||
value={value}
|
||||
onChange={(e) => handleChange(e)}
|
||||
onChange={handleChange}
|
||||
required
|
||||
/>
|
||||
<Button onClick={(e: FormEvent<HTMLButtonElement>) => startSearch(e)}>
|
||||
|
@ -1,7 +1,3 @@
|
||||
.input {
|
||||
composes: input from './Form/FieldTemplate.module.css';
|
||||
}
|
||||
|
||||
.layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -3,6 +3,7 @@ import SearchFilterSection from '../atoms/SearchFilterSection'
|
||||
import usePriceQueryParams from '../../hooks/usePriceQueryParams'
|
||||
|
||||
import styles from './SearchPriceFilter.module.css'
|
||||
import Input from '../atoms/Input'
|
||||
|
||||
export declare type PriceInputProps = {
|
||||
label: string
|
||||
@ -18,18 +19,14 @@ export const PriceInput = ({
|
||||
text
|
||||
}: PriceInputProps) => {
|
||||
return (
|
||||
<label htmlFor={label} className={styles.label}>
|
||||
<input
|
||||
id={label}
|
||||
name={label}
|
||||
type="number"
|
||||
min="0"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
className={styles.input}
|
||||
/>
|
||||
<span>{text}</span>
|
||||
</label>
|
||||
<Input
|
||||
name={label}
|
||||
label={text}
|
||||
type="number"
|
||||
min="0"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,43 +1,110 @@
|
||||
import React from 'react'
|
||||
import { QueryResult } from '@oceanprotocol/squid/dist/node/aquarius/Aquarius'
|
||||
import Layout from '../../components/Layout'
|
||||
import PageHeader from '../molecules/PageHeader'
|
||||
import React, { ReactElement, useState, useEffect } from 'react'
|
||||
import {
|
||||
QueryResult,
|
||||
SearchQuery
|
||||
} from '@oceanprotocol/squid/dist/node/aquarius/Aquarius'
|
||||
import SearchBar from '../molecules/SearchBar'
|
||||
import AssetList from '../organisms/AssetList'
|
||||
import { SearchPriceFilter } from '../molecules/SearchPriceFilter'
|
||||
|
||||
import styles from './Search.module.css'
|
||||
import { priceQueryParamToWei } from '../../utils'
|
||||
import { Aquarius, Logger } from '@oceanprotocol/squid'
|
||||
import { config } from '../../config/ocean'
|
||||
import { useLocation } from '@reach/router'
|
||||
import queryString from 'query-string'
|
||||
|
||||
export declare type SearchPageProps = {
|
||||
text: string | string[]
|
||||
|
||||
tag: string | string[]
|
||||
queryResult: QueryResult
|
||||
}
|
||||
|
||||
const SearchPage = ({ text, tag, queryResult }: SearchPageProps) => {
|
||||
return (
|
||||
<Layout noPageHeader>
|
||||
<section className={styles.grid}>
|
||||
<div className={styles.search}>
|
||||
<PageHeader title={`Search for ${text || tag}`} />
|
||||
{text && <SearchBar initialValue={text as string} />}
|
||||
</div>
|
||||
export function getSearchQuery(
|
||||
page?: string | string[],
|
||||
offset?: string | string[],
|
||||
text?: string | string[],
|
||||
tag?: string | string[],
|
||||
priceQuery?: [string | undefined, string | undefined]
|
||||
): SearchQuery {
|
||||
return {
|
||||
page: Number(page) || 1,
|
||||
offset: Number(offset) || 20,
|
||||
query: {
|
||||
text,
|
||||
tags: tag ? [tag] : undefined,
|
||||
price: priceQuery
|
||||
},
|
||||
sort: {
|
||||
created: -1
|
||||
}
|
||||
|
||||
<aside className={styles.side}>
|
||||
<SearchPriceFilter />
|
||||
</aside>
|
||||
|
||||
<div className={styles.results}>
|
||||
{queryResult.results.length > 0 ? (
|
||||
<AssetList queryResult={queryResult} />
|
||||
) : (
|
||||
<div className={styles.empty}>No results found.</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</Layout>
|
||||
)
|
||||
// Something in squid-js is weird when using 'categories: [type]'
|
||||
// which is the only way the query actually returns desired results.
|
||||
// But it doesn't follow 'SearchQuery' interface so we have to assign
|
||||
// it here.
|
||||
} as SearchQuery
|
||||
}
|
||||
|
||||
export default SearchPage
|
||||
export async function getResults(params: any): Promise<QueryResult> {
|
||||
const { text, tag, page, offset, minPrice, maxPrice } = params
|
||||
|
||||
const minPriceParsed = priceQueryParamToWei(
|
||||
minPrice as string,
|
||||
'Error parsing context.query.minPrice'
|
||||
)
|
||||
const maxPriceParsed = priceQueryParamToWei(
|
||||
maxPrice as string,
|
||||
'Error parsing context.query.maxPrice'
|
||||
)
|
||||
const priceQuery =
|
||||
minPriceParsed || maxPriceParsed
|
||||
? // sometimes TS gets a bit silly
|
||||
([minPriceParsed, maxPriceParsed] as [
|
||||
string | undefined,
|
||||
string | undefined
|
||||
])
|
||||
: undefined
|
||||
|
||||
const aquarius = new Aquarius(config.aquariusUri as string, Logger)
|
||||
const queryResult = await aquarius.queryMetadata(
|
||||
getSearchQuery(page, offset, text, tag, priceQuery)
|
||||
)
|
||||
|
||||
return queryResult
|
||||
}
|
||||
|
||||
export default function SearchPage(): ReactElement {
|
||||
const location = useLocation()
|
||||
const parsed = queryString.parse(location.search)
|
||||
const { text, tag } = parsed
|
||||
const [queryResult, setQueryResult] = useState<QueryResult>()
|
||||
|
||||
useEffect(() => {
|
||||
async function initSearch() {
|
||||
const results = await getResults(parsed)
|
||||
setQueryResult(results)
|
||||
}
|
||||
initSearch()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<section className={styles.grid}>
|
||||
<div className={styles.search}>
|
||||
{text && <SearchBar initialValue={text as string} />}
|
||||
</div>
|
||||
|
||||
<aside className={styles.side}>
|
||||
<SearchPriceFilter />
|
||||
</aside>
|
||||
|
||||
<div className={styles.results}>
|
||||
{queryResult && queryResult.results.length > 0 ? (
|
||||
<AssetList queryResult={queryResult} />
|
||||
) : (
|
||||
<div className={styles.empty}>No results found.</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
@ -1,14 +1,15 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useLocation } from '@reach/router'
|
||||
import queryString from 'query-string'
|
||||
|
||||
export default function usePriceQueryParams() {
|
||||
const location = useLocation()
|
||||
|
||||
const [min, setMin] = useState(
|
||||
(JSON.parse(location.search).minPrice as string) || '0'
|
||||
(queryString.parse(location.search).minPrice as string) || '0'
|
||||
)
|
||||
const [max, setMax] = useState(
|
||||
(JSON.parse(location.search).maxPrice as string) || '0'
|
||||
(queryString.parse(location.search).maxPrice as string) || '0'
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -1,77 +1,16 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import { Aquarius, Logger } from '@oceanprotocol/squid'
|
||||
import { SearchQuery } from '@oceanprotocol/squid/dist/node/aquarius/Aquarius'
|
||||
import PageSearch, { SearchPageProps } from '../components/templates/Search'
|
||||
import { config } from '../config/ocean'
|
||||
import { JSONparse, priceQueryParamToWei } from '../utils'
|
||||
import PageSearch from '../components/templates/Search'
|
||||
import { PageProps } from 'gatsby'
|
||||
import Layout from '../components/Layout'
|
||||
import queryString from 'query-string'
|
||||
|
||||
export default function PageGatsbySearch(props: PageProps): ReactElement {
|
||||
const content = (props.data as any).content.edges[0].node.childPagesJson
|
||||
const { title, description } = content
|
||||
const parsed = queryString.parse(props.location.search)
|
||||
const { text, tag } = parsed
|
||||
|
||||
return (
|
||||
<Layout title={title} description={description} location={props.location}>
|
||||
<PageSearch text={text} tag={tag} queryResult={queryResult} />
|
||||
<Layout title={`Search for ${text || tag}`} location={props.location}>
|
||||
<PageSearch />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
// export function getSearchQuery(
|
||||
// page?: string | string[],
|
||||
// offset?: string | string[],
|
||||
// text?: string | string[],
|
||||
// tag?: string | string[],
|
||||
// priceQuery?: [string | undefined, string | undefined]
|
||||
// ) {
|
||||
// return {
|
||||
// page: Number(page) || 1,
|
||||
// offset: Number(offset) || 20,
|
||||
// query: {
|
||||
// text,
|
||||
// tags: tag ? [tag] : undefined,
|
||||
// price: priceQuery
|
||||
// },
|
||||
// sort: {
|
||||
// created: -1
|
||||
// }
|
||||
|
||||
// // Something in squid-js is weird when using 'categories: [type]'
|
||||
// // which is the only way the query actually returns desired results.
|
||||
// // But it doesn't follow 'SearchQuery' interface so we have to assign
|
||||
// // it here.
|
||||
// } as SearchQuery
|
||||
// }
|
||||
|
||||
// Search.getInitialProps = async (context) => {
|
||||
// const { text, tag, page, offset, minPrice, maxPrice } = context.query
|
||||
|
||||
// const minPriceParsed = priceQueryParamToWei(
|
||||
// minPrice as string,
|
||||
// 'Error parsing context.query.minPrice'
|
||||
// )
|
||||
// const maxPriceParsed = priceQueryParamToWei(
|
||||
// maxPrice as string,
|
||||
// 'Error parsing context.query.maxPrice'
|
||||
// )
|
||||
// const priceQuery =
|
||||
// minPriceParsed || maxPriceParsed
|
||||
// ? // sometimes TS gets a bit silly
|
||||
// ([minPriceParsed, maxPriceParsed] as [
|
||||
// string | undefined,
|
||||
// string | undefined
|
||||
// ])
|
||||
// : undefined
|
||||
|
||||
// const aquarius = new Aquarius(config.aquariusUri as string, Logger)
|
||||
// const queryResult = await aquarius.queryMetadata(
|
||||
// getSearchQuery(page, offset, text, tag, priceQuery)
|
||||
// )
|
||||
|
||||
// return {
|
||||
// text: text,
|
||||
// tag: tag,
|
||||
// queryResult
|
||||
// }
|
||||
// }
|
||||
|
Loading…
Reference in New Issue
Block a user