diff --git a/unlock-protocol-com/package.json b/unlock-protocol-com/package.json
index e7965333cfc..9229bfecfa2 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) => (
-
-
-
-
-
-
- {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) => (
+
+
+
+
+
+
+ {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 2458b0b067b..b41a6e76ff2 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"
@@ -20513,6 +20524,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"
@@ -20523,7 +20535,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"
@@ -20546,7 +20557,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"
@@ -21838,13 +21848,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"
@@ -22524,21 +22527,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"
@@ -24165,6 +24153,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"
@@ -26386,6 +26381,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"
@@ -26414,13 +26416,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"
@@ -27627,6 +27622,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"
@@ -28050,6 +28363,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"
@@ -35196,21 +35518,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
@@ -35580,6 +35902,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"
@@ -35587,6 +35916,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"
@@ -36708,6 +37046,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"
@@ -46054,18 +46399,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"
@@ -47896,6 +48229,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"
@@ -48146,6 +48486,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"
@@ -50772,77 +51119,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"