diff --git a/unlock-protocol-com/package.json b/unlock-protocol-com/package.json index 8feae07579c..23979810e7a 100644 --- a/unlock-protocol-com/package.json +++ b/unlock-protocol-com/package.json @@ -5,6 +5,7 @@ "dependencies": { "@babel/core": "7.21.5", "@headlessui/react": "1.7.18", + "@observablehq/plot": "0.6.14", "@radix-ui/react-avatar": "1.0.4", "@tanstack/react-query": "4.36.1", "@testing-library/react": "14.2.1", @@ -15,7 +16,6 @@ "@unlock-protocol/tsconfig": "workspace:./packages/tsconfig", "@unlock-protocol/ui": "workspace:./packages/ui", "@zeit/next-source-maps": "0.0.3", - "apexcharts": "3.46.0", "babel-loader": "9.1.3", "babel-plugin-require-context-hook": "1.0.0", "babel-preset-react-app": "10.0.1", @@ -32,7 +32,6 @@ "prettier": "3.0.0", "raw-loader": "4.0.2", "react": "18.2.0", - "react-apexcharts": "1.4.1", "react-dom": "18.2.0", "react-ga": "3.3.1", "react-gtm-module": "2.0.11", diff --git a/unlock-protocol-com/src/components/pages/State/index.tsx b/unlock-protocol-com/src/components/pages/State/index.tsx index 53b5ad90ea9..f492b30311e 100644 --- a/unlock-protocol-com/src/components/pages/State/index.tsx +++ b/unlock-protocol-com/src/components/pages/State/index.tsx @@ -1,153 +1,129 @@ -import { Button } from '@unlock-protocol/ui' import React, { useEffect, useState } from 'react' -import { ActiveLock, Lock, Key } from '../../icons' -import numeral from 'numeral' -import { useQuery } from '@tanstack/react-query' -import dynamic from 'next/dynamic' import { networks } from '@unlock-protocol/networks' -import { CryptoIcon } from '@unlock-protocol/crypto-icon' -import { getGNPs } from '../../../utils/apiRequest' import { getSubgraph4GNP } from 'src/hooks/useSubgraph' -import { IconBaseProps } from 'react-icons' -import { utils } from 'ethers' +import * as Plot from '@observablehq/plot' -const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }) +// sections components +import { Overview } from './sections/overview' +import { GNP } from './sections/gnp' +import { HistoricalChart } from './sections/chart' -type IOverView = { - Icon: (props: IconBaseProps) => JSX.Element - value: number - title: string - description: string +type IDailyStats = { + name: string + id: number + date: Date + activeLocks: string[] + totalKeysSold: string + totalLockDeployed: string } -type ISeries = { +type ILockStats = { name: string - data: number[] + id: number + totalKeysSold: string + totalLocksDeployed: string + activeLocks: number } -type INetworkSubgraph = { - lockStats: { - totalKeysSold: string - totalLocksDeployed: string - } - unlockDailyDatas: { - activeLocks: string[] - id: number - totalKeysSold: string - totalLockDeployed: string - }[] +type IFilter = { + period: number + selectedNetworks: string[] } -type IXaxis = { - categories: string[] +interface IViewFilter { + label: string + value: string + cumulative?: boolean } -type IGNPSum = { - name: string - gnpSum: number -} +const views = [ + { + label: 'Locks deployed', + value: 'lockDeployed', + }, + { + label: 'Locks active', + value: 'activeLocks', + }, + { + label: 'Keys', + value: 'keySold', + }, + { + label: 'Locks deployed (cumulative)', + value: 'lockDeployed', + cumulative: true, + }, + { + label: 'Keys (cumulative)', + value: 'keySold', + cumulative: true, + }, +] -const filters = ['7D', '1M', '1Y', 'All'] +function ViewFilter({ + viewFilter, + setViewFilter, +}: { + viewFilter: IViewFilter + setViewFilter: (value: IViewFilter) => void +}) { + return ( +
+ {views.map((view, index) => ( +
setViewFilter(view)} + key={index} + > +

+ {view.label} +

+
+ ))} +
+ ) +} -function RenderChart({ series, xaxis }: { series: any; xaxis?: any }) { - if (!series || series.length === 0) { - return null - } +const timeFilters = [ + { label: '1 Month', period: 30 }, + { label: '6 Months', period: 180 }, + { label: '1 Year', period: 365 }, + { label: 'ALL', period: 1000 }, +] - const chartOptions = { - options: { - chart: { zoom: { enabled: false } }, - stroke: { - curve: 'smooth' as 'smooth' | 'straight' | 'stepline', - width: 3, - }, - dataLabels: { - enabled: false, - }, - markers: { - size: 0, - hover: { - sizeOffset: 6, - }, - }, - xaxis, - yaxis: [ - { - opposite: false, - title: { - text: 'Keys', - }, - min: Math.max( - 0, - Math.min(...series[0].data) - - 0.1 * - (Math.max(...series[0].data) - Math.min(...series[0].data)) - - 1 - ), - labels: { - formatter: function (val, index) { - return val.toFixed(0) - }, - }, - }, - { - show: false, - }, - { - opposite: true, - title: { - text: 'Locks', - }, - min: Math.max( - 0, - Math.min(...series[2].data) - - 0.1 * - (Math.max(...series[2].data) - Math.min(...series[2].data)) - - 1 - ), - labels: { - formatter: function (val, index) { - return val.toFixed(0) - }, - }, - }, - ], - tooltip: { - y: [ - { - title: { - formatter: (val) => val, - }, - }, - { - title: { - formatter: (val) => val, - }, - }, - { - title: { - formatter: (val) => val, - }, - }, - ], - }, - grid: { - borderColor: '#f1f1f1', - xaxis: { lines: { show: true } }, - yaxis: { lines: { show: true } }, - }, - }, - } +const supportedNetworks = Object.keys(networks) + .map((id) => networks[id]) + .filter(({ isTestNetwork, id }) => !isTestNetwork && id) + .map(({ name, chain, id, subgraph }) => ({ + name, + chain, + id, + subgraphURI: subgraph.endpoint, + })) +function isWithin(date, days) { + const toTest = new Date(date) + const now = new Date() + const fewDaysAgo = new Date() + fewDaysAgo.setDate(now.getDate() - days) return ( -
- -
+ fewDaysAgo.getTime() <= toTest.getTime() && toTest.getTime() < now.getTime() + ) +} + +function filterData({ dailyStats, filter }) { + const { period, selectedNetworks } = filter + return dailyStats.filter( + ({ chain, date }) => + isWithin(date, period) && + (!selectedNetworks.length ? true : selectedNetworks.includes(chain)) ) } @@ -155,23 +131,25 @@ function DateFilter({ filter, setFilter, }: { - filter: string - setFilter: (value: string) => void + filter: IFilter + setFilter: (value: IFilter) => void }) { return ( -
- {filters.map((item, index) => ( +
+ {timeFilters.map(({ label, period }, index) => (
setFilter(item)} + onClick={() => setFilter({ ...filter, period })} key={index} >

- {item} + {label}

))} @@ -179,421 +157,159 @@ function DateFilter({ ) } -function CalcActiveLocksCount(graphData: any[]) { - const currentDay = Math.round(new Date().getTime() / 86400000) - const unlockDailyDatas = graphData - .map((item) => item.data.unlockDailyDatas) - .flatMap((data) => data) - const activeLockList = unlockDailyDatas - .filter( - (dailyData) => - dailyData.id > currentDay - 30 && dailyData.id <= currentDay +function NetworkRadioPicker({ + filter, + setFilter, +}: { + filter: IFilter + setFilter: (value: IFilter) => void +}) { + const handleOnChange = (selectedChain) => { + const updatedSelectedNetworks = filter.selectedNetworks.includes( + selectedChain ) - .map((item) => item.activeLocks) - .flatMap((data) => data) - return [...new Set(activeLockList)].length -} + ? filter.selectedNetworks.filter((chain) => chain !== selectedChain) + : [...filter.selectedNetworks, selectedChain] + setFilter({ ...filter, selectedNetworks: updatedSelectedNetworks }) + } -function CalcRenderData( - graphData: INetworkSubgraph, - timestampArray: number[], - flag: 0 | 1 | 2, - filter: string -) { - return timestampArray.map((dayId) => { - const dayDatas = graphData.unlockDailyDatas.filter( - (item) => item.id >= dayId - 1 && item.id < dayId - ) - if (flag === 0) - return dayDatas.reduce((x, y) => x + Number(y.totalKeysSold), 0) - if (flag === 1) { - const lastMonthActiveLocks = graphData.unlockDailyDatas - .filter((item) => item.id > dayId - 30 && item.id <= dayId) - .map((item) => item.activeLocks) - .flatMap((lock) => lock) - return [...new Set(lastMonthActiveLocks)].length - } - if (flag === 2) - return dayDatas.reduce((x, y) => x + Number(y.totalLockDeployed), 0) + const color = Plot.scale({ + color: { + scheme: 'Tableau10', + domain: supportedNetworks.map((_, i) => i), + }, }) + + return ( +
+ {supportedNetworks.map(({ name, chain }, index) => ( + + ))} +
+ ) } export function State() { const currentDay = Math.round(new Date().getTime() / 86400000) - const [subgraphData, setSubgraphData] = useState([]) - const [filter, setFilter] = useState('7D') - const [isLoading, setIsLoading] = useState(true) - const [gnpValues, setGNPValues] = useState([]) - const [overViewData, setOverViewData] = useState([]) - const [selectedNetwork, setSelectedNetwork] = useState('ALL') - const [selectedNetworkSubgraphData, setSelectedNetworkSubgraphData] = - useState(undefined) - const [series, setSeries] = useState([]) - const [xaxis, setXaxis] = useState(undefined) - const [gnpTotalValueByNetwork, setGnpTotalValueByNetwork] = useState< - IGNPSum[] - >([]) - const [gnpPByNetworks, setGNPPByNetworks] = useState([]) - - useEffect(() => { - if (selectedNetworkSubgraphData) { - let xAxisLabels - let timestampArray - switch (filter) { - case '7D': { - xAxisLabels = [...Array(7).keys()].reverse().map((key) => { - const cur = new Date() - return new Date(cur.setDate(cur.getDate() - key)).toLocaleString( - 'default', - { dateStyle: 'short' } - ) - }) - timestampArray = [...Array(7).keys()].reverse().map((key) => { - const cur = new Date() - return Math.round(cur.setDate(cur.getDate() - key) / 86400000) - }) - break - } - case '1M': { - xAxisLabels = [...Array(30).keys()].reverse().map((key) => { - const cur = new Date() - return new Date(cur.setDate(cur.getDate() - key)).toLocaleString( - 'default', - { dateStyle: 'short' } - ) - }) - timestampArray = [...Array(30).keys()].reverse().map((key) => { - const cur = new Date() - return Math.round(cur.setDate(cur.getDate() - key) / 86400000) - }) - break - } - case '1Y': { - xAxisLabels = [...Array(12).keys()].reverse().map((key) => { - const cur = new Date() - return new Date(cur.setMonth(cur.getMonth() - key)).toLocaleString( - 'default', - { dateStyle: 'short' } - ) - }) - timestampArray = [...Array(12).keys()].reverse().map((key) => { - const cur = new Date() - return Math.round(cur.setMonth(cur.getMonth() - key) / 86400000) - }) - break - } - case 'All': { - xAxisLabels = [...Array(36).keys()].reverse().map((key) => { - const cur = new Date() - return new Date(cur.setMonth(cur.getMonth() - key)).toLocaleString( - 'default', - { dateStyle: 'short' } - ) - }) - timestampArray = [...Array(36).keys()].reverse().map((key) => { - const cur = new Date() - return Math.round(cur.setMonth(cur.getMonth() - key) / 86400000) - }) - break - } - } - - setXaxis({ - categories: xAxisLabels, - }) - setSeries([ - { - name: 'Keys (Memberships) Minted', - data: CalcRenderData( - selectedNetworkSubgraphData, - timestampArray, - 0, - filter - ), - }, - { - name: 'Active Locks', - data: CalcRenderData( - selectedNetworkSubgraphData, - timestampArray, - 1, - filter - ), - }, - { - name: 'Locks Deployed', - data: CalcRenderData( - selectedNetworkSubgraphData, - timestampArray, - 2, - filter - ), - }, - ]) - } - }, [selectedNetworkSubgraphData, filter]) + const [dailyStats, setDailyStats] = useState([]) + const [lockStats, setLockStats] = useState([]) + const [filter, setFilter] = useState({ + period: 1000, + selectedNetworks: supportedNetworks.map(({ chain }) => chain), + }) + const [viewFilter, setViewFilter] = useState(views[1]) + const [filteredData, setFilteredData] = useState([]) + // get data from all subgraphs useEffect(() => { const run = async () => { - const values = await getGNPs() - values.sort((a, b) => { - if (a.total < b.total) return 1 - if (a.total > b.total) return -1 - return 0 - }) - setGNPValues(values) - setIsLoading(false) - } - run() - }, []) + const allData = await Promise.all( + supportedNetworks.map(async ({ name, id, chain, subgraphURI }) => { + const data = await getSubgraph4GNP(subgraphURI, currentDay - 1000) + return { + name, + id, + data, + chain, + } + }) + ) - useEffect(() => { - const run = async () => { - if (selectedNetwork === 'ALL') { - const subgraphData = await Promise.all( - Object.keys(networks).map(async (key) => { - if (!networks[key].isTestNetwork) { - const { data } = await getSubgraph4GNP( - networks[key].subgraph.endpoint, - currentDay - 1030 // why? - ) - return data - } - }) - ) - setSelectedNetworkSubgraphData( - subgraphData - .filter((item) => item) - .reduce( - (a, b) => ({ - lockStats: { - totalKeysSold: - a.lockStats.totalKeysSold + - parseInt(b.lockStats.totalKeysSold), - totalLocksDeployed: - a.lockStats.totalLocksDeployed + - parseInt(b.lockStats.totalLocksDeployed), - }, - unlockDailyDatas: [ - ...a.unlockDailyDatas, - ...b.unlockDailyDatas, - ], - }), + const dailyStats = allData.reduce( + (obj, { data: { unlockDailyDatas }, name, id, chain }) => { + unlockDailyDatas.forEach(({ date, ...datum }, i) => { + obj = [ + ...obj, { - lockStats: { totalKeysSold: 0, totalLocksDeployed: 0 }, - unlockDailyDatas: [], - } - ) - ) - } else { - const { data } = await getSubgraph4GNP( - networks[selectedNetwork].subgraph.endpoint, - currentDay - 1030 // why? - ) - setSelectedNetworkSubgraphData(data) - } - } - run() - }, [selectedNetwork, filter, subgraphData, currentDay]) - - useEffect(() => { - const gnpPercentageByNetworks = subgraphData.map((networkData) => { - const sumOfGNP = parseFloat( - utils.formatUnits( - BigInt( - networkData.data.unlockDailyDatas - .filter( - (item) => - item.id >= - currentDay - - (filter === '7D' - ? 8 - : filter === '1M' - ? 31 - : filter === '1Y' - ? 200 - : 10000) && item.id <= currentDay - ) - .reduce((pv, b) => pv + parseInt(b.grossNetworkProduct), 0) - ), - '18' - ) + date, + name, + chain, + id, + // compute locks per day + lockDeployed: i + ? datum.totalLockDeployed - + unlockDailyDatas[i - 1].totalLockDeployed + : 0, + // compute keys per day + keySold: i + ? datum.totalKeysSold - unlockDailyDatas[i - 1].totalKeysSold + : 0, + ...datum, + }, + ] + }) + return obj + }, + [] ) - return { - name: networkData.name, - gnpPercentage: - sumOfGNP / - gnpTotalValueByNetwork.find((item) => item.name === networkData.name) - ?.gnpSum, - } - }) - setGNPPByNetworks(gnpPercentageByNetworks) - }, [filter, currentDay, subgraphData, gnpTotalValueByNetwork]) + setDailyStats(dailyStats) - useEffect(() => { - const run = async () => { - const subgraphData = await Promise.all( - Object.keys(networks).map(async (key) => { - if (!networks[key].isTestNetwork) { - const { data } = await getSubgraph4GNP( - networks[key].subgraph.endpoint, - currentDay - 1030 // why? - ) - return { name: networks[key].name, data } - } + const lockStats = allData.map( + ({ data: { lockStats, unlockDailyDatas }, name, id }) => ({ + name, + id, + ...lockStats, + activeLocks: unlockDailyDatas + .filter(({ date }) => isWithin(date, 30)) // last 30 days + .map(({ activeLocks }) => activeLocks) + .reduce((pv, a) => pv + a, 0), }) ) - setSubgraphData(subgraphData.filter((item) => item && item.data)) + setLockStats(lockStats) } run() }, [currentDay]) + // filter data properly useEffect(() => { - if (subgraphData !== undefined && subgraphData.length > 0) { - const overview_contents: IOverView[] = [ - { - value: subgraphData.reduce( - (pv, b) => pv + parseInt(b?.data?.lockStats?.totalLocksDeployed), - 0 - ), - title: 'Total of Locks Deployed', - description: 'All Time, production networks only', - Icon: Lock, - }, - { - value: subgraphData.reduce( - (pv, b) => pv + parseInt(b?.data?.lockStats?.totalKeysSold), - 0 - ), - title: 'Total of Keys Sold', - description: 'All Time, production networks only', - Icon: Key, - }, - { - value: CalcActiveLocksCount(subgraphData), - title: 'Active Locks', - description: 'Minted at least 1 membership in the last 30 days', - Icon: ActiveLock, - }, - ] - const gnpDataByNetworks = subgraphData.map((networkData) => ({ - name: networkData.name, - gnpSum: parseFloat( - utils.formatUnits( - BigInt( - networkData.data.unlockDailyDatas.reduce( - (pv, b) => pv + parseInt(b.grossNetworkProduct), - 0 - ) - ), - '18' - ) - ), - })) - setOverViewData(overview_contents) - setGnpTotalValueByNetwork(gnpDataByNetworks) - } - }, [subgraphData]) + setFilteredData(filterData({ filter, dailyStats })) + }, [filter, dailyStats]) return (

State of Unlock

-
-
-

Overview

-
- {overViewData && - overViewData.map( - ({ value, title, description, Icon }, index) => ( -
-

- {numeral(value).format('0,0')} -

-

- {title} -

-
- {description} - -
-
- ) - )} -
-
-
-

Activity over time

-
- - -
- -
-
-

- Gross Network Product -

- {!isLoading && ( -
- {gnpValues - .filter((item) => !item.network.isTestNetwork) - .map(({ total, network }, index) => ( -
-
-

{network.name}

-
- -
- -

- {numeral(total).format('0,0.000')}{' '} -

-

- {network.nativeCurrency.symbol} -

-
-
- ))} -
- )} -
+
+
+ +
+
+

+ Activity over time +

+
+ +
+ {filteredData.length && ( + + )} +
+
+ +
+
+

+ Gross Network Product +

+
diff --git a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx new file mode 100644 index 00000000000..66dd63d5bda --- /dev/null +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -0,0 +1,60 @@ +import React, { useRef, useEffect } from 'react' +import * as Plot from '@observablehq/plot' + +export function HistoricalChart({ + dailyStats, + filter, + supportedNetworks, + viewFilter, +}) { + const ref = useRef() + useEffect(() => { + const barChart = Plot.plot({ + width: 1200, + height: 500, + marginLeft: 50, + marginTop: 50, + marginBottom: 50, + y: { + grid: true, + axis: 'left', + label: `${viewFilter.label}`, + }, + color: { + type: 'categorical', + scheme: 'Tableau10', + legend: false, + domain: supportedNetworks.map(({ name }) => name), + label: 'Networks', + }, + marks: [ + // locks deployed + Plot.rectY( + dailyStats, + Plot.binX( + { + y: 'sum', + }, + { + x: 'date', + y: viewFilter.value, + fill: 'name', + interval: filter.period <= 365 ? 'day' : 'week', + tip: 'x', + cumulative: viewFilter.cumulative, + } + ) + ), + ], + }) + + ref.current?.append(barChart) + return () => barChart.remove() + }, [dailyStats, viewFilter, filter.period, supportedNetworks]) + + return ( +
+
+
+ ) +} diff --git a/unlock-protocol-com/src/components/pages/State/sections/gnp.tsx b/unlock-protocol-com/src/components/pages/State/sections/gnp.tsx new file mode 100644 index 00000000000..abdbeb5c3eb --- /dev/null +++ b/unlock-protocol-com/src/components/pages/State/sections/gnp.tsx @@ -0,0 +1,58 @@ +import React, { useEffect, useState } from 'react' + +import numeral from 'numeral' +import { CryptoIcon } from '@unlock-protocol/crypto-icon' +import { getGNPs } from '../../../../utils/apiRequest' + +interface IGNP { + chain: string + isTestNetwork: boolean + total: number + name: string + nativeCurrencySymbol: string +} + +export function GNP() { + const [gnpValues, setGNPValues] = useState([]) + + useEffect(() => { + const run = async () => { + const values = await getGNPs() + values.sort((a, b) => { + if (a.total < b.total) return 1 + if (a.total > b.total) return -1 + return 0 + }) + setGNPValues(values) + } + run() + }, []) + + return ( +
+ {gnpValues + .filter(({ isTestNetwork }) => !isTestNetwork) + .map(({ total, name, nativeCurrencySymbol }, index) => ( +
+
+

{name}

+
+ +
+ +

+ {numeral(total).format('0,0.000')}{' '} +

+

+ {nativeCurrencySymbol} +

+
+
+ ))} +
+ ) +} diff --git a/unlock-protocol-com/src/components/pages/State/sections/overview.tsx b/unlock-protocol-com/src/components/pages/State/sections/overview.tsx new file mode 100644 index 00000000000..9c2c377af39 --- /dev/null +++ b/unlock-protocol-com/src/components/pages/State/sections/overview.tsx @@ -0,0 +1,61 @@ +import React, { useEffect, useState } from 'react' +import { IconBaseProps } from 'react-icons' +import { ActiveLock, Lock, Key } from '../../../icons' +import numeral from 'numeral' + +type IOverView = { + Icon: (props: IconBaseProps) => JSX.Element + value: number + title: string + description: string +} + +export function Overview({ lockStats }) { + const [overViewData, setOverViewData] = useState([]) + + useEffect(() => { + if (lockStats !== undefined && lockStats.length > 0) { + const overview_contents: IOverView[] = [ + { + value: lockStats.reduce((pv, b) => pv + b?.totalLocksDeployed, 0), + title: 'Total of Locks Deployed', + description: 'All Time, production networks only', + Icon: Lock, + }, + { + value: lockStats.reduce((pv, b) => pv + b?.totalKeysSold, 0), + title: 'Total of Keys Sold', + description: 'All Time, production networks only', + Icon: Key, + }, + { + value: lockStats.reduce((pv, b) => pv + b?.activeLocks, 0), + title: 'Active Locks', + description: 'Minted at least 1 membership in the last 30 days', + Icon: ActiveLock, + }, + ] + setOverViewData(overview_contents) + } + }, [lockStats]) + + return ( +
+ {overViewData && + overViewData.map(({ value, title, description, Icon }, index) => ( +
+

+ {numeral(value).format('0,0')} +

+

+ {title} +

+
+ {description} + +
+
+ ))} +
+ ) +} diff --git a/unlock-protocol-com/src/hooks/useSubgraph.ts b/unlock-protocol-com/src/hooks/useSubgraph.ts index 93a3b75b3df..b57bb64b327 100644 --- a/unlock-protocol-com/src/hooks/useSubgraph.ts +++ b/unlock-protocol-com/src/hooks/useSubgraph.ts @@ -22,49 +22,35 @@ const subgraphConfig = (upToDate: number) => `{ } }` +const parseLockStats = ({ totalKeysSold, totalLocksDeployed }) => ({ + totalKeysSold: parseInt(totalKeysSold), + totalLocksDeployed: parseInt(totalLocksDeployed), +}) + +const parseDailyData = ({ + id, + totalLockDeployed, + totalKeysSold, + activeLocks, + grossNetworkProduct, +}) => ({ + date: new Date(parseInt(id) * 86400000), + totalLockDeployed: parseInt(totalLockDeployed), + totalKeysSold: parseInt(totalKeysSold), + activeLocks: activeLocks.length, + grossNetworkProduct, +}) + export async function getSubgraph4GNP(subgraphUrl: string, upToDate?: number) { - const { data } = await subgraphApi.post(`${subgraphUrl}`, { + const { + data: { data }, + } = await subgraphApi.post(`${subgraphUrl}`, { query: subgraphConfig(upToDate), }) - if (data?.data?.unlockDailyDatas) { - // Add missing datapoints (if no event was triggered on a day, then it's not in the list!) - const lastDayData = - data?.data?.unlockDailyDatas[data?.data?.unlockDailyDatas.length - 1] - const lastDay = parseInt(lastDayData.id, 10) - const today = Math.floor(new Date().getTime() / (1000 * 24 * 60 * 60)) - if (lastDay < today) { - data?.data?.unlockDailyDatas.push({ - id: today.toString(), - totalLockDeployed: lastDayData.totalLockDeployed, - totalKeysSold: lastDayData.totalKeysSold, - activeLocks: lastDayData.activeLocks, - grossNetworkProduct: lastDayData.grossNetworkProduct, - }) - } - data?.data?.unlockDailyDatas - .sort((a, b) => parseInt(a.id, 10) - parseInt(b.id, 10)) - .forEach((day, i) => { - if (i > 0) { - const dayNumber = parseInt(day.id, 10) - const dayBefore = parseInt(data.data.unlockDailyDatas[i - 1].id, 10) - for (let j = dayBefore + 1; j < dayNumber; j++) { - data.data.unlockDailyDatas.push({ - id: j.toString(), - totalLockDeployed: - data.data.unlockDailyDatas[i - 1].totalLockDeployed, - totalKeysSold: data.data.unlockDailyDatas[i - 1].totalKeysSold, - activeLocks: [], - grossNetworkProduct: - data.data.unlockDailyDatas[i - 1].grossNetworkProduct, - }) - } - } - }) - data.data.unlockDailyDatas = data?.data?.unlockDailyDatas.sort( - (a, b) => parseInt(a.id, 10) - parseInt(b.id, 10) - ) + return { + ...data, + unlockDailyDatas: data.unlockDailyDatas.map(parseDailyData), + lockStats: parseLockStats(data.lockStats), } - - return data } diff --git a/unlock-protocol-com/src/utils/apiRequest.ts b/unlock-protocol-com/src/utils/apiRequest.ts index a81575bff57..2c6aabcda9c 100644 --- a/unlock-protocol-com/src/utils/apiRequest.ts +++ b/unlock-protocol-com/src/utils/apiRequest.ts @@ -2,19 +2,25 @@ import { ethers } from 'ethers' import { networks } from '@unlock-protocol/networks' -async function getGdpForNetwork(provider, network) { +async function getGdpForNetwork({ + provider, + unlockAddress, + previousDeploys, + name, + id, +}) { const abi = ['function grossNetworkProduct() constant view returns (uint256)'] - const contract = new ethers.Contract(network.unlockAddress, abi, provider) + const contract = new ethers.Contract(unlockAddress, abi, provider) let gnp = await contract.grossNetworkProduct() - if (network.id === 1) { + if (id === 1) { // temp fix until we fix GNP on mainnet! gnp = 0 } - if (network.previousDeploys) { - for (let i = 0; i < network.previousDeploys.length; i++) { + if (previousDeploys) { + for (let i = 0; i < previousDeploys.length; i++) { try { const previousContract = new ethers.Contract( - network.previousDeploys[i].unlockAddress, + previousDeploys[i].unlockAddress, abi, provider ) @@ -22,7 +28,7 @@ async function getGdpForNetwork(provider, network) { gnp = previousGnp.add(gnp) } catch (error) { console.error( - `Error retrieving GNP for ${network.name} at ${network.previousDeploys[i].name}`, + `Error retrieving GNP for ${name} at ${previousDeploys[i].name}`, error ) } @@ -35,16 +41,34 @@ export async function getGNPs() { const values = await Promise.all( Object.keys(networks).map(async (id) => { try { - const network = networks[id] - if (!network.unlockAddress) { + const { + unlockAddress, + chain, + name, + provider: providerUrl, + previousDeploys, + isTestNetwork, + nativeCurrency, + } = networks[id] + if (!unlockAddress) { return null } - const provider = new ethers.providers.JsonRpcBatchProvider( - network.provider - ) - const gdp = await getGdpForNetwork(provider, network) + const provider = new ethers.providers.JsonRpcBatchProvider(providerUrl) + const gdp = await getGdpForNetwork({ + provider, + unlockAddress, + previousDeploys, + name, + id, + }) const total = parseFloat(ethers.utils.formatUnits(gdp, '18')) - return { total, network } + return { + total, + chain, + name, + isTestNetwork, + nativeCurrencySymbol: nativeCurrency.symbol, + } } catch (error) { console.error('Error retrieving data for', id) console.error(error) diff --git a/yarn.lock b/yarn.lock index 19f450c1b24..1f71d92d9d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11493,6 +11493,17 @@ __metadata: languageName: node linkType: hard +"@observablehq/plot@npm:0.6.14": + version: 0.6.14 + resolution: "@observablehq/plot@npm:0.6.14" + dependencies: + d3: "npm:^7.9.0" + interval-tree-1d: "npm:^1.0.0" + isoformat: "npm:^0.2.0" + checksum: 10/bb54b1e33b3c269f8cb8818dc8ec35fb7c404cff7587bc0e59aaf6cff6712dbe9d18325f683a7a1d570724b38404adeba87ba6410a3e5ce31bbf52cf4827b08e + languageName: node + linkType: hard + "@oclif/core@npm:2.8.6": version: 2.8.6 resolution: "@oclif/core@npm:2.8.6" @@ -20394,6 +20405,7 @@ __metadata: dependencies: "@babel/core": "npm:7.21.5" "@headlessui/react": "npm:1.7.18" + "@observablehq/plot": "npm:0.6.14" "@radix-ui/react-avatar": "npm:1.0.4" "@tanstack/react-query": "npm:4.36.1" "@testing-library/react": "npm:14.2.1" @@ -20404,7 +20416,6 @@ __metadata: "@unlock-protocol/tsconfig": "workspace:./packages/tsconfig" "@unlock-protocol/ui": "workspace:./packages/ui" "@zeit/next-source-maps": "npm:0.0.3" - apexcharts: "npm:3.46.0" autoprefixer: "npm:10.4.18" babel-loader: "npm:9.1.3" babel-plugin-require-context-hook: "npm:1.0.0" @@ -20427,7 +20438,6 @@ __metadata: prettier: "npm:3.0.0" raw-loader: "npm:4.0.2" react: "npm:18.2.0" - react-apexcharts: "npm:1.4.1" react-dom: "npm:18.2.0" react-ga: "npm:3.3.1" react-gtm-module: "npm:2.0.11" @@ -21719,13 +21729,6 @@ __metadata: languageName: node linkType: hard -"@yr/monotone-cubic-spline@npm:^1.0.3": - version: 1.0.3 - resolution: "@yr/monotone-cubic-spline@npm:1.0.3" - checksum: 10/f946b0a1aa3e976126b8ee07d4fd430f3b956f195b16f2497ab4510d8463b777d6dd53c49e4f86c6c506de7d8420c05fa566a7454548afde804ffd7fb21ff8d4 - languageName: node - linkType: hard - "@zeit/next-source-maps@npm:0.0.3": version: 0.0.3 resolution: "@zeit/next-source-maps@npm:0.0.3" @@ -22405,21 +22408,6 @@ __metadata: languageName: node linkType: hard -"apexcharts@npm:3.46.0": - version: 3.46.0 - resolution: "apexcharts@npm:3.46.0" - dependencies: - "@yr/monotone-cubic-spline": "npm:^1.0.3" - svg.draggable.js: "npm:^2.2.2" - svg.easing.js: "npm:^2.0.0" - svg.filter.js: "npm:^2.0.2" - svg.pathmorphing.js: "npm:^0.1.3" - svg.resize.js: "npm:^1.4.3" - svg.select.js: "npm:^3.0.1" - checksum: 10/e7ff2b05b938d8f4d7b945066c21bd2b205489bf92d22bbdf81d79788c9d7eed3c74019248ca952aaef9d1d6e4cbee08b48d70e4ce0689e3b463a56bf153d405 - languageName: node - linkType: hard - "apg-js@npm:^4.1.1": version: 4.3.0 resolution: "apg-js@npm:4.3.0" @@ -24046,6 +24034,13 @@ __metadata: languageName: node linkType: hard +"binary-search-bounds@npm:^2.0.0": + version: 2.0.5 + resolution: "binary-search-bounds@npm:2.0.5" + checksum: 10/34a65dfb835314f01e40584083d5c8675141d6eac1523508e925298b34f7903798f5c8389aa1cb26f01fdafa86245db9837d86c82eb2d16826a57bd0d69a0852 + languageName: node + linkType: hard + "binaryen@npm:101.0.0-nightly.20210723": version: 101.0.0-nightly.20210723 resolution: "binaryen@npm:101.0.0-nightly.20210723" @@ -26267,6 +26262,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:7, commander@npm:^7.2.0": + version: 7.2.0 + resolution: "commander@npm:7.2.0" + checksum: 10/9973af10727ad4b44f26703bf3e9fdc323528660a7590efe3aa9ad5042b4584c0deed84ba443f61c9d6f02dade54a5a5d3c95e306a1e1630f8374ae6db16c06d + languageName: node + linkType: hard + "commander@npm:8.3.0, commander@npm:^8.3.0": version: 8.3.0 resolution: "commander@npm:8.3.0" @@ -26295,13 +26297,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:^7.2.0": - version: 7.2.0 - resolution: "commander@npm:7.2.0" - checksum: 10/9973af10727ad4b44f26703bf3e9fdc323528660a7590efe3aa9ad5042b4584c0deed84ba443f61c9d6f02dade54a5a5d3c95e306a1e1630f8374ae6db16c06d - languageName: node - linkType: hard - "commander@npm:^9.0.0, commander@npm:^9.3.0, commander@npm:^9.4.0": version: 9.5.0 resolution: "commander@npm:9.5.0" @@ -27508,6 +27503,324 @@ __metadata: languageName: node linkType: hard +"d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:2.5.0 - 3, d3-array@npm:3, d3-array@npm:^3.2.0": + version: 3.2.4 + resolution: "d3-array@npm:3.2.4" + dependencies: + internmap: "npm:1 - 2" + checksum: 10/5800c467f89634776a5977f6dae3f4e127d91be80f1d07e3e6e35303f9de93e6636d014b234838eea620f7469688d191b3f41207a30040aab750a63c97ec1d7c + languageName: node + linkType: hard + +"d3-axis@npm:3": + version: 3.0.0 + resolution: "d3-axis@npm:3.0.0" + checksum: 10/15ec43ecbd4e7b606fcda60f67a522e45576dfd6aa83dff47f3e91ef6c8448841a09cd91f630b492250dcec67c6ea64463510ead5e632ff6b827aeefae1d42ad + languageName: node + linkType: hard + +"d3-brush@npm:3": + version: 3.0.0 + resolution: "d3-brush@npm:3.0.0" + dependencies: + d3-dispatch: "npm:1 - 3" + d3-drag: "npm:2 - 3" + d3-interpolate: "npm:1 - 3" + d3-selection: "npm:3" + d3-transition: "npm:3" + checksum: 10/fa3a461b62f0f0ee6fe41f5babf45535a0a8f6d4999f675fb1dce932ee02eff72dec14c7296af31ca15998dc0141ccf5d02aa6499363f8bf2941d90688a1d644 + languageName: node + linkType: hard + +"d3-chord@npm:3": + version: 3.0.1 + resolution: "d3-chord@npm:3.0.1" + dependencies: + d3-path: "npm:1 - 3" + checksum: 10/4febcdca4fdc8ba91fc4f7545f4b6321c440150dff80c1ebef887db07bb4200395dfebede63b257393259de07f914da10842da5ab3135e1e281e33ad153e0849 + languageName: node + linkType: hard + +"d3-color@npm:1 - 3, d3-color@npm:3": + version: 3.1.0 + resolution: "d3-color@npm:3.1.0" + checksum: 10/536ba05bfd9f4fcd6fa289b5974f5c846b21d186875684637e22bf6855e6aba93e24a2eb3712985c6af3f502fbbfa03708edb72f58142f626241a8a17258e545 + languageName: node + linkType: hard + +"d3-contour@npm:4": + version: 4.0.2 + resolution: "d3-contour@npm:4.0.2" + dependencies: + d3-array: "npm:^3.2.0" + checksum: 10/0b252267e0c3c5e97d7e0c720bd35654de99f981199f7240d7dd1acfd4e2d5bf1638829f6db486452eff9c38608efa4a6ab5a0d1525131735c011ee7be3cb4ba + languageName: node + linkType: hard + +"d3-delaunay@npm:6": + version: 6.0.4 + resolution: "d3-delaunay@npm:6.0.4" + dependencies: + delaunator: "npm:5" + checksum: 10/4588e2872d4154daaf2c3f34fefe74e43b909cc460238a7b02823907ca6dd109f2c488c57c8551f1a2607fe4b44fdf24e3a190cea29bca70ef5606678dd9e2de + languageName: node + linkType: hard + +"d3-dispatch@npm:1 - 3, d3-dispatch@npm:3": + version: 3.0.1 + resolution: "d3-dispatch@npm:3.0.1" + checksum: 10/2b82f41bf4ef88c2f9033dfe32815b67e2ef1c5754a74137a74c7d44d6f0d6ecfa934ac56ed8afe358f6c1f06462e8aa42ca0a388397b5b77a42721570e80487 + languageName: node + linkType: hard + +"d3-drag@npm:2 - 3, d3-drag@npm:3": + version: 3.0.0 + resolution: "d3-drag@npm:3.0.0" + dependencies: + d3-dispatch: "npm:1 - 3" + d3-selection: "npm:3" + checksum: 10/80bc689935e5a46ee92b2d7f71e1c792279382affed9fbcf46034bff3ff7d3f50cf61a874da4bdf331037292b9e7dca5c6401a605d4bb699fdcb4e0c87e176ec + languageName: node + linkType: hard + +"d3-dsv@npm:1 - 3, d3-dsv@npm:3": + version: 3.0.1 + resolution: "d3-dsv@npm:3.0.1" + dependencies: + commander: "npm:7" + iconv-lite: "npm:0.6" + rw: "npm:1" + bin: + csv2json: bin/dsv2json.js + csv2tsv: bin/dsv2dsv.js + dsv2dsv: bin/dsv2dsv.js + dsv2json: bin/dsv2json.js + json2csv: bin/json2dsv.js + json2dsv: bin/json2dsv.js + json2tsv: bin/json2dsv.js + tsv2csv: bin/dsv2dsv.js + tsv2json: bin/dsv2json.js + checksum: 10/a628ac42a272466940f713f310db2e5246690b22035121dc1230077070c9135fb7c9b4d260f093fcadf63b0528202a1953107448a4be3a860c4f42f50d09504d + languageName: node + linkType: hard + +"d3-ease@npm:1 - 3, d3-ease@npm:3": + version: 3.0.1 + resolution: "d3-ease@npm:3.0.1" + checksum: 10/985d46e868494e9e6806fedd20bad712a50dcf98f357bf604a843a9f6bc17714a657c83dd762f183173dcde983a3570fa679b2bc40017d40b24163cdc4167796 + languageName: node + linkType: hard + +"d3-fetch@npm:3": + version: 3.0.1 + resolution: "d3-fetch@npm:3.0.1" + dependencies: + d3-dsv: "npm:1 - 3" + checksum: 10/cd35d55f8fbb1ea1e37be362a575bb0161449957133aa5b45b9891889b2aca1dc0769c240a236736e33cd823e820a0e73fb3744582307a5d26d1df7bed0ccecb + languageName: node + linkType: hard + +"d3-force@npm:3": + version: 3.0.0 + resolution: "d3-force@npm:3.0.0" + dependencies: + d3-dispatch: "npm:1 - 3" + d3-quadtree: "npm:1 - 3" + d3-timer: "npm:1 - 3" + checksum: 10/85945f8d444d78567009518f0ab54c0f0c8873eb8eb9a2ff0ab667b0f81b419e101a411415d4a2c752547ec7143f89675e8c33b8f111e55e5579a04cb7f4591c + languageName: node + linkType: hard + +"d3-format@npm:1 - 3, d3-format@npm:3": + version: 3.1.0 + resolution: "d3-format@npm:3.1.0" + checksum: 10/a0fe23d2575f738027a3db0ce57160e5a473ccf24808c1ed46d45ef4f3211076b34a18b585547d34e365e78dcc26dd4ab15c069731fc4b1c07a26bfced09ea31 + languageName: node + linkType: hard + +"d3-geo@npm:3": + version: 3.1.1 + resolution: "d3-geo@npm:3.1.1" + dependencies: + d3-array: "npm:2.5.0 - 3" + checksum: 10/dc5e980330d891dabf92869b98871b05ca2021c64d7ef253bcfd4f2348839ad33576fba474baecc2def86ebd3d943a11d93c0af26be0a2694f5bd59824838133 + languageName: node + linkType: hard + +"d3-hierarchy@npm:3": + version: 3.1.2 + resolution: "d3-hierarchy@npm:3.1.2" + checksum: 10/497b79dc6c35e28b21e8a7b94db92876abd1d4ec082d9803a07ea8964e55b0e71c511a21489363a36f1456f069adb8ff7d33c633678730d6ae961ed350b27733 + languageName: node + linkType: hard + +"d3-interpolate@npm:1 - 3, d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:3": + version: 3.0.1 + resolution: "d3-interpolate@npm:3.0.1" + dependencies: + d3-color: "npm:1 - 3" + checksum: 10/988d66497ef5c190cf64f8c80cd66e1e9a58c4d1f8932d776a8e3ae59330291795d5a342f5a97602782ccbef21a5df73bc7faf1f0dc46a5145ba6243a82a0f0e + languageName: node + linkType: hard + +"d3-path@npm:1 - 3, d3-path@npm:3, d3-path@npm:^3.1.0": + version: 3.1.0 + resolution: "d3-path@npm:3.1.0" + checksum: 10/8e97a9ab4930a05b18adda64cf4929219bac913a5506cf8585631020253b39309549632a5cbeac778c0077994442ddaaee8316ee3f380e7baf7566321b84e76a + languageName: node + linkType: hard + +"d3-polygon@npm:3": + version: 3.0.1 + resolution: "d3-polygon@npm:3.0.1" + checksum: 10/c4fa2ed19dcba13fd341815361d27e64597aa0d38d377e401e1353c4acbe8bd73c0afb3e49a1cf4119fadc3651ec8073d06aa6d0e34e664c868d071e58912cd1 + languageName: node + linkType: hard + +"d3-quadtree@npm:1 - 3, d3-quadtree@npm:3": + version: 3.0.1 + resolution: "d3-quadtree@npm:3.0.1" + checksum: 10/1915b6a7b031fc312f9af61947072db9468c5a2b03837f6a90b38fdaebcd0ea17a883bffd94d16b8a6848e81711a06222f7d39f129386ef1850297219b8d32ba + languageName: node + linkType: hard + +"d3-random@npm:3": + version: 3.0.1 + resolution: "d3-random@npm:3.0.1" + checksum: 10/9f41d6ca3a1826cea8d88392917b5039504337d442a4d1357c870fa3031701e60209a2689a6ddae7df8fca824383d038c957eb545bc49a7428c71aaf3b11f56f + languageName: node + linkType: hard + +"d3-scale-chromatic@npm:3": + version: 3.1.0 + resolution: "d3-scale-chromatic@npm:3.1.0" + dependencies: + d3-color: "npm:1 - 3" + d3-interpolate: "npm:1 - 3" + checksum: 10/25df6a7c621b9171df8b2225e98e41c0a6bcac4de02deb4807280b31116e8f495c5ac93301796098ee5b698cb690154e8138d90d72fd1fe36744c60e02a3d8c4 + languageName: node + linkType: hard + +"d3-scale@npm:4": + version: 4.0.2 + resolution: "d3-scale@npm:4.0.2" + dependencies: + d3-array: "npm:2.10.0 - 3" + d3-format: "npm:1 - 3" + d3-interpolate: "npm:1.2.0 - 3" + d3-time: "npm:2.1.1 - 3" + d3-time-format: "npm:2 - 4" + checksum: 10/e2dc4243586eae2a0fdf91de1df1a90d51dfacb295933f0ca7e9184c31203b01436bef69906ad40f1100173a5e6197ae753cb7b8a1a8fcfda43194ea9cad6493 + languageName: node + linkType: hard + +"d3-selection@npm:2 - 3, d3-selection@npm:3": + version: 3.0.0 + resolution: "d3-selection@npm:3.0.0" + checksum: 10/0e5acfd305b31628b7be5009ba7303d84bb34817a88ed4dde9c8bd9c23528573fc5272f89fc04e5be03d2cbf5441a248d7274aaf55a8ef3dad46e16333d72298 + languageName: node + linkType: hard + +"d3-shape@npm:3": + version: 3.2.0 + resolution: "d3-shape@npm:3.2.0" + dependencies: + d3-path: "npm:^3.1.0" + checksum: 10/2e861f4d4781ee8abd85d2b435f848d667479dcf01a4e0db3a06600a5bdeddedb240f88229ec7b3bf7fa300c2b3526faeaf7e75f9a24dbf4396d3cc5358ff39d + languageName: node + linkType: hard + +"d3-time-format@npm:2 - 4, d3-time-format@npm:4": + version: 4.1.0 + resolution: "d3-time-format@npm:4.1.0" + dependencies: + d3-time: "npm:1 - 3" + checksum: 10/ffc0959258fbb90e3890bfb31b43b764f51502b575e87d0af2c85b85ac379120d246914d07fca9f533d1bcedc27b2841d308a00fd64848c3e2cad9eff5c9a0aa + languageName: node + linkType: hard + +"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:3": + version: 3.1.0 + resolution: "d3-time@npm:3.1.0" + dependencies: + d3-array: "npm:2 - 3" + checksum: 10/c110bed295ce63e8180e45b82a9b0ba114d5f33ff315871878f209c1a6d821caa505739a2b07f38d1396637155b8e7372632dacc018e11fbe8ceef58f6af806d + languageName: node + linkType: hard + +"d3-timer@npm:1 - 3, d3-timer@npm:3": + version: 3.0.1 + resolution: "d3-timer@npm:3.0.1" + checksum: 10/004128602bb187948d72c7dc153f0f063f38ac7a584171de0b45e3a841ad2e17f1e40ad396a4af9cce5551b6ab4a838d5246d23492553843d9da4a4050a911e2 + languageName: node + linkType: hard + +"d3-transition@npm:2 - 3, d3-transition@npm:3": + version: 3.0.1 + resolution: "d3-transition@npm:3.0.1" + dependencies: + d3-color: "npm:1 - 3" + d3-dispatch: "npm:1 - 3" + d3-ease: "npm:1 - 3" + d3-interpolate: "npm:1 - 3" + d3-timer: "npm:1 - 3" + peerDependencies: + d3-selection: 2 - 3 + checksum: 10/02571636acb82f5532117928a87fe25de68f088c38ab4a8b16e495f0f2d08a3fd2937eaebdefdfcf7f1461545524927d2632d795839b88d2e4c71e387aaaffac + languageName: node + linkType: hard + +"d3-zoom@npm:3": + version: 3.0.0 + resolution: "d3-zoom@npm:3.0.0" + dependencies: + d3-dispatch: "npm:1 - 3" + d3-drag: "npm:2 - 3" + d3-interpolate: "npm:1 - 3" + d3-selection: "npm:2 - 3" + d3-transition: "npm:2 - 3" + checksum: 10/0e6e5c14e33c4ecdff311a900dd037dea407734f2dd2818988ed6eae342c1799e8605824523678bd404f81e37824cc588f62dbde46912444c89acc7888036c6b + languageName: node + linkType: hard + +"d3@npm:^7.9.0": + version: 7.9.0 + resolution: "d3@npm:7.9.0" + dependencies: + d3-array: "npm:3" + d3-axis: "npm:3" + d3-brush: "npm:3" + d3-chord: "npm:3" + d3-color: "npm:3" + d3-contour: "npm:4" + d3-delaunay: "npm:6" + d3-dispatch: "npm:3" + d3-drag: "npm:3" + d3-dsv: "npm:3" + d3-ease: "npm:3" + d3-fetch: "npm:3" + d3-force: "npm:3" + d3-format: "npm:3" + d3-geo: "npm:3" + d3-hierarchy: "npm:3" + d3-interpolate: "npm:3" + d3-path: "npm:3" + d3-polygon: "npm:3" + d3-quadtree: "npm:3" + d3-random: "npm:3" + d3-scale: "npm:4" + d3-scale-chromatic: "npm:3" + d3-selection: "npm:3" + d3-shape: "npm:3" + d3-time: "npm:3" + d3-time-format: "npm:4" + d3-timer: "npm:3" + d3-transition: "npm:3" + d3-zoom: "npm:3" + checksum: 10/b0b418996bdf279b01f5c7a0117927f9ad3e833c9ce4657550ce6f6ace70b70cf829c4144b01df0be5a0f716d4e5f15ab0cadc5ff1ce1561d7be29ac86493d83 + languageName: node + linkType: hard + "d@npm:1, d@npm:^1.0.1, d@npm:^1.0.2": version: 1.0.2 resolution: "d@npm:1.0.2" @@ -27931,6 +28244,15 @@ __metadata: languageName: node linkType: hard +"delaunator@npm:5": + version: 5.0.1 + resolution: "delaunator@npm:5.0.1" + dependencies: + robust-predicates: "npm:^3.0.2" + checksum: 10/c378a55138d81d471a7214635b1a2c5e74f8ee06582f558df72f0c7c82c25868599ce9a18fb25a245c6c03cab886d17fb574681c78371b539dd069818703f53a + languageName: node + linkType: hard + "delay@npm:^5.0.0": version: 5.0.0 resolution: "delay@npm:5.0.0" @@ -35129,21 +35451,21 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:0.6.2": - version: 0.6.2 - resolution: "iconv-lite@npm:0.6.2" +"iconv-lite@npm:0.6, iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" dependencies: safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10/ba81a32a54066e64ac68174851d1c17534ef398627eb5d07b4ef2999126674d66f7377aa46c8d1450ef6aee3d679ccaeb9af402b5c58ecec649cee361c1ad16d + checksum: 10/24e3292dd3dadaa81d065c6f8c41b274a47098150d444b96e5f53b4638a9a71482921ea6a91a1f59bb71d9796de25e04afd05919fa64c360347ba65d3766f10f languageName: node linkType: hard -"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2": - version: 0.6.3 - resolution: "iconv-lite@npm:0.6.3" +"iconv-lite@npm:0.6.2": + version: 0.6.2 + resolution: "iconv-lite@npm:0.6.2" dependencies: safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10/24e3292dd3dadaa81d065c6f8c41b274a47098150d444b96e5f53b4638a9a71482921ea6a91a1f59bb71d9796de25e04afd05919fa64c360347ba65d3766f10f + checksum: 10/ba81a32a54066e64ac68174851d1c17534ef398627eb5d07b4ef2999126674d66f7377aa46c8d1450ef6aee3d679ccaeb9af402b5c58ecec649cee361c1ad16d languageName: node linkType: hard @@ -35513,6 +35835,13 @@ __metadata: languageName: node linkType: hard +"internmap@npm:1 - 2": + version: 2.0.3 + resolution: "internmap@npm:2.0.3" + checksum: 10/873e0e7fcfe32f999aa0997a0b648b1244508e56e3ea6b8259b5245b50b5eeb3853fba221f96692bd6d1def501da76c32d64a5cb22a0b26cdd9b445664f805e0 + languageName: node + linkType: hard + "interpret@npm:^1.0.0": version: 1.4.0 resolution: "interpret@npm:1.4.0" @@ -35520,6 +35849,15 @@ __metadata: languageName: node linkType: hard +"interval-tree-1d@npm:^1.0.0": + version: 1.0.4 + resolution: "interval-tree-1d@npm:1.0.4" + dependencies: + binary-search-bounds: "npm:^2.0.0" + checksum: 10/76bb99efae888250bfef78eef9f616bf80803a1f6f2509a6448902958efce4bc5f083d51475f83792a585f2c243a93646647b7e0703ea75fd5bf588d2986ad6b + languageName: node + linkType: hard + "invariant@npm:^2.2.2, invariant@npm:^2.2.4": version: 2.2.4 resolution: "invariant@npm:2.2.4" @@ -36641,6 +36979,13 @@ __metadata: languageName: node linkType: hard +"isoformat@npm:^0.2.0": + version: 0.2.1 + resolution: "isoformat@npm:0.2.1" + checksum: 10/28487777526c93360c2f49abbf03d45778ad2c55bfccb3a6bf04905b2ddfafcb9f29a68d6ab5251f2919afb47e0e018fe25f815fd68180f4117161c508878558 + languageName: node + linkType: hard + "isomorphic-fetch@npm:3.0.0": version: 3.0.0 resolution: "isomorphic-fetch@npm:3.0.0" @@ -46020,18 +46365,6 @@ __metadata: languageName: node linkType: hard -"react-apexcharts@npm:1.4.1": - version: 1.4.1 - resolution: "react-apexcharts@npm:1.4.1" - dependencies: - prop-types: "npm:^15.8.1" - peerDependencies: - apexcharts: ^3.41.0 - react: ">=0.13" - checksum: 10/0f0963ad31b5fc30b094f7b44536f6d3a95dc3453276589d39195f43c233ec983843b94066d53b3ef3a3bff43465453291567c3d4b9eaa54d66f28badf8c0e4c - languageName: node - linkType: hard - "react-async-script@npm:^1.2.0": version: 1.2.0 resolution: "react-async-script@npm:1.2.0" @@ -47873,6 +48206,13 @@ __metadata: languageName: node linkType: hard +"robust-predicates@npm:^3.0.2": + version: 3.0.2 + resolution: "robust-predicates@npm:3.0.2" + checksum: 10/88bd7d45a6b89e88da2631d4c111aaaf0443de4d7078e9ab7f732245790a3645cf79bf91882a9740dbc959cf56ba75d5dced5bf2259410f8b6de19fd240cd08c + languageName: node + linkType: hard + "rollup-plugin-inject@npm:^3.0.0": version: 3.0.2 resolution: "rollup-plugin-inject@npm:3.0.2" @@ -48123,6 +48463,13 @@ __metadata: languageName: node linkType: hard +"rw@npm:1": + version: 1.3.3 + resolution: "rw@npm:1.3.3" + checksum: 10/e90985d64777a00f4ab5f8c0bfea2fb5645c6bda5238840afa339c8a4f86f776e8ce83731155643a7425a0b27ce89077dab27b2f57519996ba4d2fe54cac1941 + languageName: node + linkType: hard + "rxjs@npm:7.8.0": version: 7.8.0 resolution: "rxjs@npm:7.8.0" @@ -50749,77 +51096,6 @@ __metadata: languageName: node linkType: hard -"svg.draggable.js@npm:^2.2.2": - version: 2.2.2 - resolution: "svg.draggable.js@npm:2.2.2" - dependencies: - svg.js: "npm:^2.0.1" - checksum: 10/0200198f64a6883c88a31b8663a0bcc21bf01bdf7dfca1930dbeeeed49d4993d8ad4c3da044166205128b8835ce6d7a429e95d68fed1dce644730794beb45c23 - languageName: node - linkType: hard - -"svg.easing.js@npm:^2.0.0": - version: 2.0.0 - resolution: "svg.easing.js@npm:2.0.0" - dependencies: - svg.js: "npm:>=2.3.x" - checksum: 10/06a9f0b75e8b0625b8e3dd13ff5fb9c279fa1a098fbf5d28f8f7f298d93f280d3d8afa3737bf0304f16589d1c02b1823cefdf7d4a6a8817fd07bcb46f456c97e - languageName: node - linkType: hard - -"svg.filter.js@npm:^2.0.2": - version: 2.0.2 - resolution: "svg.filter.js@npm:2.0.2" - dependencies: - svg.js: "npm:^2.2.5" - checksum: 10/7337c780f715f1292deb93b62e29926bed3deb841d2ee253fa7cb9785ecb2ba6425169949b19bca57ea30b8455d355bc2ef84c71b476e833c2e662a4554dc917 - languageName: node - linkType: hard - -"svg.js@npm:>=2.3.x, svg.js@npm:^2.0.1, svg.js@npm:^2.2.5, svg.js@npm:^2.4.0, svg.js@npm:^2.6.5": - version: 2.7.1 - resolution: "svg.js@npm:2.7.1" - checksum: 10/28333c819aa461d20358d8cf43db6a92fd41389f0a6c5a2563d398865f541a88d9cb118d5e276c513bc307aea8aeb893725a198ec9447ca19ccf898d5c4126cd - languageName: node - linkType: hard - -"svg.pathmorphing.js@npm:^0.1.3": - version: 0.1.3 - resolution: "svg.pathmorphing.js@npm:0.1.3" - dependencies: - svg.js: "npm:^2.4.0" - checksum: 10/a958c3e2a4a1e845da443dd72b890feed5cc6a1d0a5bfcd16b5be610292b7a9c2ab8453689b416e2a8f2abe0f65e987eb981c6d2428b892b67f511d776ccc1bb - languageName: node - linkType: hard - -"svg.resize.js@npm:^1.4.3": - version: 1.4.3 - resolution: "svg.resize.js@npm:1.4.3" - dependencies: - svg.js: "npm:^2.6.5" - svg.select.js: "npm:^2.1.2" - checksum: 10/78c6973695a185fb2e3efa582f8b6a5c8c01e8a0c04a0126d0141f4eecb260c5d471cb15353b1afa8e811dee2a05f0637a75897c9c5e350c8fac7baf86f45a8e - languageName: node - linkType: hard - -"svg.select.js@npm:^2.1.2": - version: 2.1.2 - resolution: "svg.select.js@npm:2.1.2" - dependencies: - svg.js: "npm:^2.2.5" - checksum: 10/65e9b0e605fae5aaa29e5972577f4cf0e5ffc5de54d26c6e1a3c17be7fbcdc2b6faba1874735491f1c8d1caf9a50ca404422782c292080ea5eb0165af48a9ccb - languageName: node - linkType: hard - -"svg.select.js@npm:^3.0.1": - version: 3.0.1 - resolution: "svg.select.js@npm:3.0.1" - dependencies: - svg.js: "npm:^2.6.5" - checksum: 10/357e759ffb405b7ac97f50d161f1bfeb8fb145288fe0b34fc32a0347538b74cf92ef0c2cff8fe4a2acfccbd8ff10ec5ba852071400559623629ce97b56e4c8e9 - languageName: node - linkType: hard - "svgo@npm:^2.7.0, svgo@npm:^2.8.0": version: 2.8.0 resolution: "svgo@npm:2.8.0"