diff --git a/src/components/atoms/Alert.tsx b/src/components/atoms/Alert.tsx index 471a60381..85ded0081 100644 --- a/src/components/atoms/Alert.tsx +++ b/src/components/atoms/Alert.tsx @@ -23,6 +23,7 @@ export default function Alert({ action?: { name: string style?: 'text' | 'primary' | 'ghost' + disabled?: boolean handleAction: (e: FormEvent) => void } onDismiss?: () => void @@ -48,6 +49,7 @@ export default function Alert({ size="small" style={action.style || 'primary'} onClick={action.handleAction} + disabled={action.disabled} > {action.name} diff --git a/src/components/molecules/AssetTeaser.module.css b/src/components/molecules/AssetTeaser.module.css index 10ce0ccfc..d5e013c29 100644 --- a/src/components/molecules/AssetTeaser.module.css +++ b/src/components/molecules/AssetTeaser.module.css @@ -21,9 +21,7 @@ .content { margin-top: calc(var(--spacer) / 2); overflow-wrap: break-word; - word-wrap: break-word; - word-break: break-all; - + hyphens: auto; /* for sticking footer to bottom */ flex: 1; } @@ -36,6 +34,7 @@ font-size: var(--font-size-large); margin: 0; padding-bottom: calc(var(--spacer) / 6); + overflow-wrap: break-word; } .publisher { diff --git a/src/components/organisms/AssetActions/Consume.tsx b/src/components/organisms/AssetActions/Consume.tsx index d83498cc8..473572112 100644 --- a/src/components/organisms/AssetActions/Consume.tsx +++ b/src/components/organisms/AssetActions/Consume.tsx @@ -5,7 +5,8 @@ import File from '../../atoms/File' import Price from '../../atoms/Price' import { useSiteMetadata } from '../../../hooks/useSiteMetadata' import { useAsset } from '../../../providers/Asset' -import { gql, useQuery } from 'urql' +import { gql } from 'urql' +import { fetchData, getQueryContext } from '../../../utils/subgraph' import { OrdersData } from '../../../@types/apollo/OrdersData' import BigNumber from 'bignumber.js' import { useOcean } from '../../../providers/Ocean' @@ -63,15 +64,19 @@ export default function Consume({ const [maxDt, setMaxDT] = useState(1) const [isConsumablePrice, setIsConsumablePrice] = useState(true) const [assetTimeout, setAssetTimeout] = useState('') - const [result] = useQuery({ - query: previousOrderQuery, - variables: { + const [data, setData] = useState() + + useEffect(() => { + if (!ddo || !accountId) return + const context = getQueryContext(ddo.chainId) + const variables = { id: ddo.dataToken?.toLowerCase(), account: accountId?.toLowerCase() } - // pollInterval: 5000 - }) - const { data } = result + fetchData(previousOrderQuery, variables, context).then((result: any) => { + setData(result.data) + }) + }, [ddo, accountId, hasPreviousOrder]) async function checkMaxAvaialableTokens(price: BestPrice) { if (!ocean || !price) return @@ -83,7 +88,8 @@ export default function Consume({ } useEffect(() => { - if (!data || !assetTimeout || data.tokenOrders.length === 0) return + if (!data || !assetTimeout || data.tokenOrders.length === 0 || !accountId) + return const lastOrder = data.tokenOrders[0] if (assetTimeout === '0') { @@ -99,7 +105,7 @@ export default function Consume({ setHasPreviousOrder(false) } } - }, [data, assetTimeout]) + }, [data, assetTimeout, accountId]) useEffect(() => { const { timeout } = ddo.findServiceByType('access').attributes.main @@ -120,6 +126,7 @@ export default function Consume({ }, [dtBalance]) useEffect(() => { + if (!accountId) return setIsDisabled( !isConsumable || ((!ocean || @@ -141,6 +148,7 @@ export default function Consume({ pricingIsLoading, isConsumablePrice, hasDatatoken, + accountId, isConsumable ]) diff --git a/src/components/organisms/AssetContent/Pricing/index.tsx b/src/components/organisms/AssetContent/Pricing/index.tsx index ee828d336..88363821d 100644 --- a/src/components/organisms/AssetContent/Pricing/index.tsx +++ b/src/components/organisms/AssetContent/Pricing/index.tsx @@ -10,6 +10,7 @@ import Feedback from './Feedback' import { graphql, useStaticQuery } from 'gatsby' import { usePricing } from '../../../../hooks/usePricing' import styles from './index.module.css' +import { useAsset } from '../../../../providers/Asset' const query = graphql` query PricingQuery { @@ -67,6 +68,7 @@ export default function Pricing({ ddo }: { ddo: DDO }): ReactElement { const { createPricing, pricingIsLoading, pricingError, pricingStepText } = usePricing() + const { isAssetNetwork } = useAsset() const hasFeedback = pricingIsLoading || typeof success !== 'undefined' @@ -133,6 +135,7 @@ export default function Pricing({ ddo }: { ddo: DDO }): ReactElement { text={content.empty.info} action={{ name: content.empty.action.name, + disabled: !isAssetNetwork, handleAction: handleShowPricingForm }} /> diff --git a/src/components/templates/Search/Filters.module.css b/src/components/templates/Search/Filters.module.css index 0b65a3751..18b4ee0fd 100644 --- a/src/components/templates/Search/Filters.module.css +++ b/src/components/templates/Search/Filters.module.css @@ -2,6 +2,13 @@ div.filterList { white-space: normal; margin-bottom: 0; + display: flex; + flex-direction: row; + align-items: baseline; +} + +.separator { + width: calc(var(--spacer) / 2); } .filter { diff --git a/src/components/templates/Search/Filters.tsx b/src/components/templates/Search/Filters.tsx index cd6e15a09..ecea7cd80 100644 --- a/src/components/templates/Search/Filters.tsx +++ b/src/components/templates/Search/Filters.tsx @@ -1,7 +1,11 @@ import React, { ReactElement, useState } from 'react' import { useNavigate } from '@reach/router' import classNames from 'classnames/bind' -import { addExistingParamsToUrl, FilterByTypeOptions } from './utils' +import { + addExistingParamsToUrl, + FilterByAccessOptions, + FilterByTypeOptions +} from './utils' import Button from '../../atoms/Button' import styles from './Filters.module.css' @@ -14,111 +18,197 @@ const serviceFilterItems = [ { display: 'algorithms', value: FilterByTypeOptions.Algorithm } ] +const accessFilterItems = [ + { display: 'download ', value: FilterByAccessOptions.Download }, + { display: 'compute ', value: FilterByAccessOptions.Compute } +] + export default function Filters({ serviceType, + accessType, setServiceType, + setAccessType, isSearch, className }: { serviceType: string + accessType: string setServiceType: React.Dispatch> isSearch: boolean + setAccessType: React.Dispatch> className?: string }): ReactElement { const navigate = useNavigate() const [serviceSelections, setServiceSelections] = useState([]) + const [accessSelections, setAccessSelections] = useState([]) - async function applyServiceFilter(filterBy: string) { - setServiceType(filterBy) - if (isSearch) { - let urlLocation = await addExistingParamsToUrl(location, ['serviceType']) - if (filterBy && location.search.indexOf('&serviceType') === -1) { - urlLocation = `${urlLocation}&serviceType=${filterBy}` - } - navigate(urlLocation) + async function applyFilter(filter: string, filterType: string) { + let urlLocation = '' + if (filterType.localeCompare('accessType') === 0) { + urlLocation = await addExistingParamsToUrl(location, ['accessType']) + } else { + urlLocation = await addExistingParamsToUrl(location, ['serviceType']) } - } - async function handleSelectedFilter(isSelected: boolean, value: string) { - if (isSelected) { - if (serviceSelections.length > 1) { - const otherValue = serviceFilterItems.find( - (p) => p.value !== value - ).value - await applyServiceFilter(otherValue) - setServiceSelections([otherValue]) + async function applyServiceFilter(filterBy: string) { + setServiceType(filterBy) + if (filter && location.search.indexOf(filterType) === -1) { + filterType === 'accessType' + ? (urlLocation = `${urlLocation}&accessType=${filter}`) + : (urlLocation = `${urlLocation}&serviceType=${filter}`) + } + + if (isSearch) { + let urlLocation = await addExistingParamsToUrl(location, [ + 'serviceType' + ]) + if (filterBy && location.search.indexOf('&serviceType') === -1) { + urlLocation = `${urlLocation}&serviceType=${filterBy}` + } + filterType === 'accessType' + ? setAccessType(filter) + : setServiceType(filter) + navigate(urlLocation) + } + } + + async function handleSelectedFilter(isSelected: boolean, value: string) { + if ( + value === FilterByAccessOptions.Download || + value === FilterByAccessOptions.Compute + ) { + if (isSelected) { + if (accessSelections.length > 1) { + // both selected -> select the other one + const otherValue = accessFilterItems.find( + (p) => p.value !== value + ).value + await applyFilter(otherValue, 'accessType') + setAccessSelections([otherValue]) + } else { + // only the current one selected -> deselect it + await applyFilter(undefined, 'accessType') + setAccessSelections([]) + } + } else { + if (accessSelections.length) { + // one already selected -> both selected + await applyFilter(undefined, 'accessType') + setAccessSelections(accessFilterItems.map((p) => p.value)) + } else { + // none selected -> select + await applyFilter(value, 'accessType') + setAccessSelections([value]) + } + } } else { - await applyServiceFilter(undefined) - if (serviceSelections.includes(value)) { - serviceSelections.pop() + if (isSelected) { + if (serviceSelections.length > 1) { + const otherValue = serviceFilterItems.find( + (p) => p.value !== value + ).value + await applyFilter(otherValue, 'serviceType') + setServiceSelections([otherValue]) + } else { + await applyFilter(undefined, 'serviceType') + setServiceSelections([]) + } + } else { + if (serviceSelections.length) { + await applyFilter(undefined, 'serviceType') + setServiceSelections(serviceFilterItems.map((p) => p.value)) + } else { + await applyFilter(value, 'serviceType') + setServiceSelections([value]) + } } } - } else { - if (serviceSelections.length) { - await applyServiceFilter(undefined) - setServiceSelections(serviceFilterItems.map((p) => p.value)) - } else { - await applyServiceFilter(value) - setServiceSelections([value]) + } + + async function applyClearFilter(isSearch: boolean) { + setServiceSelections([]) + setAccessSelections([]) + + setServiceType(undefined) + setAccessType(undefined) + if (isSearch) { + let urlLocation = await addExistingParamsToUrl(location, [ + 'serviceType' + ]) + urlLocation = `${urlLocation}` + navigate(urlLocation) } } + + const styleClasses = cx({ + filterList: true, + [className]: className + }) + + return ( +
+ {serviceFilterItems.map((e, index) => { + const isServiceSelected = + e.value === serviceType || serviceSelections.includes(e.value) + + const selectFilter = cx({ + [styles.selected]: isServiceSelected, + [styles.filter]: true + }) + return ( + + ) + })} +
+ {accessFilterItems.map((e, index) => { + const isAccessSelected = + e.value === accessType || accessSelections.includes(e.value) + const selectFilter = cx({ + [styles.selected]: isAccessSelected, + [styles.filter]: true + }) + return ( + + ) + })} + {clearFilters.map((e, index) => { + const showClear = + accessSelections.length > 0 || serviceSelections.length > 0 + return ( + + ) + })} +
+ ) } - - async function applyClearFilter(isSearch: boolean) { - setServiceSelections([]) - setServiceType(undefined) - if (isSearch) { - let urlLocation = await addExistingParamsToUrl(location, ['serviceType']) - urlLocation = `${urlLocation}` - navigate(urlLocation) - } - } - - const styleClasses = cx({ - filterList: true, - [className]: className - }) - - return ( -
- {serviceFilterItems.map((e, index) => { - const isServiceSelected = - e.value === serviceType || serviceSelections.includes(e.value) - - const selectFilter = cx({ - [styles.selected]: isServiceSelected, - [styles.filter]: true - }) - return ( - - ) - })} - {clearFilters.map((e, index) => { - const showClear = serviceSelections.length > 0 - return ( - - ) - })} -
- ) } diff --git a/src/components/templates/Search/index.tsx b/src/components/templates/Search/index.tsx index bcf509d39..bf7b35bc0 100644 --- a/src/components/templates/Search/index.tsx +++ b/src/components/templates/Search/index.tsx @@ -21,11 +21,13 @@ export default function SearchPage({ }): ReactElement { const { appConfig } = useSiteMetadata() const parsed = queryString.parse(location.search) - const { text, owner, tags, page, sort, sortOrder, serviceType } = parsed + const { text, owner, tags, page, sort, sortOrder, serviceType, accessType } = + parsed const { chainIds } = useUserPreferences() const [queryResult, setQueryResult] = useState() const [loading, setLoading] = useState() const [service, setServiceType] = useState(serviceType as string) + const [access, setAccessType] = useState(accessType as string) const [sortType, setSortType] = useState(sort as string) const [sortDirection, setSortDirection] = useState( sortOrder as string @@ -53,6 +55,7 @@ export default function SearchPage({ sort, page, serviceType, + accessType, sortOrder, appConfig.metadataCacheUri, chainIds @@ -74,7 +77,9 @@ export default function SearchPage({