diff --git a/package-lock.json b/package-lock.json index c5b4f8ad0..f6662aad3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31934,6 +31934,21 @@ } } }, + "swr": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/swr/-/swr-0.2.3.tgz", + "integrity": "sha512-JhuuD5ojqgjAQpZAhoPBd8Di0Mr1+ykByVKuRJdtKaxkUX/y8kMACWKkLgLQc8pcDOKEAnbIreNjU7HfqI9nHQ==", + "requires": { + "fast-deep-equal": "2.0.1" + }, + "dependencies": { + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + } + } + }, "symbol-observable": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", diff --git a/package.json b/package.json index 5141ee3bc..380e5f1a0 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "react-toastify": "^6.0.8", "shortid": "^2.2.15", "slugify": "^1.4.4", + "swr": "^0.2.3", "web3connect": "^1.0.0-beta.33", "yup": "^0.29.1" }, diff --git a/src/components/atoms/Price/Conversion.module.css b/src/components/atoms/Price/Conversion.module.css new file mode 100644 index 000000000..1dedb014e --- /dev/null +++ b/src/components/atoms/Price/Conversion.module.css @@ -0,0 +1,6 @@ +.conversion { + display: inline-block; + font-size: var(--font-size-mini); + margin-left: calc(var(--spacer) / 6); + color: var(--color-secondary); +} diff --git a/src/components/atoms/Price/Conversion.tsx b/src/components/atoms/Price/Conversion.tsx new file mode 100644 index 000000000..66a0e9267 --- /dev/null +++ b/src/components/atoms/Price/Conversion.tsx @@ -0,0 +1,49 @@ +import React, { useEffect, useState, ReactElement } from 'react' +import useSWR from 'swr' +import { fetchData, isBrowser } from '../../../utils' +import styles from './Conversion.module.css' + +const currencies = 'EUR' // comma-separated list +const url = `https://api.coingecko.com/api/v3/simple/price?ids=ocean-protocol&vs_currencies=${currencies}&include_24hr_change=true` + +export default function Conversion({ + price, + update = true +}: { + price: string // expects price in OCEAN, not wei + update?: boolean +}): ReactElement { + const [priceEur, setPriceEur] = useState('0.00') + + const onSuccess = async (data: { 'ocean-protocol': { eur: number } }) => { + if (!data) return + if (!price || price === '' || price === '0') { + setPriceEur('0.00') + return + } + + const { eur } = data['ocean-protocol'] + const converted = eur * Number(price) + setPriceEur(`${converted.toFixed(2)}`) + } + + useEffect(() => { + async function getData() { + const data = await fetchData(url) + await onSuccess(data) + } + if (isBrowser && price !== '0') { + getData() + } + }, [price]) + + if (update) { + // Fetch new prices periodically with swr + useSWR(url, fetchData, { + refreshInterval: 30000, // 30 sec. + onSuccess + }) + } + + return ≈ EUR {priceEur} +} diff --git a/src/components/atoms/Price.module.css b/src/components/atoms/Price/index.module.css similarity index 78% rename from src/components/atoms/Price.module.css rename to src/components/atoms/Price/index.module.css index 955c01c54..357a91056 100644 --- a/src/components/atoms/Price.module.css +++ b/src/components/atoms/Price/index.module.css @@ -4,13 +4,14 @@ color: var(--brand-grey-dark); } -.price span { +.price span:first-child { font-weight: var(--font-weight-base); color: var(--color-secondary); font-size: var(--font-size-base); } .small { + /* lazy making-conversion-smaller-with-same-markup */ transform: scale(0.7); transform-origin: left 80%; } diff --git a/src/components/atoms/Price.stories.tsx b/src/components/atoms/Price/index.stories.tsx similarity index 58% rename from src/components/atoms/Price.stories.tsx rename to src/components/atoms/Price/index.stories.tsx index eccdbf7a7..cfe503e82 100644 --- a/src/components/atoms/Price.stories.tsx +++ b/src/components/atoms/Price/index.stories.tsx @@ -1,8 +1,10 @@ import React from 'react' -import Price from './Price' +import Price from '.' export default { title: 'Atoms/Price' } export const Normal = () => + +export const Small = () => diff --git a/src/components/atoms/Price.tsx b/src/components/atoms/Price/index.tsx similarity index 71% rename from src/components/atoms/Price.tsx rename to src/components/atoms/Price/index.tsx index 511aadf9f..2cbad0a91 100644 --- a/src/components/atoms/Price.tsx +++ b/src/components/atoms/Price/index.tsx @@ -1,7 +1,8 @@ import React, { ReactElement } from 'react' -import Web3 from 'web3' +import { fromWei } from 'web3-utils' import classNames from 'classnames/bind' -import styles from './Price.module.css' +import PriceConversion from './Conversion' +import styles from './index.module.css' const cx = classNames.bind(styles) @@ -26,7 +27,8 @@ export default function Price({ 'Free' ) : ( <> - OCEAN {Web3.utils.fromWei(price)} + OCEAN {fromWei(price)} + ) diff --git a/src/components/molecules/Menu.module.css b/src/components/molecules/Menu.module.css index 5a279c27a..37c279a23 100644 --- a/src/components/molecules/Menu.module.css +++ b/src/components/molecules/Menu.module.css @@ -20,6 +20,7 @@ width: 4rem; height: 4rem; margin-left: -0.5rem; + margin-right: 0.5rem; } .logoUnit path { @@ -39,17 +40,7 @@ margin: 0; display: block; color: var(--color-secondary); - font-size: var(--font-size-base); - } - - .logoUnit svg { - margin-top: -0.4rem; - } -} - -@media screen and (min-width: 60rem) { - .title { - font-size: var(--font-size-large); + font-size: var(--font-size-h4); } } @@ -77,7 +68,7 @@ text-transform: uppercase; color: var(--brand-grey); font-weight: var(--font-weight-bold); - font-size: var(--font-size-small); + font-size: var(--font-size-base); position: relative; z-index: 1; } diff --git a/src/components/organisms/JobsList.tsx b/src/components/organisms/JobsList.tsx index 52ca50915..89875e4d1 100644 --- a/src/components/organisms/JobsList.tsx +++ b/src/components/organisms/JobsList.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState, ReactElement } from 'react' +import React, { useState, ReactElement } from 'react' import Loader from '../atoms/Loader' import { useOcean, @@ -16,8 +16,6 @@ import DateCell from '../atoms/Table/DateCell' import DdoLinkCell from '../atoms/Table/DdoLinkCell' import shortid from 'shortid' import ActionsCell from '../atoms/Table/ActionsCell' -import Tooltip from '../atoms/Tooltip' -import Tippy from '@tippyjs/react' import JobDetailsDialog from '../molecules/JobDetailsDialog' const columns = [ diff --git a/src/utils/index.ts b/src/utils/index.ts index a542bece9..f497653b8 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -72,6 +72,20 @@ export async function getFileInfo(url: string): Promise { } } +export async function fetchData(url: string): Promise { + try { + const response = await axios(url) + + if (response.status !== 200) { + return console.error('Non-200 response: ' + response.status) + } + + return response.data + } catch (error) { + console.error('Error parsing json: ' + error.message) + } +} + export function isDid(did: string | undefined): boolean { const didMatch = (did as string).match(/^did:op:([a-f0-9]{64})$/i) return !!didMatch