From 365618f5d96e592db8577872c290764d340119a9 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Thu, 22 Sep 2022 14:22:31 +0100 Subject: [PATCH 1/5] CI tweaks --- .github/workflows/ci.yml | 36 +++++++++++++-------------- .github/workflows/codeql-analysis.yml | 8 +++--- .github/workflows/deploy.yml | 6 ++--- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72f33fd0f..43cc16fbb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,13 +23,13 @@ jobs: node: ['16'] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - name: Cache node_modules - uses: actions/cache@v2 + uses: actions/cache@v3 env: cache-name: cache-node-modules with: @@ -37,7 +37,7 @@ jobs: key: ${{ runner.os }}-${{ matrix.node }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} restore-keys: ${{ runner.os }}-${{ matrix.node }}-build-${{ env.cache-name }}- - - run: npm ci --legacy-peer-deps + - run: npm ci - run: npm run build test: @@ -50,13 +50,13 @@ jobs: node: ['16'] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - name: Cache node_modules - uses: actions/cache@v2 + uses: actions/cache@v3 env: cache-name: cache-node-modules with: @@ -64,11 +64,11 @@ jobs: key: ${{ runner.os }}-${{ matrix.node }}-test-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} restore-keys: ${{ runner.os }}-${{ matrix.node }}-test-${{ env.cache-name }}- - - run: npm ci --legacy-peer-deps + - run: npm ci - run: npm test - name: Upload coverage artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: coverage-${{ runner.os }} path: coverage/ @@ -79,12 +79,12 @@ jobs: if: ${{ success() && github.actor != 'dependabot[bot]' }} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '16' - name: Cache node_modules - uses: actions/cache@v2 + uses: actions/cache@v3 env: cache-name: cache-node-modules with: @@ -92,11 +92,11 @@ jobs: key: ${{ runner.os }}-coverage-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} restore-keys: ${{ runner.os }}-coverage-${{ env.cache-name }}- - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: coverage-${{ runner.os }} - - run: npm ci --legacy-peer-deps + - run: npm ci - run: npm run codegen:apollo - uses: paambaati/codeclimate-action@v3.0.0 @@ -113,13 +113,13 @@ jobs: node: ['16'] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - name: Cache node_modules - uses: actions/cache@v2 + uses: actions/cache@v3 env: cache-name: cache-node-modules with: @@ -127,6 +127,6 @@ jobs: key: ${{ runner.os }}-${{ matrix.node }}-storybook-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} restore-keys: ${{ runner.os }}-${{ matrix.node }}-storybook-${{ env.cache-name }}- - - run: npm ci --legacy-peer-deps + - run: npm ci - run: npm run pregenerate - run: npm run storybook:build diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index fe99c0596..d41572ce9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -35,11 +35,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -50,7 +50,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -64,4 +64,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7f73fb655..7735d6682 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,9 +10,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - - run: npm ci --legacy-peer-deps + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + - run: npm ci - run: npm run build:static env: From 5b2bb3045e8bce8ea7fe967c75eb71c96ac42af0 Mon Sep 17 00:00:00 2001 From: EnzoVezzaro Date: Thu, 22 Sep 2022 12:17:12 -0400 Subject: [PATCH 2/5] added N/A for negative values as well as missing data (#1691) * added N/A for negative values as well as missing data * added N/A in teaser for negative orders count * added N/A to profile and asset teaser * change typing on Conversion and PriceUnit * remove log * removed unnecessary check on price value --- .../@shared/AssetList/AssetComputeList.tsx | 2 +- src/components/@shared/AssetType/index.tsx | 8 ++++--- .../FormFields/AssetSelection/index.tsx | 2 +- src/components/@shared/Price/Conversion.tsx | 14 ++++------- src/components/@shared/Price/PriceUnit.tsx | 9 ++++---- src/components/@shared/Price/index.tsx | 3 ++- .../Asset/AssetActions/AssetStats/index.tsx | 4 +++- .../AssetActions/Compute/PriceOutput.tsx | 4 ++-- src/components/Header/Wallet/Details.tsx | 2 +- src/components/Profile/Header/Stats.tsx | 23 ++++++++++++------- 10 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/components/@shared/AssetList/AssetComputeList.tsx b/src/components/@shared/AssetList/AssetComputeList.tsx index 964ac85db..74ee4d339 100644 --- a/src/components/@shared/AssetList/AssetComputeList.tsx +++ b/src/components/@shared/AssetList/AssetComputeList.tsx @@ -37,7 +37,7 @@ export default function AssetComputeSelection({ diff --git a/src/components/@shared/AssetType/index.tsx b/src/components/@shared/AssetType/index.tsx index 565a87270..7d3384c02 100644 --- a/src/components/@shared/AssetType/index.tsx +++ b/src/components/@shared/AssetType/index.tsx @@ -29,11 +29,13 @@ export default function AssetType({ {type === 'dataset' ? 'dataset' : 'algorithm'} - {totalSales ? ( + {(totalSales || totalSales === 0) && (
- {`${totalSales} ${totalSales === 1 ? 'sale' : 'sales'}`} + {totalSales < 0 + ? 'N/A' + : `${totalSales} ${totalSales === 1 ? 'sale' : 'sales'}`}
- ) : null} + )} ) } diff --git a/src/components/@shared/FormFields/AssetSelection/index.tsx b/src/components/@shared/FormFields/AssetSelection/index.tsx index 11d391ab1..cd73b6b18 100644 --- a/src/components/@shared/FormFields/AssetSelection/index.tsx +++ b/src/components/@shared/FormFields/AssetSelection/index.tsx @@ -108,7 +108,7 @@ export default function AssetSelection({ { - if ( - !prices || - !price || - price === '0' || - !priceTokenId || - !prices[priceTokenId] - ) { + if (!prices || !price || !priceTokenId || !prices[priceTokenId]) { return } const conversionValue = prices[priceTokenId][currency.toLowerCase()] - const converted = conversionValue * Number(price) + const converted = conversionValue * price const convertedFormatted = formatCurrency( converted, // No passing of `currency` for non-fiat so symbol conversion @@ -58,7 +52,7 @@ export default function Conversion({ setPriceConverted(convertedFormattedHTMLstring) }, [price, prices, currency, locale, isFiat, priceTokenId]) - return Number(price) > 0 ? ( + return price > 0 ? (
- {Number.isNaN(Number(price)) ? '-' : formatPrice(price, locale)}{' '} + {Number.isNaN(price) ? '-' : formatPrice(price, locale)}{' '} {symbol}
{conversion && } diff --git a/src/components/@shared/Price/index.tsx b/src/components/@shared/Price/index.tsx index cff963a62..f555f484e 100644 --- a/src/components/@shared/Price/index.tsx +++ b/src/components/@shared/Price/index.tsx @@ -16,10 +16,11 @@ export default function Price({ }): ReactElement { const isSupported = accessDetails?.type === 'fixed' || accessDetails?.type === 'free' + const price = `${orderPriceAndFees?.price || accessDetails?.price}` return isSupported ? ( - {!asset || !asset?.stats || asset?.stats?.orders === 0 ? ( + {!asset || !asset?.stats || asset?.stats?.orders < 0 ? ( + 'N/A' + ) : asset?.stats?.orders === 0 ? ( 'No sales yet' ) : ( <> diff --git a/src/components/Asset/AssetActions/Compute/PriceOutput.tsx b/src/components/Asset/AssetActions/Compute/PriceOutput.tsx index f142d0385..f8d1de628 100644 --- a/src/components/Asset/AssetActions/Compute/PriceOutput.tsx +++ b/src/components/Asset/AssetActions/Compute/PriceOutput.tsx @@ -45,7 +45,7 @@ function Row({
{type}
You will pay{' '} - + diff --git a/src/components/Header/Wallet/Details.tsx b/src/components/Header/Wallet/Details.tsx index e6e55a36e..5f0355a36 100644 --- a/src/components/Header/Wallet/Details.tsx +++ b/src/components/Header/Wallet/Details.tsx @@ -56,7 +56,7 @@ export default function Details(): ReactElement { diff --git a/src/components/Profile/Header/Stats.tsx b/src/components/Profile/Header/Stats.tsx index ac8ba10e6..e5a8e3ea3 100644 --- a/src/components/Profile/Header/Stats.tsx +++ b/src/components/Profile/Header/Stats.tsx @@ -15,7 +15,7 @@ export default function Stats({ const { chainIds } = useUserPreferences() const { assets, assetsTotal, sales } = useProfile() - const [totalSales, setTotalSales] = useState('0') + const [totalSales, setTotalSales] = useState(0) useEffect(() => { if (!assets || !accountId || !chainIds) return @@ -30,7 +30,7 @@ export default function Stats({ parseInt(priceInfo.accessDetails.price) * priceInfo.stats.orders } } - setTotalSales(JSON.stringify(count)) + setTotalSales(count) } catch (error) { LoggerInstance.error(error.message) } @@ -43,14 +43,21 @@ export default function Stats({ + totalSales > 0 ? ( + + ) : ( + '0' + ) } /> - +
) From 92b7063b3d5f1ed94505a77575e5ead9f129e4e7 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Thu, 22 Sep 2022 19:18:32 +0100 Subject: [PATCH 3/5] ENS integration, the right way (#1410) * prototype getting ENS names the right decentralized way * get all profile metadata with ENS * refactor account display in context of top sales list * support almost all default text records * refactor text record fetching * more web3 calls reduction * package cleanup * add Publisher component test, mock out ens utils * remove mock to run @utils/ens directly * add Avatar stories * cleanup * rebase fixes * profile loading tweaks * fixes * merge cleanup * remove @ensdomains/ensjs * fetch ENS data from proxy * update avatar tests * tweak error catching for all axios fetches * test tweaks * api path fix * fetching fixes * account switching tweaks * remove unused methods * add ENS fetching tests * jest timeout tweak * update readme --- .eslintrc | 3 +- README.md | 30 ++---- package-lock.json | 11 --- package.json | 1 - .../{Profile.tsx => Profile/index.tsx} | 76 ++++++--------- src/@context/Web3.tsx | 50 ++++++---- src/@hooks/{contracts => }/useNftFactory.ts | 0 src/@types/Profile.d.ts | 32 +------ src/@types/viewModels/AccountTeaserVM.d.ts | 4 - src/@utils/aquarius.ts | 39 ++++++++ src/@utils/ens.test.ts | 64 +++++++++++++ src/@utils/ens.ts | 62 ++++-------- src/@utils/fetch.ts | 23 +++-- src/@utils/numbers.ts | 9 -- src/@utils/pricingFeedback.ts | 15 --- src/@utils/profile.ts | 94 ------------------- src/@utils/purgatory.ts | 1 - src/@utils/subgraph.ts | 67 ------------- .../@shared/AccountList/AccountList.tsx | 57 ----------- .../@shared/AccountTeaser/AccountTeaser.tsx | 58 ------------ .../@shared/Publisher/Add.module.css | 7 -- src/components/@shared/Publisher/Add.tsx | 16 ---- .../@shared/Publisher/index.module.css | 7 -- .../@shared/Publisher/index.test.tsx | 56 +++++++++++ src/components/@shared/Publisher/index.tsx | 45 ++------- .../{Blockies => Avatar}/index.module.css | 2 +- .../@shared/atoms/Avatar/index.stories.tsx | 31 ++++++ .../@shared/atoms/Avatar/index.test.tsx | 19 ++++ src/components/@shared/atoms/Avatar/index.tsx | 24 +++++ .../@shared/atoms/Blockies/index.stories.tsx | 22 ----- .../@shared/atoms/Blockies/index.test.tsx | 8 -- .../@shared/atoms/Blockies/index.tsx | 28 ------ src/components/Header/Wallet/Account.tsx | 7 +- .../TopSales/Account/index.module.css} | 4 +- .../Home/TopSales/Account/index.tsx | 53 +++++++++++ .../TopSales/AccountList/index.module.css | 11 +++ .../Home/TopSales/AccountList/index.tsx | 43 +++++++++ src/components/Home/TopSales/index.module.css | 3 + .../index.tsx} | 10 +- src/components/Home/index.tsx | 6 +- src/components/Profile/Header/Account.tsx | 22 ++--- .../Profile/Header/PublisherLinks.module.css | 5 +- .../Profile/Header/PublisherLinks.tsx | 60 ++++++++---- src/components/Profile/Header/index.tsx | 17 +--- src/components/Publish/index.tsx | 2 +- src/pages/profile/index.tsx | 7 +- 46 files changed, 543 insertions(+), 668 deletions(-) rename src/@context/{Profile.tsx => Profile/index.tsx} (78%) rename src/@hooks/{contracts => }/useNftFactory.ts (100%) delete mode 100644 src/@types/viewModels/AccountTeaserVM.d.ts create mode 100644 src/@utils/ens.test.ts delete mode 100644 src/@utils/pricingFeedback.ts delete mode 100644 src/@utils/profile.ts delete mode 100644 src/components/@shared/AccountList/AccountList.tsx delete mode 100644 src/components/@shared/AccountTeaser/AccountTeaser.tsx delete mode 100644 src/components/@shared/Publisher/Add.module.css delete mode 100644 src/components/@shared/Publisher/Add.tsx create mode 100644 src/components/@shared/Publisher/index.test.tsx rename src/components/@shared/atoms/{Blockies => Avatar}/index.module.css (93%) create mode 100644 src/components/@shared/atoms/Avatar/index.stories.tsx create mode 100644 src/components/@shared/atoms/Avatar/index.test.tsx create mode 100644 src/components/@shared/atoms/Avatar/index.tsx delete mode 100644 src/components/@shared/atoms/Blockies/index.stories.tsx delete mode 100644 src/components/@shared/atoms/Blockies/index.test.tsx delete mode 100644 src/components/@shared/atoms/Blockies/index.tsx rename src/components/{@shared/AccountTeaser/AccountTeaser.module.css => Home/TopSales/Account/index.module.css} (92%) create mode 100644 src/components/Home/TopSales/Account/index.tsx create mode 100644 src/components/Home/TopSales/AccountList/index.module.css create mode 100644 src/components/Home/TopSales/AccountList/index.tsx create mode 100644 src/components/Home/TopSales/index.module.css rename src/components/Home/{PublishersWithMostSales.tsx => TopSales/index.tsx} (79%) diff --git a/.eslintrc b/.eslintrc index 585180b3e..8cf04d8ad 100644 --- a/.eslintrc +++ b/.eslintrc @@ -53,7 +53,8 @@ "object": true, "array": false } - ] + ], + "testing-library/no-node-access": "off" } } ] diff --git a/README.md b/README.md index c32d82481..355babc4b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ - [🦀 Data Sources](#-data-sources) - [Aquarius](#aquarius) - [Ocean Protocol Subgraph](#ocean-protocol-subgraph) - - [3Box](#3box) + - [ENS](#ens) - [Purgatory](#purgatory) - [Network Metadata](#network-metadata) - [👩‍🎤 Storybook](#-storybook) @@ -194,37 +194,21 @@ function Component() { } ``` -### 3Box +### ENS -Publishers can create a profile on [3Box Hub](https://www.3box.io/hub) and when found, it will be displayed in the app. +Publishers can fill their account's [ENS domain](https://ens.domains) profile and when found, it will be displayed in the app. -For this our own [3box-proxy](https://github.com/oceanprotocol/3box-proxy) is used, within the app the utility method `get3BoxProfile()` can be used to get all info: +For this our own [ens-proxy](https://github.com/oceanprotocol/ens-proxy) is used, within the app the utility method `getEnsProfile()` is called as part of the `useProfile()` hook: ```tsx -import get3BoxProfile from '@utils/profile' +import { useProfile } from '@context/Profile' function Component() { - const [profile, setProfile] = useState() + const { profile } = useProfile() - useEffect(() => { - if (!account) return - const source = axios.CancelToken.source() - - async function get3Box() { - const profile = await get3BoxProfile(account, source.token) - if (!profile) return - - setProfile(profile) - } - get3Box() - - return () => { - source.cancel() - } - }, [account]) return (
- {profile.emoji} {profile.name} + {profile.avatar} {profile.name}
) } diff --git a/package-lock.json b/package-lock.json index 1b96a2014..5f97423ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,6 @@ "gray-matter": "^4.0.3", "is-url-superb": "^6.1.0", "js-cookie": "^3.0.1", - "jwt-decode": "^3.1.2", "lodash.debounce": "^4.0.8", "lodash.omit": "^4.5.0", "myetherwallet-blockies": "^0.1.1", @@ -28113,11 +28112,6 @@ "node": ">=8" } }, - "node_modules/jwt-decode": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", - "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" - }, "node_modules/keccak": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", @@ -63001,11 +62995,6 @@ "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==", "dev": true }, - "jwt-decode": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", - "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" - }, "keccak": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", diff --git a/package.json b/package.json index 2d8f93351..e32d89988 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,6 @@ "gray-matter": "^4.0.3", "is-url-superb": "^6.1.0", "js-cookie": "^3.0.1", - "jwt-decode": "^3.1.2", "lodash.debounce": "^4.0.8", "lodash.omit": "^4.5.0", "myetherwallet-blockies": "^0.1.1", diff --git a/src/@context/Profile.tsx b/src/@context/Profile/index.tsx similarity index 78% rename from src/@context/Profile.tsx rename to src/@context/Profile/index.tsx index bd895c6a0..ab6b46f28 100644 --- a/src/@context/Profile.tsx +++ b/src/@context/Profile/index.tsx @@ -7,15 +7,18 @@ import React, { useCallback, ReactNode } from 'react' -import { getUserSales, getUserTokenOrders } from '@utils/subgraph' -import { useUserPreferences } from './UserPreferences' +import { getUserTokenOrders } from '@utils/subgraph' +import { useUserPreferences } from '../UserPreferences' import { Asset, LoggerInstance } from '@oceanprotocol/lib' -import { getDownloadAssets, getPublishedAssets } from '@utils/aquarius' -import { accountTruncate } from '@utils/web3' +import { + getDownloadAssets, + getPublishedAssets, + getUserSales +} from '@utils/aquarius' import axios, { CancelToken } from 'axios' -import get3BoxProfile from '@utils/profile' import web3 from 'web3' -import { useMarketMetadata } from './MarketMetadata' +import { useMarketMetadata } from '../MarketMetadata' +import { getEnsProfile } from '@utils/ens' interface ProfileProviderValue { profile: Profile @@ -32,6 +35,14 @@ const ProfileContext = createContext({} as ProfileProviderValue) const refreshInterval = 10000 // 10 sec. +const clearedProfile: Profile = { + name: null, + avatar: null, + url: null, + description: null, + links: null +} + function ProfileProvider({ accountId, accountEns, @@ -56,9 +67,9 @@ function ProfileProvider({ }, [accountId]) // - // User profile: ENS + 3Box + // User profile: ENS // - const [profile, setProfile] = useState() + const [profile, setProfile] = useState({ name: accountEns }) useEffect(() => { if (!accountEns) return @@ -66,53 +77,22 @@ function ProfileProvider({ }, [accountId, accountEns]) useEffect(() => { - const clearedProfile: Profile = { - name: null, - accountEns: null, - image: null, - description: null, - links: null - } - - if (!accountId || !isEthAddress) { + if ( + !accountId || + accountId === '0x0000000000000000000000000000000000000000' || + !isEthAddress + ) { setProfile(clearedProfile) return } - const cancelTokenSource = axios.CancelToken.source() - async function getInfo() { - setProfile({ name: accountEns || accountTruncate(accountId), accountEns }) - - const profile3Box = await get3BoxProfile( - accountId, - cancelTokenSource.token - ) - if (profile3Box) { - const { name, emoji, description, image, links } = profile3Box - const newName = `${emoji || ''} ${name || accountTruncate(accountId)}` - const newProfile = { - name: newName, - image, - description, - links - } - setProfile((prevState) => ({ - ...prevState, - ...newProfile - })) - LoggerInstance.log('[profile] Found and set 3box profile.', newProfile) - } else { - // setProfile(clearedProfile) - LoggerInstance.log('[profile] No 3box profile found.') - } + const profile = await getEnsProfile(accountId) + setProfile(profile) + LoggerInstance.log(`[profile] ENS metadata for ${accountId}:`, profile) } getInfo() - - return () => { - cancelTokenSource.cancel() - } - }, [accountId, accountEns, isEthAddress]) + }, [accountId, isEthAddress]) // // PUBLISHED ASSETS diff --git a/src/@context/Web3.tsx b/src/@context/Web3.tsx index 7dcf1dd38..71e48f19a 100644 --- a/src/@context/Web3.tsx +++ b/src/@context/Web3.tsx @@ -13,7 +13,7 @@ import { infuraProjectId as infuraId } from '../../app.config' import WalletConnectProvider from '@walletconnect/web3-provider' import { LoggerInstance } from '@oceanprotocol/lib' import { isBrowser } from '@utils/index' -import { getEnsName } from '@utils/ens' +import { getEnsProfile } from '@utils/ens' import useNetworkMetadata, { getNetworkDataById, getNetworkDisplayName, @@ -32,6 +32,7 @@ interface Web3ProviderValue { web3ProviderInfo: IProviderInfo accountId: string accountEns: string + accountEnsAvatar: string balance: UserBalance networkId: number chainId: number @@ -54,8 +55,6 @@ const web3ModalTheme = { hover: 'var(--background-highlight)' } -// HEADS UP! We inline-require some packages so the SSR build does not break. -// We only need them client-side. const providerOptions = isBrowser ? { walletconnect: { @@ -99,6 +98,7 @@ function Web3Provider({ children }: { children: ReactNode }): ReactElement { const [isTestnet, setIsTestnet] = useState() const [accountId, setAccountId] = useState() const [accountEns, setAccountEns] = useState() + const [accountEnsAvatar, setAccountEnsAvatar] = useState() const [web3Loading, setWeb3Loading] = useState(true) const [balance, setBalance] = useState({ eth: '0' @@ -192,24 +192,35 @@ function Web3Provider({ children }: { children: ReactNode }): ReactElement { }, [accountId, approvedBaseTokens, networkId, web3, networkData]) // ----------------------------------- - // Helper: Get user ENS name + // Helper: Get user ENS info // ----------------------------------- - const getUserEnsName = useCallback(async () => { + const getUserEns = useCallback(async () => { if (!accountId) return try { - // const accountEns = await getEnsNameWithWeb3( - // accountId, - // web3Provider, - // `${networkId}` - // ) - const accountEns = await getEnsName(accountId) - setAccountEns(accountEns) - accountEns && + const profile = await getEnsProfile(accountId) + + if (!profile) { + setAccountEns(null) + setAccountEnsAvatar(null) + return + } + + setAccountEns(profile.name) + LoggerInstance.log( + `[web3] ENS name found for ${accountId}:`, + profile.name + ) + + if (profile.avatar) { + setAccountEnsAvatar(profile.avatar) LoggerInstance.log( - `[web3] ENS name found for ${accountId}:`, - accountEns + `[web3] ENS avatar found for ${accountId}:`, + profile.avatar ) + } else { + setAccountEnsAvatar(null) + } } catch (error) { LoggerInstance.error('[web3] Error: ', error.message) } @@ -275,11 +286,11 @@ function Web3Provider({ children }: { children: ReactNode }): ReactElement { }, [getUserBalance]) // ----------------------------------- - // Get and set user ENS name + // Get and set user ENS info // ----------------------------------- useEffect(() => { - getUserEnsName() - }, [getUserEnsName]) + getUserEns() + }, [getUserEns]) // ----------------------------------- // Get and set network metadata @@ -337,7 +348,7 @@ function Web3Provider({ children }: { children: ReactNode }): ReactElement { // ----------------------------------- async function logout() { /* eslint-disable @typescript-eslint/no-explicit-any */ - if (web3 && web3.currentProvider && (web3.currentProvider as any).close) { + if ((web3?.currentProvider as any)?.close) { await (web3.currentProvider as any).close() } /* eslint-enable @typescript-eslint/no-explicit-any */ @@ -402,6 +413,7 @@ function Web3Provider({ children }: { children: ReactNode }): ReactElement { web3ProviderInfo, accountId, accountEns, + accountEnsAvatar, balance, networkId, chainId, diff --git a/src/@hooks/contracts/useNftFactory.ts b/src/@hooks/useNftFactory.ts similarity index 100% rename from src/@hooks/contracts/useNftFactory.ts rename to src/@hooks/useNftFactory.ts diff --git a/src/@types/Profile.d.ts b/src/@types/Profile.d.ts index 5649571b4..e0c1d1a69 100644 --- a/src/@types/Profile.d.ts +++ b/src/@types/Profile.d.ts @@ -1,36 +1,12 @@ interface ProfileLink { - name: string + key: string value: string } interface Profile { - did?: string - name?: string - accountEns?: string + name: string + url?: string + avatar?: string description?: string - emoji?: string - image?: string links?: ProfileLink[] } - -interface ResponseData3Box { - name: string - description: string - website: string - status?: 'error' - /* eslint-disable camelcase */ - proof_did: string - proof_twitter: string - proof_github: string - /* eslint-enable camelcase */ - emoji: string - job: string - employer: string - location: string - memberSince: string - image: { - contentUrl: { - [key: string]: string - } - }[] -} diff --git a/src/@types/viewModels/AccountTeaserVM.d.ts b/src/@types/viewModels/AccountTeaserVM.d.ts deleted file mode 100644 index 0367993da..000000000 --- a/src/@types/viewModels/AccountTeaserVM.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -interface AccountTeaserVM { - address: string - nrSales: number -} diff --git a/src/@utils/aquarius.ts b/src/@utils/aquarius.ts index 5ca056db2..036139f2d 100644 --- a/src/@utils/aquarius.ts +++ b/src/@utils/aquarius.ts @@ -9,6 +9,11 @@ import { } from '../@types/aquarius/SearchQuery' import { transformAssetToAssetSelection } from './assetConvertor' +export interface UserSales { + id: string + totalSales: number +} + export const MAXIMUM_NUMBER_OF_PAGES_WITH_RESULTS = 476 export function escapeEsReservedCharacters(value: string): string { @@ -397,6 +402,40 @@ export async function getTopPublishers( } } +export async function getTopAssetsPublishers( + chainIds: number[], + nrItems = 9 +): Promise { + const publishers: UserSales[] = [] + + const result = await getTopPublishers(chainIds, null) + const { topPublishers } = result.aggregations + + for (let i = 0; i < topPublishers.buckets.length; i++) { + publishers.push({ + id: topPublishers.buckets[i].key, + totalSales: parseInt(topPublishers.buckets[i].totalSales.value) + }) + } + + publishers.sort((a, b) => b.totalSales - a.totalSales) + + return publishers.slice(0, nrItems) +} + +export async function getUserSales( + accountId: string, + chainIds: number[] +): Promise { + try { + const result = await getPublishedAssets(accountId, chainIds, null) + const { totalOrders } = result.aggregations + return totalOrders.value + } catch (error) { + LoggerInstance.error('Error getUserSales', error.message) + } +} + export async function getDownloadAssets( dtList: string[], tokenOrders: OrdersData[], diff --git a/src/@utils/ens.test.ts b/src/@utils/ens.test.ts new file mode 100644 index 000000000..1cf27521a --- /dev/null +++ b/src/@utils/ens.test.ts @@ -0,0 +1,64 @@ +import { getEnsName, getEnsAddress, getEnsProfile } from './ens' + +describe('@utils/ens', () => { + jest.setTimeout(10000) + jest.retryTimes(2) + + test('getEnsName', async () => { + const ensName = await getEnsName( + '0x99840Df5Cb42faBE0Feb8811Aaa4BC99cA6C84e0' + ) + expect(ensName).toBe('jellymcjellyfish.eth') + }) + + test('getEnsName with invalid address', async () => { + const ensName = await getEnsName('0x123') + expect(ensName).toBeUndefined() + }) + + test('getEnsName with empty address', async () => { + const ensName = await getEnsName('') + expect(ensName).toBeUndefined() + }) + + test('getEnsName with undefined address', async () => { + const ensName = await getEnsName(undefined) + expect(ensName).toBeUndefined() + }) + + test('getEnsAddress', async () => { + const ensAddress = await getEnsAddress('jellymcjellyfish.eth') + expect(ensAddress).toBe('0x99840Df5Cb42faBE0Feb8811Aaa4BC99cA6C84e0') + }) + + test('getEnsAddress with invalid address', async () => { + const ensAddress = await getEnsAddress('0x123') + expect(ensAddress).toBeUndefined() + }) + + test('getEnsAddress with empty address', async () => { + const ensAddress = await getEnsAddress('') + expect(ensAddress).toBeUndefined() + }) + + test('getEnsProfile', async () => { + const ensProfile = await getEnsProfile( + '0x99840Df5Cb42faBE0Feb8811Aaa4BC99cA6C84e0' + ) + expect(ensProfile).toEqual({ + avatar: + 'https://metadata.ens.domains/mainnet/avatar/jellymcjellyfish.eth', + links: [ + { key: 'url', value: 'https://oceanprotocol.com' }, + { key: 'com.twitter', value: 'oceanprotocol' }, + { key: 'com.github', value: 'oceanprotocol' } + ], + name: 'jellymcjellyfish.eth' + }) + }) + + test('getEnsProfile with empty address', async () => { + const ensProfile = await getEnsProfile('') + expect(ensProfile).toBeUndefined() + }) +}) diff --git a/src/@utils/ens.ts b/src/@utils/ens.ts index 9f2807bc3..b367db96e 100644 --- a/src/@utils/ens.ts +++ b/src/@utils/ens.ts @@ -1,52 +1,24 @@ -import { gql, OperationContext, OperationResult } from 'urql' -import { fetchData } from './subgraph' +import { fetchData } from './fetch' -// make sure to only query for domains owned by account, so domains -// solely set by 3rd parties like *.gitcoin.eth won't show up -const UserEnsNames = gql` - query UserEnsDomains($accountId: String!) { - domains(where: { resolvedAddress: $accountId, owner: $accountId }) { - name - } - } -` - -const UserEnsAddress = gql` - query UserEnsDomainsAddress($name: String!) { - domains(where: { name: $name }) { - resolvedAddress { - id - } - } - } -` - -const ensSubgraphQueryContext: OperationContext = { - url: `https://api.thegraph.com/subgraphs/name/ensdomains/ens`, - requestPolicy: 'cache-and-network' -} +const apiUrl = 'https://ens-proxy.oceanprotocol.com/api' export async function getEnsName(accountId: string): Promise { - const response: OperationResult = await fetchData( - UserEnsNames, - { accountId: accountId.toLowerCase() }, - ensSubgraphQueryContext - ) - if (!response?.data?.domains?.length) return + if (!accountId || accountId === '') return - // Default order of response.data.domains seems to be by creation time, from oldest to newest. - // Pick the last one as that is what direct web3 calls do. - const { name } = response.data.domains.slice(-1)[0] - return name + const data = await fetchData(`${apiUrl}/name?accountId=${accountId}`) + return data?.name } -export async function getEnsAddress(ensName: string): Promise { - const response: OperationResult = await fetchData( - UserEnsAddress, - { name: ensName }, - ensSubgraphQueryContext - ) - if (!response?.data?.domains?.length) return - const { id } = response.data.domains[0].resolvedAddress - return id +export async function getEnsAddress(accountId: string): Promise { + if (!accountId || accountId === '' || !accountId.includes('.')) return + + const data = await fetchData(`${apiUrl}/address?name=${accountId}`) + return data?.address +} + +export async function getEnsProfile(accountId: string): Promise { + if (!accountId || accountId === '') return + + const data = await fetchData(`${apiUrl}/profile?address=${accountId}`) + return data?.profile } diff --git a/src/@utils/fetch.ts b/src/@utils/fetch.ts index 2c07ff444..305e06b3f 100644 --- a/src/@utils/fetch.ts +++ b/src/@utils/fetch.ts @@ -1,15 +1,24 @@ +import { LoggerInstance } from '@oceanprotocol/lib' import axios, { AxiosResponse } from 'axios' 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 + return response?.data } catch (error) { - console.error('Error parsing json: ' + error.message) + if (error.response) { + // The request was made and the server responded with a status code + // that falls out of the range of 2xx + LoggerInstance.error(`Non-200 response from ${url}:`, error.response) + } else if (error.request) { + // The request was made but no response was received + // `error.request` is an instance of XMLHttpRequest in the browser and an instance of + // http.ClientRequest in node.js + LoggerInstance.error('No response with:', error.request) + } else { + // Something happened in setting up the request that triggered an Error + LoggerInstance.error('Error in setting up request:', error.message) + } + LoggerInstance.error(error.message) } } diff --git a/src/@utils/numbers.ts b/src/@utils/numbers.ts index 0d31581bf..e7b4a4327 100644 --- a/src/@utils/numbers.ts +++ b/src/@utils/numbers.ts @@ -1,14 +1,5 @@ import { Decimal } from 'decimal.js' -export function isValidNumber(value: any): boolean { - const isUndefinedValue = typeof value === 'undefined' - const isNullValue = value === null - const isNaNValue = isNaN(Number(value)) - const isEmptyString = value === '' - - return !isUndefinedValue && !isNullValue && !isNaNValue && !isEmptyString -} - // Run decimal.js comparison // http://mikemcl.github.io/decimal.js/#cmp export function compareAsBN(balance: string, price: string): boolean { diff --git a/src/@utils/pricingFeedback.ts b/src/@utils/pricingFeedback.ts deleted file mode 100644 index ad49d8cbd..000000000 --- a/src/@utils/pricingFeedback.ts +++ /dev/null @@ -1,15 +0,0 @@ -export function getBuyDTFeedback(dtSymbol: string): { [key: number]: string } { - return { - 1: '1/3 Approving OCEAN ...', - 2: `2/3 Buying ${dtSymbol} ...`, - 3: `3/3 ${dtSymbol} bought.` - } -} - -export function getSellDTFeedback(dtSymbol: string): { [key: number]: string } { - return { - 1: '1/3 Approving OCEAN ...', - 2: `2/3 Selling ${dtSymbol} ...`, - 3: `3/3 ${dtSymbol} sold.` - } -} diff --git a/src/@utils/profile.ts b/src/@utils/profile.ts deleted file mode 100644 index b61bc1c4b..000000000 --- a/src/@utils/profile.ts +++ /dev/null @@ -1,94 +0,0 @@ -import axios, { AxiosResponse, CancelToken } from 'axios' -import jwtDecode from 'jwt-decode' - -// https://docs.3box.io/api/rest-api -const apiUri = 'https://3box.oceanprotocol.com' -const ipfsUrl = 'https://infura-ipfs.io' - -function decodeProof(proofJWT: string) { - if (!proofJWT) return - const proof = jwtDecode(proofJWT) as any - return proof -} - -function getLinks( - website: string, - twitterProof: string, - githubProof: string -): ProfileLink[] { - // Conditionally add links if they exist - const links = [ - ...(website ? [{ name: 'Website', value: website }] : []), - ...(twitterProof - ? [ - { - name: 'Twitter', - value: decodeProof(twitterProof).claim.twitter_handle - } - ] - : []), - ...(githubProof - ? [{ name: 'GitHub', value: githubProof.split('/')[3] }] - : []) - ] - - return links -} - -function transformResponse({ - name, - description, - website, - emoji, - image, - /* eslint-disable camelcase */ - proof_twitter, - proof_github, - proof_did -}: ResponseData3Box) { - /* eslint-enable camelcase */ - const links = getLinks(website, proof_twitter, proof_github) - - const profile: Profile = { - did: decodeProof(proof_did).iss, - // Conditionally add profile items if they exist - ...(name && { name }), - ...(description && { description }), - ...(emoji && { emoji }), - ...(image && { - image: `${ipfsUrl}/ipfs/${ - image.map( - (img: { contentUrl: { [key: string]: string } }) => - img.contentUrl['/'] - )[0] - }` - }), - ...(links.length && { links }) - } - - return profile -} - -export default async function get3BoxProfile( - accountId: string, - cancelToken: CancelToken -): Promise { - try { - const response = (await axios(`${apiUri}/profile/${accountId}`, { - cancelToken - })) as AxiosResponse - - if ( - !response || - !response.data || - response.status !== 200 || - response.data.status === 'error' - ) - return - - // LoggerInstance.log(`3Box profile found for ${accountId}`, response.data) - const profile = transformResponse(response.data) - return profile - // eslint-disable-next-line no-empty - } catch (error) {} -} diff --git a/src/@utils/purgatory.ts b/src/@utils/purgatory.ts index 9d9dae043..81ed2a33e 100644 --- a/src/@utils/purgatory.ts +++ b/src/@utils/purgatory.ts @@ -1,4 +1,3 @@ -import { Purgatory } from '@oceanprotocol/lib' import { fetchData } from './fetch' const purgatoryUrl = 'https://market-purgatory.oceanprotocol.com/api/' diff --git a/src/@utils/subgraph.ts b/src/@utils/subgraph.ts index 41ca897bf..c8ac601f9 100644 --- a/src/@utils/subgraph.ts +++ b/src/@utils/subgraph.ts @@ -6,16 +6,6 @@ import { AssetPreviousOrder } from '../@types/subgraph/AssetPreviousOrder' import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData' import { OpcFeesQuery as OpcFeesData } from '../@types/subgraph/OpcFeesQuery' -import { getPublishedAssets, getTopPublishers } from '@utils/aquarius' -export interface UserLiquidity { - price: string - oceanBalance: string -} - -export interface PriceList { - [key: string]: string -} - const PreviousOrderQuery = gql` query AssetPreviousOrder($id: String!, $account: String!) { orders( @@ -153,29 +143,6 @@ export async function getOpcFees(chainId: number) { return opcFees } -export async function getPreviousOrders( - id: string, - account: string, - assetTimeout: string -): Promise { - const variables = { id, account } - const fetchedPreviousOrders: OperationResult = - await fetchData(PreviousOrderQuery, variables, null) - if (fetchedPreviousOrders.data?.orders?.length === 0) return null - if (assetTimeout === '0') { - return fetchedPreviousOrders?.data?.orders[0]?.tx - } else { - const expiry = - fetchedPreviousOrders?.data?.orders[0]?.createdTimestamp * 1000 + - Number(assetTimeout) * 1000 - if (Date.now() <= expiry) { - return fetchedPreviousOrders?.data?.orders[0]?.tx - } else { - return null - } - } -} - export async function getUserTokenOrders( accountId: string, chainIds: number[] @@ -201,40 +168,6 @@ export async function getUserTokenOrders( } } -export async function getUserSales( - accountId: string, - chainIds: number[] -): Promise { - try { - const result = await getPublishedAssets(accountId, chainIds, null) - const { totalOrders } = result.aggregations - return totalOrders.value - } catch (error) { - LoggerInstance.error('Error getUserSales', error.message) - } -} - -export async function getTopAssetsPublishers( - chainIds: number[], - nrItems = 9 -): Promise { - const publishers: AccountTeaserVM[] = [] - - const result = await getTopPublishers(chainIds, null) - const { topPublishers } = result.aggregations - - for (let i = 0; i < topPublishers.buckets.length; i++) { - publishers.push({ - address: topPublishers.buckets[i].key, - nrSales: parseInt(topPublishers.buckets[i].totalSales.value) - }) - } - - publishers.sort((a, b) => b.nrSales - a.nrSales) - - return publishers.slice(0, nrItems) -} - export async function getOpcsApprovedTokens( chainId: number ): Promise { diff --git a/src/components/@shared/AccountList/AccountList.tsx b/src/components/@shared/AccountList/AccountList.tsx deleted file mode 100644 index fc2a9fa6d..000000000 --- a/src/components/@shared/AccountList/AccountList.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React, { ReactElement } from 'react' -import styles from './index.module.css' -import classNames from 'classnames/bind' -import Loader from '../atoms/Loader' -import { useUserPreferences } from '@context/UserPreferences' -import AccountTeaser from '@shared/AccountTeaser/AccountTeaser' - -const cx = classNames.bind(styles) - -function LoaderArea() { - return ( -
- -
- ) -} - -declare type AccountListProps = { - accounts: AccountTeaserVM[] - isLoading: boolean - className?: string -} - -export default function AccountList({ - accounts, - isLoading, - className -}: AccountListProps): ReactElement { - const { chainIds } = useUserPreferences() - - const styleClasses = cx({ - accountList: true, - [className]: className - }) - - return accounts && (isLoading === undefined || isLoading === false) ? ( - <> -
- {accounts.length > 0 ? ( - accounts.map((account, index) => ( - - )) - ) : chainIds.length === 0 ? ( -
No network selected.
- ) : ( -
No results found.
- )} -
- - ) : ( - - ) -} diff --git a/src/components/@shared/AccountTeaser/AccountTeaser.tsx b/src/components/@shared/AccountTeaser/AccountTeaser.tsx deleted file mode 100644 index 4a20867a7..000000000 --- a/src/components/@shared/AccountTeaser/AccountTeaser.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import React, { ReactElement, useEffect, useState } from 'react' -import Dotdotdot from 'react-dotdotdot' -import Link from 'next/link' -import styles from './AccountTeaser.module.css' -import Blockies from '../atoms/Blockies' -import { useCancelToken } from '@hooks/useCancelToken' -import get3BoxProfile from '@utils/profile' -import { accountTruncate } from '@utils/web3' - -declare type AccountTeaserProps = { - accountTeaserVM: AccountTeaserVM - place?: number -} - -export default function AccountTeaser({ - accountTeaserVM, - place -}: AccountTeaserProps): ReactElement { - const [profile, setProfile] = useState() - const newCancelToken = useCancelToken() - - useEffect(() => { - if (!accountTeaserVM) return - async function getProfileData() { - const profile = await get3BoxProfile( - accountTeaserVM.address, - newCancelToken() - ) - if (!profile) return - setProfile(profile) - } - getProfileData() - }, [accountTeaserVM, newCancelToken]) - - return ( - - - {place && {place}} - -
- - {profile?.name - ? profile?.name - : accountTruncate(accountTeaserVM.address)} - -

- {accountTeaserVM.nrSales} - {`${accountTeaserVM.nrSales === 1 ? ' sale' : ' sales'}`} -

-
-
- - ) -} diff --git a/src/components/@shared/Publisher/Add.module.css b/src/components/@shared/Publisher/Add.module.css deleted file mode 100644 index 3482d355f..000000000 --- a/src/components/@shared/Publisher/Add.module.css +++ /dev/null @@ -1,7 +0,0 @@ -.add { - color: var(--brand-pink); -} - -.linksExternal { - composes: linksExternal from './index.module.css'; -} diff --git a/src/components/@shared/Publisher/Add.tsx b/src/components/@shared/Publisher/Add.tsx deleted file mode 100644 index f40437fc7..000000000 --- a/src/components/@shared/Publisher/Add.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React, { ReactElement } from 'react' -import External from '@images/external.svg' -import styles from './Add.module.css' - -export default function Add(): ReactElement { - return ( - - Add profile on 3Box - - ) -} diff --git a/src/components/@shared/Publisher/index.module.css b/src/components/@shared/Publisher/index.module.css index 93592f599..0bddf6f83 100644 --- a/src/components/@shared/Publisher/index.module.css +++ b/src/components/@shared/Publisher/index.module.css @@ -7,10 +7,3 @@ display: inline-block; } } - -.linksExternal { - width: 6px; - height: 6px; - display: inline-block; - fill: var(--color-secondary); -} diff --git a/src/components/@shared/Publisher/index.test.tsx b/src/components/@shared/Publisher/index.test.tsx new file mode 100644 index 000000000..ffe21a8db --- /dev/null +++ b/src/components/@shared/Publisher/index.test.tsx @@ -0,0 +1,56 @@ +import React from 'react' +import { render, screen } from '@testing-library/react' +import * as axios from 'axios' +import Publisher from './' + +const account = '0x0000000000000000000000000000000000000000' + +jest.mock('axios') + +describe('Publisher', () => { + test('should return correct markup by default', async () => { + ;(axios as any).get.mockImplementationOnce(() => + Promise.resolve({ data: { name: 'jellymcjellyfish.eth' } }) + ) + + render() + + const element = await screen.findByRole('link') + expect(element).toBeInTheDocument() + expect(element).toContainHTML(' { + ;(axios as any).get.mockImplementationOnce(() => + Promise.resolve({ data: { name: null } }) + ) + + render() + + const element = await screen.findByText('0x…00000000') + expect(element).toBeInTheDocument() + }) + + test('should return correct markup in minimal state', async () => { + ;(axios as any).get.mockImplementationOnce(() => + Promise.resolve({ data: { name: null } }) + ) + + render() + + const element = await screen.findByText('0x…00000000') + expect(element).not.toHaveAttribute('href') + }) + + test('should return markup with empty account', async () => { + ;(axios as any).get.mockImplementationOnce(() => + Promise.resolve({ data: { name: null } }) + ) + + render() + + const element = await screen.findByRole('link') + expect(element).toBeInTheDocument() + }) +}) diff --git a/src/components/@shared/Publisher/index.tsx b/src/components/@shared/Publisher/index.tsx index 0eecd5fa0..55589b5b1 100644 --- a/src/components/@shared/Publisher/index.tsx +++ b/src/components/@shared/Publisher/index.tsx @@ -1,72 +1,47 @@ import React, { ReactElement, useEffect, useState } from 'react' import styles from './index.module.css' -import classNames from 'classnames/bind' import Link from 'next/link' -import get3BoxProfile from '@utils/profile' import { accountTruncate } from '@utils/web3' -import axios from 'axios' import { getEnsName } from '@utils/ens' import { useIsMounted } from '@hooks/useIsMounted' -const cx = classNames.bind(styles) +export interface PublisherProps { + account: string + minimal?: boolean + className?: string +} export default function Publisher({ account, minimal, className -}: { - account: string - minimal?: boolean - className?: string -}): ReactElement { +}: PublisherProps): ReactElement { const isMounted = useIsMounted() - const [profile, setProfile] = useState() - const [name, setName] = useState('') - const [accountEns, setAccountEns] = useState() + const [name, setName] = useState(accountTruncate(account)) useEffect(() => { - if (!account) return + if (!account || account === '') return // set default name on hook // to avoid side effect (UI not updating on account's change) setName(accountTruncate(account)) - const source = axios.CancelToken.source() - async function getExternalName() { - // ENS const accountEns = await getEnsName(account) if (accountEns && isMounted()) { - setAccountEns(accountEns) setName(accountEns) } - - // 3box - const profile = await get3BoxProfile(account, source.token) - if (!profile) return - setProfile(profile) - const { name, emoji } = profile - name && setName(`${emoji || ''} ${name}`) } getExternalName() - - return () => { - source.cancel() - } }, [account, isMounted]) - const styleClasses = cx({ - publisher: true, - [className]: className - }) - return ( -
+
{minimal ? ( name ) : ( <> - + {name} diff --git a/src/components/@shared/atoms/Blockies/index.module.css b/src/components/@shared/atoms/Avatar/index.module.css similarity index 93% rename from src/components/@shared/atoms/Blockies/index.module.css rename to src/components/@shared/atoms/Avatar/index.module.css index 928123b18..26ddad81d 100644 --- a/src/components/@shared/atoms/Blockies/index.module.css +++ b/src/components/@shared/atoms/Avatar/index.module.css @@ -1,4 +1,4 @@ -.blockies { +.avatar { width: var(--font-size-large); height: var(--font-size-large); border-radius: 50%; diff --git a/src/components/@shared/atoms/Avatar/index.stories.tsx b/src/components/@shared/atoms/Avatar/index.stories.tsx new file mode 100644 index 000000000..eb3b25a34 --- /dev/null +++ b/src/components/@shared/atoms/Avatar/index.stories.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import { ComponentStory, ComponentMeta } from '@storybook/react' + +import Avatar, { AvatarProps } from '@shared/atoms/Avatar' + +export default { + title: 'Component/@shared/atoms/Avatar', + component: Avatar +} as ComponentMeta + +const Template: ComponentStory = (args) => + +interface Props { + args: AvatarProps +} + +export const DefaultWithBlockies: Props = Template.bind({}) +DefaultWithBlockies.args = { + accountId: '0x1234567890123456789012345678901234567890' +} + +export const CustomSource: Props = Template.bind({}) +CustomSource.args = { + accountId: '0x1234567890123456789012345678901234567890', + src: 'http://placekitten.com/g/300/300' +} + +export const Empty: Props = Template.bind({}) +Empty.args = { + accountId: null +} diff --git a/src/components/@shared/atoms/Avatar/index.test.tsx b/src/components/@shared/atoms/Avatar/index.test.tsx new file mode 100644 index 000000000..2d0030433 --- /dev/null +++ b/src/components/@shared/atoms/Avatar/index.test.tsx @@ -0,0 +1,19 @@ +import React from 'react' +import testRender from '../../../../../.jest/testRender' +import Avatar from '@shared/atoms/Avatar' +import { DefaultWithBlockies, CustomSource, Empty } from './index.stories' +import { render } from '@testing-library/react' + +describe('Avatar', () => { + testRender() + + it('renders without crashing with custom source', () => { + const { container } = render() + expect(container.firstChild).toBeInTheDocument() + }) + + it('renders empty without crashing', () => { + const { container } = render() + expect(container.firstChild).toBeInTheDocument() + }) +}) diff --git a/src/components/@shared/atoms/Avatar/index.tsx b/src/components/@shared/atoms/Avatar/index.tsx new file mode 100644 index 000000000..436fbdc2a --- /dev/null +++ b/src/components/@shared/atoms/Avatar/index.tsx @@ -0,0 +1,24 @@ +import { toDataUrl } from 'myetherwallet-blockies' +import React, { ReactElement } from 'react' +import styles from './index.module.css' + +export interface AvatarProps { + accountId: string + src?: string + className?: string +} + +export default function Avatar({ + accountId, + src, + className +}: AvatarProps): ReactElement { + return ( + + ) +} diff --git a/src/components/@shared/atoms/Blockies/index.stories.tsx b/src/components/@shared/atoms/Blockies/index.stories.tsx deleted file mode 100644 index 12137bf5f..000000000 --- a/src/components/@shared/atoms/Blockies/index.stories.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react' -import { ComponentStory, ComponentMeta } from '@storybook/react' - -import Blockies, { BlockiesProps } from '@shared/atoms/Blockies' - -export default { - title: 'Component/@shared/atoms/Blockies', - component: Blockies -} as ComponentMeta - -const Template: ComponentStory = (args) => ( - -) - -interface Props { - args: BlockiesProps -} - -export const Default: Props = Template.bind({}) -Default.args = { - accountId: '0x1xxxxxxxxxx3Exxxxxx7xxxxxxxxxxxxF1fd' -} diff --git a/src/components/@shared/atoms/Blockies/index.test.tsx b/src/components/@shared/atoms/Blockies/index.test.tsx deleted file mode 100644 index b0bd9443c..000000000 --- a/src/components/@shared/atoms/Blockies/index.test.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react' -import testRender from '../../../../../.jest/testRender' -import Blockies from '@shared/atoms/Blockies' -import { Default } from './index.stories' - -describe('Blockies', () => { - testRender() -}) diff --git a/src/components/@shared/atoms/Blockies/index.tsx b/src/components/@shared/atoms/Blockies/index.tsx deleted file mode 100644 index ba3a23070..000000000 --- a/src/components/@shared/atoms/Blockies/index.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { toDataUrl } from 'myetherwallet-blockies' -import React, { ReactElement } from 'react' -import styles from './index.module.css' - -export interface BlockiesProps { - accountId: string - className?: string - image?: string -} - -export default function Blockies({ - accountId, - className, - image -}: BlockiesProps): ReactElement { - if (!accountId) return null - - const blockies = toDataUrl(accountId) - - return ( - - ) -} diff --git a/src/components/Header/Wallet/Account.tsx b/src/components/Header/Wallet/Account.tsx index e81f4edd5..d19a01f0a 100644 --- a/src/components/Header/Wallet/Account.tsx +++ b/src/components/Header/Wallet/Account.tsx @@ -4,12 +4,13 @@ import { accountTruncate } from '@utils/web3' import Loader from '@shared/atoms/Loader' import styles from './Account.module.css' import { useWeb3 } from '@context/Web3' -import Blockies from '@shared/atoms/Blockies' +import Avatar from '@shared/atoms/Avatar' // Forward ref for Tippy.js // eslint-disable-next-line const Account = React.forwardRef((props, ref: any) => { - const { accountId, accountEns, web3Modal, connect } = useWeb3() + const { accountId, accountEns, accountEnsAvatar, web3Modal, connect } = + useWeb3() async function handleActivation(e: FormEvent) { // prevent accidentially submitting a form the button might be in @@ -30,7 +31,7 @@ const Account = React.forwardRef((props, ref: any) => { ref={ref} onClick={(e) => e.preventDefault()} > - + {accountTruncate(accountEns || accountId)} diff --git a/src/components/@shared/AccountTeaser/AccountTeaser.module.css b/src/components/Home/TopSales/Account/index.module.css similarity index 92% rename from src/components/@shared/AccountTeaser/AccountTeaser.module.css rename to src/components/Home/TopSales/Account/index.module.css index e042e0f7f..2e3353c5b 100644 --- a/src/components/@shared/AccountTeaser/AccountTeaser.module.css +++ b/src/components/Home/TopSales/Account/index.module.css @@ -1,4 +1,4 @@ -.blockies { +.avatar { aspect-ratio: 1/1; width: calc(var(--font-size-large) * 2) !important; height: calc(var(--font-size-large) * 2) !important; @@ -8,7 +8,7 @@ } .teaser { - composes: box from '../atoms/Box.module.css'; + composes: box from '@shared/atoms/Box.module.css'; padding: calc(var(--spacer) / 3) calc(var(--spacer) / 2); color: var(--color-secondary); position: relative; diff --git a/src/components/Home/TopSales/Account/index.tsx b/src/components/Home/TopSales/Account/index.tsx new file mode 100644 index 000000000..a56048202 --- /dev/null +++ b/src/components/Home/TopSales/Account/index.tsx @@ -0,0 +1,53 @@ +import React, { ReactElement, useEffect, useState } from 'react' +import Dotdotdot from 'react-dotdotdot' +import Link from 'next/link' +import styles from './index.module.css' +import { accountTruncate } from '@utils/web3' +import Avatar from '../../../@shared/atoms/Avatar' +import { getEnsProfile } from '@utils/ens' +import { UserSales } from '@utils/aquarius' + +declare type AccountProps = { + account: UserSales + place?: number +} + +export default function Account({ + account, + place +}: AccountProps): ReactElement { + const [profile, setProfile] = useState() + + useEffect(() => { + if (!account?.id) return + + async function getProfileData() { + const profile = await getEnsProfile(account.id) + if (!profile) return + setProfile(profile) + } + getProfileData() + }, [account?.id]) + + return ( + + + {place && {place}} + +
+ + {profile?.name ? profile?.name : accountTruncate(account.id)} + +

+ {account.totalSales} + {`${account.totalSales === 1 ? ' sale' : ' sales'}`} +

+
+
+ + ) +} diff --git a/src/components/Home/TopSales/AccountList/index.module.css b/src/components/Home/TopSales/AccountList/index.module.css new file mode 100644 index 000000000..2a4b6a7a3 --- /dev/null +++ b/src/components/Home/TopSales/AccountList/index.module.css @@ -0,0 +1,11 @@ +.list { + composes: assetList from '@shared/AssetList/index.module.css'; +} + +.loaderWrap { + composes: loaderWrap from '@shared/AssetList/index.module.css'; +} + +.empty { + composes: empty from '@shared/AssetList/index.module.css'; +} diff --git a/src/components/Home/TopSales/AccountList/index.tsx b/src/components/Home/TopSales/AccountList/index.tsx new file mode 100644 index 000000000..1cbc2f94a --- /dev/null +++ b/src/components/Home/TopSales/AccountList/index.tsx @@ -0,0 +1,43 @@ +import React, { ReactElement } from 'react' +import styles from './index.module.css' +import Loader from '../../../@shared/atoms/Loader' +import { useUserPreferences } from '@context/UserPreferences' +import Account from 'src/components/Home/TopSales/Account' +import { UserSales } from '@utils/aquarius' + +function LoaderArea() { + return ( +
+ +
+ ) +} + +declare type AccountListProps = { + accounts: UserSales[] + isLoading: boolean + className?: string +} + +export default function AccountList({ + accounts, + isLoading +}: AccountListProps): ReactElement { + const { chainIds } = useUserPreferences() + const emptyText = + chainIds.length === 0 ? 'No network selected.' : 'No results found.' + + return isLoading ? ( + + ) : ( +
+ {accounts?.length > 0 ? ( + accounts.map((account, index) => ( + + )) + ) : ( +
{emptyText}
+ )} +
+ ) +} diff --git a/src/components/Home/TopSales/index.module.css b/src/components/Home/TopSales/index.module.css new file mode 100644 index 000000000..d176386d7 --- /dev/null +++ b/src/components/Home/TopSales/index.module.css @@ -0,0 +1,3 @@ +.section { + composes: section from '../index.module.css'; +} diff --git a/src/components/Home/PublishersWithMostSales.tsx b/src/components/Home/TopSales/index.tsx similarity index 79% rename from src/components/Home/PublishersWithMostSales.tsx rename to src/components/Home/TopSales/index.tsx index c36b7857b..44eb3176c 100644 --- a/src/components/Home/PublishersWithMostSales.tsx +++ b/src/components/Home/TopSales/index.tsx @@ -1,11 +1,11 @@ import { useUserPreferences } from '@context/UserPreferences' import { LoggerInstance } from '@oceanprotocol/lib' -import AccountList from '@shared/AccountList/AccountList' -import { getTopAssetsPublishers } from '@utils/subgraph' +import AccountList from 'src/components/Home/TopSales/AccountList' +import { getTopAssetsPublishers, UserSales } from '@utils/aquarius' import React, { ReactElement, useEffect, useState } from 'react' import styles from './index.module.css' -export default function PublishersWithMostSales({ +export default function TopSales({ title, action }: { @@ -13,14 +13,14 @@ export default function PublishersWithMostSales({ action?: ReactElement }): ReactElement { const { chainIds } = useUserPreferences() - const [result, setResult] = useState([]) + const [result, setResult] = useState([]) const [loading, setLoading] = useState() useEffect(() => { async function init() { setLoading(true) if (chainIds.length === 0) { - const result: AccountTeaserVM[] = [] + const result: UserSales[] = [] setResult(result) setLoading(false) } else { diff --git a/src/components/Home/index.tsx b/src/components/Home/index.tsx index 8fdd86799..e256ee102 100644 --- a/src/components/Home/index.tsx +++ b/src/components/Home/index.tsx @@ -5,11 +5,11 @@ import Bookmarks from './Bookmarks' import { generateBaseQuery, queryMetadata } from '@utils/aquarius' import { Asset, LoggerInstance } from '@oceanprotocol/lib' import { useUserPreferences } from '@context/UserPreferences' -import styles from './index.module.css' import { useIsMounted } from '@hooks/useIsMounted' import { useCancelToken } from '@hooks/useCancelToken' import { SortTermOptions } from '../../@types/aquarius/SearchQuery' -import PublishersWithMostSales from './PublishersWithMostSales' +import TopSales from './TopSales' +import styles from './index.module.css' function sortElements(items: Asset[], sorted: string[]) { items.sort(function (a, b) { @@ -136,7 +136,7 @@ export default function HomePage(): ReactElement { } /> - + ) } diff --git a/src/components/Profile/Header/Account.tsx b/src/components/Profile/Header/Account.tsx index bbf2a676b..0aab25685 100644 --- a/src/components/Profile/Header/Account.tsx +++ b/src/components/Profile/Header/Account.tsx @@ -4,9 +4,10 @@ import ExplorerLink from '@shared/ExplorerLink' import NetworkName from '@shared/NetworkName' import Jellyfish from '@oceanprotocol/art/creatures/jellyfish/jellyfish-grid.svg' import Copy from '@shared/atoms/Copy' -import Blockies from '@shared/atoms/Blockies' +import Avatar from '@shared/atoms/Avatar' import styles from './Account.module.css' import { useProfile } from '@context/Profile' +import { accountTruncate } from '@utils/web3' export default function Account({ accountId @@ -19,28 +20,27 @@ export default function Account({ return (
- {profile?.image ? ( - - ) : accountId ? ( - ) : ( )}
-

{profile?.name}

+

+ {profile?.name || accountTruncate(accountId)} +

{accountId && ( - {profile?.accountEns || accountId} + {accountId} )}

diff --git a/src/components/Profile/Header/PublisherLinks.module.css b/src/components/Profile/Header/PublisherLinks.module.css index a7970a765..006de6983 100644 --- a/src/components/Profile/Header/PublisherLinks.module.css +++ b/src/components/Profile/Header/PublisherLinks.module.css @@ -24,5 +24,8 @@ } .linksExternal { - composes: linksExternal from '@shared/Publisher/index.module.css'; + width: 6px; + height: 6px; + display: inline-block; + fill: var(--color-secondary); } diff --git a/src/components/Profile/Header/PublisherLinks.tsx b/src/components/Profile/Header/PublisherLinks.tsx index 023ea4085..ca6f97b84 100644 --- a/src/components/Profile/Header/PublisherLinks.tsx +++ b/src/components/Profile/Header/PublisherLinks.tsx @@ -6,6 +6,39 @@ import { useProfile } from '@context/Profile' const cx = classNames.bind(styles) +function getLinkData(link: ProfileLink): { href: string; label: string } { + let href, label + + switch (link.key) { + case 'url': + href = link.value + label = 'Website' + break + case 'com.twitter': + href = `https://twitter.com/${link.value}` + label = 'Twitter' + break + case 'com.github': + href = `https://github.com/${link.value}` + label = 'GitHub' + break + case 'org.telegram': + href = `https://telegram.org/${link.value}` + label = 'Telegram' + break + case 'com.discord': + href = `https://discordapp.com/users/${link.value}` + label = 'Discord' + break + case 'com.reddit': + href = `https://reddit.com/u/${link.value}` + label = 'Reddit' + break + } + + return { href, label } +} + export default function PublisherLinks({ className }: { @@ -21,22 +54,17 @@ export default function PublisherLinks({ return (

{' — '} - {profile?.links?.map((link) => { - const href = - link.name === 'Twitter' - ? `https://twitter.com/${link.value}` - : link.name === 'GitHub' - ? `https://github.com/${link.value}` - : link.value.includes('http') // safeguard against urls without protocol defined - ? link.value - : `//${link.value}` - - return ( - - {link.name} - - ) - })} + {profile?.links?.map((link) => ( + + {getLinkData(link).label}{' '} + + + ))}
) } diff --git a/src/components/Profile/Header/index.tsx b/src/components/Profile/Header/index.tsx index 15afbe128..a09165606 100644 --- a/src/components/Profile/Header/index.tsx +++ b/src/components/Profile/Header/index.tsx @@ -43,8 +43,8 @@ export default function AccountHeader({ {isDescriptionTextClamped() ? ( ) : ( @@ -56,18 +56,9 @@ export default function AccountHeader({
Profile data from{' '} - {profile?.accountEns && ( - <> - {' '} - &{' '} - - )}
diff --git a/src/components/Publish/index.tsx b/src/components/Publish/index.tsx index 7035128ba..9e3cc6480 100644 --- a/src/components/Publish/index.tsx +++ b/src/components/Publish/index.tsx @@ -13,7 +13,7 @@ import Navigation from './Navigation' import { Steps } from './Steps' import { FormPublishData } from './_types' import { useUserPreferences } from '@context/UserPreferences' -import useNftFactory from '@hooks/contracts/useNftFactory' +import useNftFactory from '@hooks/useNftFactory' import { ProviderInstance, LoggerInstance, DDO } from '@oceanprotocol/lib' import { getOceanConfig } from '@utils/ocean' import { validationSchema } from './_validation' diff --git a/src/pages/profile/index.tsx b/src/pages/profile/index.tsx index 4bb1949bd..d14b24f94 100644 --- a/src/pages/profile/index.tsx +++ b/src/pages/profile/index.tsx @@ -28,7 +28,7 @@ export default function PageProfile(): ReactElement { const pathAccount = router.query.account as string - // Path has ETH addreess + // Path has ETH address if (web3.utils.isAddress(pathAccount)) { const finalAccountId = pathAccount || accountId setFinalAccountId(finalAccountId) @@ -40,6 +40,11 @@ export default function PageProfile(): ReactElement { // Path has ENS name setFinalAccountEns(pathAccount) const resolvedAccountId = await getEnsAddress(pathAccount) + if ( + !resolvedAccountId || + resolvedAccountId === '0x0000000000000000000000000000000000000000' + ) + return setFinalAccountId(resolvedAccountId) } } From 228ff19056cc342d4181c5bb0f04883eaedde188 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Fri, 23 Sep 2022 10:05:52 +0100 Subject: [PATCH 4/5] tweak sanitizeUrl() (#1703) * tweak sanitizeUrl() * add test --- src/@utils/url.test.ts | 9 +++++++++ src/@utils/url.ts | 9 ++------- 2 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 src/@utils/url.test.ts diff --git a/src/@utils/url.test.ts b/src/@utils/url.test.ts new file mode 100644 index 000000000..20afffdb4 --- /dev/null +++ b/src/@utils/url.test.ts @@ -0,0 +1,9 @@ +import { sanitizeUrl } from './url' + +describe('@utils/url', () => { + test('sanitizeUrl', () => { + expect(sanitizeUrl('http://example.com')).toBe('http://example.com') + expect(sanitizeUrl('https://example.com')).toBe('https://example.com') + expect(sanitizeUrl('ftp://example.com')).toBe('about:blank') + }) +}) diff --git a/src/@utils/url.ts b/src/@utils/url.ts index 5fbfe5f43..0ef9ea781 100644 --- a/src/@utils/url.ts +++ b/src/@utils/url.ts @@ -1,10 +1,5 @@ export function sanitizeUrl(url: string) { const u = decodeURI(url).trim().toLowerCase() - if ( - u.startsWith('javascript:') || - u.startsWith('data:') || - u.startsWith('vbscript:') - ) - return 'about:blank' - return url + const isAllowedUrlScheme = u.startsWith('http://') || u.startsWith('https://') + return isAllowedUrlScheme ? url : 'about:blank' } From e9ff108ea3c64d3c4dfc9cad69924a76027509f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Sep 2022 13:59:13 +0100 Subject: [PATCH 5/5] Bump next from 12.1.6 to 12.3.1 (#1698) * Bump next from 12.1.6 to 12.3.1 Bumps [next](https://github.com/vercel/next.js) from 12.1.6 to 12.3.1. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v12.1.6...v12.3.1) --- updated-dependencies: - dependency-name: next dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * fix test runs Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Matthias Kretschmann --- .jest/jest.config.js | 2 +- package-lock.json | 325 +++++++++++++++++++++++++------------------ package.json | 2 +- 3 files changed, 188 insertions(+), 141 deletions(-) diff --git a/.jest/jest.config.js b/.jest/jest.config.js index 1facc2912..0e3dc230c 100644 --- a/.jest/jest.config.js +++ b/.jest/jest.config.js @@ -14,7 +14,7 @@ const customJestConfig = { moduleDirectories: ['node_modules', '/src'], testEnvironment: 'jest-environment-jsdom', moduleNameMapper: { - '\\.svg': '/.jest/__mocks__/svgrMock.tsx', + '^.+\\.(svg)$': '/.jest/__mocks__/svgrMock.tsx', // '^@/components/(.*)$': '/components/$1', '@shared(.*)$': '/src/components/@shared/$1', '@hooks/(.*)$': '/src/@hooks/$1', diff --git a/package-lock.json b/package-lock.json index 5f97423ca..a071dd196 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "lodash.debounce": "^4.0.8", "lodash.omit": "^4.5.0", "myetherwallet-blockies": "^0.1.1", - "next": "12.1.6", + "next": "12.3.1", "query-string": "^7.1.1", "react": "^18.2.0", "react-clipboard.js": "^2.0.16", @@ -4111,14 +4111,14 @@ "dev": true }, "node_modules/@next/env": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.6.tgz", - "integrity": "sha512-Te/OBDXFSodPU6jlXYPAXpmZr/AkG6DCATAxttQxqOWaq6eDFX25Db3dK0120GZrSZmv4QCe9KsZmJKDbWs4OA==" + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.1.tgz", + "integrity": "sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==" }, "node_modules/@next/swc-android-arm-eabi": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.6.tgz", - "integrity": "sha512-BxBr3QAAAXWgk/K7EedvzxJr2dE014mghBSA9iOEAv0bMgF+MRq4PoASjuHi15M2zfowpcRG8XQhMFtxftCleQ==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.1.tgz", + "integrity": "sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ==", "cpu": [ "arm" ], @@ -4131,9 +4131,9 @@ } }, "node_modules/@next/swc-android-arm64": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.6.tgz", - "integrity": "sha512-EboEk3ROYY7U6WA2RrMt/cXXMokUTXXfnxe2+CU+DOahvbrO8QSWhlBl9I9ZbFzJx28AGB9Yo3oQHCvph/4Lew==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.1.tgz", + "integrity": "sha512-CmgU2ZNyBP0rkugOOqLnjl3+eRpXBzB/I2sjwcGZ7/Z6RcUJXK5Evz+N0ucOxqE4cZ3gkTeXtSzRrMK2mGYV8Q==", "cpu": [ "arm64" ], @@ -4146,9 +4146,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.6.tgz", - "integrity": "sha512-P0EXU12BMSdNj1F7vdkP/VrYDuCNwBExtRPDYawgSUakzi6qP0iKJpya2BuLvNzXx+XPU49GFuDC5X+SvY0mOw==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.1.tgz", + "integrity": "sha512-hT/EBGNcu0ITiuWDYU9ur57Oa4LybD5DOQp4f22T6zLfpoBMfBibPtR8XktXmOyFHrL/6FC2p9ojdLZhWhvBHg==", "cpu": [ "arm64" ], @@ -4161,9 +4161,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.6.tgz", - "integrity": "sha512-9FptMnbgHJK3dRDzfTpexs9S2hGpzOQxSQbe8omz6Pcl7rnEp9x4uSEKY51ho85JCjL4d0tDLBcXEJZKKLzxNg==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.1.tgz", + "integrity": "sha512-9S6EVueCVCyGf2vuiLiGEHZCJcPAxglyckTZcEwLdJwozLqN0gtS0Eq0bQlGS3dH49Py/rQYpZ3KVWZ9BUf/WA==", "cpu": [ "x64" ], @@ -4175,10 +4175,25 @@ "node": ">= 10" } }, + "node_modules/@next/swc-freebsd-x64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.1.tgz", + "integrity": "sha512-qcuUQkaBZWqzM0F1N4AkAh88lLzzpfE6ImOcI1P6YeyJSsBmpBIV8o70zV+Wxpc26yV9vpzb+e5gCyxNjKJg5Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@next/swc-linux-arm-gnueabihf": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.6.tgz", - "integrity": "sha512-PvfEa1RR55dsik/IDkCKSFkk6ODNGJqPY3ysVUZqmnWMDSuqFtf7BPWHFa/53znpvVB5XaJ5Z1/6aR5CTIqxPw==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.1.tgz", + "integrity": "sha512-diL9MSYrEI5nY2wc/h/DBewEDUzr/DqBjIgHJ3RUNtETAOB3spMNHvJk2XKUDjnQuluLmFMloet9tpEqU2TT9w==", "cpu": [ "arm" ], @@ -4191,9 +4206,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.6.tgz", - "integrity": "sha512-53QOvX1jBbC2ctnmWHyRhMajGq7QZfl974WYlwclXarVV418X7ed7o/EzGY+YVAEKzIVaAB9JFFWGXn8WWo0gQ==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.1.tgz", + "integrity": "sha512-o/xB2nztoaC7jnXU3Q36vGgOolJpsGG8ETNjxM1VAPxRwM7FyGCPHOMk1XavG88QZSQf+1r+POBW0tLxQOJ9DQ==", "cpu": [ "arm64" ], @@ -4206,9 +4221,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.6.tgz", - "integrity": "sha512-CMWAkYqfGdQCS+uuMA1A2UhOfcUYeoqnTW7msLr2RyYAys15pD960hlDfq7QAi8BCAKk0sQ2rjsl0iqMyziohQ==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.1.tgz", + "integrity": "sha512-2WEasRxJzgAmP43glFNhADpe8zB7kJofhEAVNbDJZANp+H4+wq+/cW1CdDi8DqjkShPEA6/ejJw+xnEyDID2jg==", "cpu": [ "arm64" ], @@ -4221,9 +4236,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.6.tgz", - "integrity": "sha512-AC7jE4Fxpn0s3ujngClIDTiEM/CQiB2N2vkcyWWn6734AmGT03Duq6RYtPMymFobDdAtZGFZd5nR95WjPzbZAQ==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.1.tgz", + "integrity": "sha512-JWEaMyvNrXuM3dyy9Pp5cFPuSSvG82+yABqsWugjWlvfmnlnx9HOQZY23bFq3cNghy5V/t0iPb6cffzRWylgsA==", "cpu": [ "x64" ], @@ -4236,9 +4251,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.6.tgz", - "integrity": "sha512-c9Vjmi0EVk0Kou2qbrynskVarnFwfYIi+wKufR9Ad7/IKKuP6aEhOdZiIIdKsYWRtK2IWRF3h3YmdnEa2WLUag==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.1.tgz", + "integrity": "sha512-xoEWQQ71waWc4BZcOjmatuvPUXKTv6MbIFzpm4LFeCHsg2iwai0ILmNXf81rJR+L1Wb9ifEke2sQpZSPNz1Iyg==", "cpu": [ "x64" ], @@ -4251,9 +4266,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.6.tgz", - "integrity": "sha512-3UTOL/5XZSKFelM7qN0it35o3Cegm6LsyuERR3/OoqEExyj3aCk7F025b54/707HTMAnjlvQK3DzLhPu/xxO4g==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.1.tgz", + "integrity": "sha512-hswVFYQYIeGHE2JYaBVtvqmBQ1CppplQbZJS/JgrVI3x2CurNhEkmds/yqvDONfwfbttTtH4+q9Dzf/WVl3Opw==", "cpu": [ "arm64" ], @@ -4266,9 +4281,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.6.tgz", - "integrity": "sha512-8ZWoj6nCq6fI1yCzKq6oK0jE6Mxlz4MrEsRyu0TwDztWQWe7rh4XXGLAa2YVPatYcHhMcUL+fQQbqd1MsgaSDA==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.1.tgz", + "integrity": "sha512-Kny5JBehkTbKPmqulr5i+iKntO5YMP+bVM8Hf8UAmjSMVo3wehyLVc9IZkNmcbxi+vwETnQvJaT5ynYBkJ9dWA==", "cpu": [ "ia32" ], @@ -4281,9 +4296,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.6.tgz", - "integrity": "sha512-4ZEwiRuZEicXhXqmhw3+de8Z4EpOLQj/gp+D9fFWo6ii6W1kBkNNvvEx4A90ugppu+74pT1lIJnOuz3A9oQeJA==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.1.tgz", + "integrity": "sha512-W1ijvzzg+kPEX6LAc+50EYYSEo0FVu7dmTE+t+DM4iOLqgGHoW9uYSz9wCVdkXOEEMP9xhXfGpcSxsfDucyPkA==", "cpu": [ "x64" ], @@ -12498,6 +12513,14 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@swc/helpers": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz", + "integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@szmarczak/http-timer": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", @@ -31688,14 +31711,16 @@ "dev": true }, "node_modules/next": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/next/-/next-12.1.6.tgz", - "integrity": "sha512-cebwKxL3/DhNKfg9tPZDQmbRKjueqykHHbgaoG4VBRH3AHQJ2HO0dbKFiS1hPhe1/qgc2d/hFeadsbPicmLD+A==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/next/-/next-12.3.1.tgz", + "integrity": "sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==", "dependencies": { - "@next/env": "12.1.6", - "caniuse-lite": "^1.0.30001332", - "postcss": "8.4.5", - "styled-jsx": "5.0.2" + "@next/env": "12.3.1", + "@swc/helpers": "0.4.11", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.0.7", + "use-sync-external-store": "1.2.0" }, "bin": { "next": "dist/bin/next" @@ -31704,18 +31729,19 @@ "node": ">=12.22.0" }, "optionalDependencies": { - "@next/swc-android-arm-eabi": "12.1.6", - "@next/swc-android-arm64": "12.1.6", - "@next/swc-darwin-arm64": "12.1.6", - "@next/swc-darwin-x64": "12.1.6", - "@next/swc-linux-arm-gnueabihf": "12.1.6", - "@next/swc-linux-arm64-gnu": "12.1.6", - "@next/swc-linux-arm64-musl": "12.1.6", - "@next/swc-linux-x64-gnu": "12.1.6", - "@next/swc-linux-x64-musl": "12.1.6", - "@next/swc-win32-arm64-msvc": "12.1.6", - "@next/swc-win32-ia32-msvc": "12.1.6", - "@next/swc-win32-x64-msvc": "12.1.6" + "@next/swc-android-arm-eabi": "12.3.1", + "@next/swc-android-arm64": "12.3.1", + "@next/swc-darwin-arm64": "12.3.1", + "@next/swc-darwin-x64": "12.3.1", + "@next/swc-freebsd-x64": "12.3.1", + "@next/swc-linux-arm-gnueabihf": "12.3.1", + "@next/swc-linux-arm64-gnu": "12.3.1", + "@next/swc-linux-arm64-musl": "12.3.1", + "@next/swc-linux-x64-gnu": "12.3.1", + "@next/swc-linux-x64-musl": "12.3.1", + "@next/swc-win32-arm64-msvc": "12.3.1", + "@next/swc-win32-ia32-msvc": "12.3.1", + "@next/swc-win32-x64-msvc": "12.3.1" }, "peerDependencies": { "fibers": ">= 3.1.0", @@ -31747,20 +31773,26 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/next/node_modules/postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], "dependencies": { - "nanoid": "^3.1.30", + "nanoid": "^3.3.4", "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" + "source-map-js": "^1.0.2" }, "engines": { "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" } }, "node_modules/nice-try": { @@ -37845,9 +37877,9 @@ } }, "node_modules/styled-jsx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.2.tgz", - "integrity": "sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz", + "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==", "engines": { "node": ">= 12.0.0" }, @@ -39560,7 +39592,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "peer": true, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } @@ -44226,80 +44257,86 @@ } }, "@next/env": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.6.tgz", - "integrity": "sha512-Te/OBDXFSodPU6jlXYPAXpmZr/AkG6DCATAxttQxqOWaq6eDFX25Db3dK0120GZrSZmv4QCe9KsZmJKDbWs4OA==" + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.1.tgz", + "integrity": "sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==" }, "@next/swc-android-arm-eabi": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.6.tgz", - "integrity": "sha512-BxBr3QAAAXWgk/K7EedvzxJr2dE014mghBSA9iOEAv0bMgF+MRq4PoASjuHi15M2zfowpcRG8XQhMFtxftCleQ==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.1.tgz", + "integrity": "sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ==", "optional": true }, "@next/swc-android-arm64": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.6.tgz", - "integrity": "sha512-EboEk3ROYY7U6WA2RrMt/cXXMokUTXXfnxe2+CU+DOahvbrO8QSWhlBl9I9ZbFzJx28AGB9Yo3oQHCvph/4Lew==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.1.tgz", + "integrity": "sha512-CmgU2ZNyBP0rkugOOqLnjl3+eRpXBzB/I2sjwcGZ7/Z6RcUJXK5Evz+N0ucOxqE4cZ3gkTeXtSzRrMK2mGYV8Q==", "optional": true }, "@next/swc-darwin-arm64": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.6.tgz", - "integrity": "sha512-P0EXU12BMSdNj1F7vdkP/VrYDuCNwBExtRPDYawgSUakzi6qP0iKJpya2BuLvNzXx+XPU49GFuDC5X+SvY0mOw==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.1.tgz", + "integrity": "sha512-hT/EBGNcu0ITiuWDYU9ur57Oa4LybD5DOQp4f22T6zLfpoBMfBibPtR8XktXmOyFHrL/6FC2p9ojdLZhWhvBHg==", "optional": true }, "@next/swc-darwin-x64": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.6.tgz", - "integrity": "sha512-9FptMnbgHJK3dRDzfTpexs9S2hGpzOQxSQbe8omz6Pcl7rnEp9x4uSEKY51ho85JCjL4d0tDLBcXEJZKKLzxNg==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.1.tgz", + "integrity": "sha512-9S6EVueCVCyGf2vuiLiGEHZCJcPAxglyckTZcEwLdJwozLqN0gtS0Eq0bQlGS3dH49Py/rQYpZ3KVWZ9BUf/WA==", + "optional": true + }, + "@next/swc-freebsd-x64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.1.tgz", + "integrity": "sha512-qcuUQkaBZWqzM0F1N4AkAh88lLzzpfE6ImOcI1P6YeyJSsBmpBIV8o70zV+Wxpc26yV9vpzb+e5gCyxNjKJg5Q==", "optional": true }, "@next/swc-linux-arm-gnueabihf": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.6.tgz", - "integrity": "sha512-PvfEa1RR55dsik/IDkCKSFkk6ODNGJqPY3ysVUZqmnWMDSuqFtf7BPWHFa/53znpvVB5XaJ5Z1/6aR5CTIqxPw==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.1.tgz", + "integrity": "sha512-diL9MSYrEI5nY2wc/h/DBewEDUzr/DqBjIgHJ3RUNtETAOB3spMNHvJk2XKUDjnQuluLmFMloet9tpEqU2TT9w==", "optional": true }, "@next/swc-linux-arm64-gnu": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.6.tgz", - "integrity": "sha512-53QOvX1jBbC2ctnmWHyRhMajGq7QZfl974WYlwclXarVV418X7ed7o/EzGY+YVAEKzIVaAB9JFFWGXn8WWo0gQ==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.1.tgz", + "integrity": "sha512-o/xB2nztoaC7jnXU3Q36vGgOolJpsGG8ETNjxM1VAPxRwM7FyGCPHOMk1XavG88QZSQf+1r+POBW0tLxQOJ9DQ==", "optional": true }, "@next/swc-linux-arm64-musl": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.6.tgz", - "integrity": "sha512-CMWAkYqfGdQCS+uuMA1A2UhOfcUYeoqnTW7msLr2RyYAys15pD960hlDfq7QAi8BCAKk0sQ2rjsl0iqMyziohQ==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.1.tgz", + "integrity": "sha512-2WEasRxJzgAmP43glFNhADpe8zB7kJofhEAVNbDJZANp+H4+wq+/cW1CdDi8DqjkShPEA6/ejJw+xnEyDID2jg==", "optional": true }, "@next/swc-linux-x64-gnu": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.6.tgz", - "integrity": "sha512-AC7jE4Fxpn0s3ujngClIDTiEM/CQiB2N2vkcyWWn6734AmGT03Duq6RYtPMymFobDdAtZGFZd5nR95WjPzbZAQ==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.1.tgz", + "integrity": "sha512-JWEaMyvNrXuM3dyy9Pp5cFPuSSvG82+yABqsWugjWlvfmnlnx9HOQZY23bFq3cNghy5V/t0iPb6cffzRWylgsA==", "optional": true }, "@next/swc-linux-x64-musl": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.6.tgz", - "integrity": "sha512-c9Vjmi0EVk0Kou2qbrynskVarnFwfYIi+wKufR9Ad7/IKKuP6aEhOdZiIIdKsYWRtK2IWRF3h3YmdnEa2WLUag==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.1.tgz", + "integrity": "sha512-xoEWQQ71waWc4BZcOjmatuvPUXKTv6MbIFzpm4LFeCHsg2iwai0ILmNXf81rJR+L1Wb9ifEke2sQpZSPNz1Iyg==", "optional": true }, "@next/swc-win32-arm64-msvc": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.6.tgz", - "integrity": "sha512-3UTOL/5XZSKFelM7qN0it35o3Cegm6LsyuERR3/OoqEExyj3aCk7F025b54/707HTMAnjlvQK3DzLhPu/xxO4g==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.1.tgz", + "integrity": "sha512-hswVFYQYIeGHE2JYaBVtvqmBQ1CppplQbZJS/JgrVI3x2CurNhEkmds/yqvDONfwfbttTtH4+q9Dzf/WVl3Opw==", "optional": true }, "@next/swc-win32-ia32-msvc": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.6.tgz", - "integrity": "sha512-8ZWoj6nCq6fI1yCzKq6oK0jE6Mxlz4MrEsRyu0TwDztWQWe7rh4XXGLAa2YVPatYcHhMcUL+fQQbqd1MsgaSDA==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.1.tgz", + "integrity": "sha512-Kny5JBehkTbKPmqulr5i+iKntO5YMP+bVM8Hf8UAmjSMVo3wehyLVc9IZkNmcbxi+vwETnQvJaT5ynYBkJ9dWA==", "optional": true }, "@next/swc-win32-x64-msvc": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.6.tgz", - "integrity": "sha512-4ZEwiRuZEicXhXqmhw3+de8Z4EpOLQj/gp+D9fFWo6ii6W1kBkNNvvEx4A90ugppu+74pT1lIJnOuz3A9oQeJA==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.1.tgz", + "integrity": "sha512-W1ijvzzg+kPEX6LAc+50EYYSEo0FVu7dmTE+t+DM4iOLqgGHoW9uYSz9wCVdkXOEEMP9xhXfGpcSxsfDucyPkA==", "optional": true }, "@nodelib/fs.scandir": { @@ -50596,6 +50633,14 @@ "@svgr/plugin-svgo": "^6.3.1" } }, + "@swc/helpers": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz", + "integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==", + "requires": { + "tslib": "^2.4.0" + } + }, "@szmarczak/http-timer": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", @@ -65952,26 +65997,29 @@ "dev": true }, "next": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/next/-/next-12.1.6.tgz", - "integrity": "sha512-cebwKxL3/DhNKfg9tPZDQmbRKjueqykHHbgaoG4VBRH3AHQJ2HO0dbKFiS1hPhe1/qgc2d/hFeadsbPicmLD+A==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/next/-/next-12.3.1.tgz", + "integrity": "sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==", "requires": { - "@next/env": "12.1.6", - "@next/swc-android-arm-eabi": "12.1.6", - "@next/swc-android-arm64": "12.1.6", - "@next/swc-darwin-arm64": "12.1.6", - "@next/swc-darwin-x64": "12.1.6", - "@next/swc-linux-arm-gnueabihf": "12.1.6", - "@next/swc-linux-arm64-gnu": "12.1.6", - "@next/swc-linux-arm64-musl": "12.1.6", - "@next/swc-linux-x64-gnu": "12.1.6", - "@next/swc-linux-x64-musl": "12.1.6", - "@next/swc-win32-arm64-msvc": "12.1.6", - "@next/swc-win32-ia32-msvc": "12.1.6", - "@next/swc-win32-x64-msvc": "12.1.6", - "caniuse-lite": "^1.0.30001332", - "postcss": "8.4.5", - "styled-jsx": "5.0.2" + "@next/env": "12.3.1", + "@next/swc-android-arm-eabi": "12.3.1", + "@next/swc-android-arm64": "12.3.1", + "@next/swc-darwin-arm64": "12.3.1", + "@next/swc-darwin-x64": "12.3.1", + "@next/swc-freebsd-x64": "12.3.1", + "@next/swc-linux-arm-gnueabihf": "12.3.1", + "@next/swc-linux-arm64-gnu": "12.3.1", + "@next/swc-linux-arm64-musl": "12.3.1", + "@next/swc-linux-x64-gnu": "12.3.1", + "@next/swc-linux-x64-musl": "12.3.1", + "@next/swc-win32-arm64-msvc": "12.3.1", + "@next/swc-win32-ia32-msvc": "12.3.1", + "@next/swc-win32-x64-msvc": "12.3.1", + "@swc/helpers": "0.4.11", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.0.7", + "use-sync-external-store": "1.2.0" }, "dependencies": { "picocolors": { @@ -65980,13 +66028,13 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", "requires": { - "nanoid": "^3.1.30", + "nanoid": "^3.3.4", "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" + "source-map-js": "^1.0.2" } } } @@ -70753,9 +70801,9 @@ } }, "styled-jsx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.2.tgz", - "integrity": "sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz", + "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==", "requires": {} }, "sudo-prompt": { @@ -72067,7 +72115,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "peer": true, "requires": {} }, "utf-8-validate": { diff --git a/package.json b/package.json index e32d89988..1553815b1 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "lodash.debounce": "^4.0.8", "lodash.omit": "^4.5.0", "myetherwallet-blockies": "^0.1.1", - "next": "12.1.6", + "next": "12.3.1", "query-string": "^7.1.1", "react": "^18.2.0", "react-clipboard.js": "^2.0.16",