From 64067322d144989b2619ad52a4d1fbeb3f967056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Wed, 27 Mar 2024 17:39:41 +0100 Subject: [PATCH 01/13] init refactoring --- .../src/components/pages/State/index.tsx | 609 +++--------------- .../components/pages/State/sections/chart.tsx | 247 +++++++ .../components/pages/State/sections/gnp.tsx | 50 ++ .../pages/State/sections/overview.tsx | 97 +++ 4 files changed, 497 insertions(+), 506 deletions(-) create mode 100644 unlock-protocol-com/src/components/pages/State/sections/chart.tsx create mode 100644 unlock-protocol-com/src/components/pages/State/sections/gnp.tsx create mode 100644 unlock-protocol-com/src/components/pages/State/sections/overview.tsx diff --git a/unlock-protocol-com/src/components/pages/State/index.tsx b/unlock-protocol-com/src/components/pages/State/index.tsx index 53b5ad90ea9..036f6b0d056 100644 --- a/unlock-protocol-com/src/components/pages/State/index.tsx +++ b/unlock-protocol-com/src/components/pages/State/index.tsx @@ -1,29 +1,15 @@ 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' -const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }) - -type IOverView = { - Icon: (props: IconBaseProps) => JSX.Element - value: number - title: string - description: string -} - -type ISeries = { - name: string - data: number[] -} +// sections components +import { Overview } from './sections/overview' +import { GNP } from './sections/gnp' +import { HistoricalChart } from './sections/chart' type INetworkSubgraph = { lockStats: { @@ -38,137 +24,77 @@ type INetworkSubgraph = { }[] } -type IXaxis = { - categories: string[] -} - type IGNPSum = { name: string gnpSum: number } const filters = ['7D', '1M', '1Y', 'All'] +type IFilter = { + period: string + selectedNetwork?: string | undefined +} -function RenderChart({ series, xaxis }: { series: any; xaxis?: any }) { - if (!series || series.length === 0) { - return null - } +function filterData({ subgraphData, filter }) { + const { period, selectedNetwork } = filter - 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 currentDay = Math.round(new Date().getTime() / 86400000) + const days = { + '7D': 8, + '1M': 31, + '1Y': 360, + ALL: 0, + }[period] + const upperLimit = currentDay - days + + const filterTime = ({ name, data }) => { + console.log({ name, data }) + return { + name, + data: { + ...data, + unlockDailyDatas: period + ? data.unlockDailyDatas.filter(({ id }) => id >= upperLimit) + : data.unlockDailyDatas, }, - }, + } } - return ( -
- -
- ) + // aggregate data + console.log(selectedNetwork) + if (!selectedNetwork || selectedNetwork === 'ALL') { + return subgraphData.map((row) => { + filterTime(row) + }) + } else { + return subgraphData + .filter(({ name }) => + selectedNetwork ? name === filter.selectedNetwork : true + ) + .map(filterTime) + } } function DateFilter({ filter, setFilter, }: { - filter: string - setFilter: (value: string) => void + filter: IFilter + setFilter: (value: IFilter) => void }) { return (
{filters.map((item, index) => (
setFilter(item)} + onClick={() => setFilter({ ...filter, period: item })} key={index} >

{item} @@ -179,257 +105,46 @@ 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 - ) - .map((item) => item.activeLocks) - .flatMap((data) => data) - return [...new Set(activeLockList)].length -} - -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) - }) +function NetworkPicker({ + filter, + setFilter, +}: { + filter: IFilter + setFilter: (value: IFilter) => void +}) { + return ( +

+ +
+ ) } 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]) - - 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() - }, []) - - 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, - ], - }), - { - 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' - ) - ) - return { - name: networkData.name, - gnpPercentage: - sumOfGNP / - gnpTotalValueByNetwork.find((item) => item.name === networkData.name) - ?.gnpSum, - } - }) - setGNPPByNetworks(gnpPercentageByNetworks) - }, [filter, currentDay, subgraphData, gnpTotalValueByNetwork]) + const [filter, setFilter] = useState({ period: '7D' }) + const [filteredData, setFilteredData] = useState([]) + // get subgraphData useEffect(() => { const run = async () => { const subgraphData = await Promise.all( @@ -448,152 +163,34 @@ export function State() { 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, subgraphData })) + }, [filter, subgraphData]) 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} -

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

Overview

+ +
+
+

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..4de9f57c184 --- /dev/null +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -0,0 +1,247 @@ +import React, { useEffect, useState } from 'react' +import dynamic from 'next/dynamic' +const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }) + +type ISeries = { + name: string + data: number[] +} +type IXaxis = { + categories: string[] +} + +function parseRenderData(subgraphData, timestampArray: number[]) { + console.log(timestampArray) + console.log(subgraphData) + return timestampArray.map((dayId) => { + const dayDatas = unlockDailyDatas.filter( + (item) => item.id >= dayId - 1 && item.id < dayId + ) + + const keys = dayDatas.reduce((x, y) => x + Number(y.totalKeysSold), 0) + + const lastMonthActiveLocks = unlockDailyDatas.unlockDailyDatas + .filter((item) => item.id > dayId - 30 && item.id <= dayId) + .map((item) => item.activeLocks) + .flatMap((lock) => lock) + const activeLocks = [...new Set(lastMonthActiveLocks)].length + + const allLocks = dayDatas.reduce( + (x, y) => x + Number(y.totalLockDeployed), + 0 + ) + return { + keys, + activeLocks, + allLocks, + } + }) +} + +function RenderChart({ series, xaxis }: { series: any; xaxis?: any }) { + if (!series || series.length === 0) { + return null + } + + 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 } }, + }, + }, + } + + return ( +
+ +
+ ) +} + +function getTimestamps({ period }) { + const ticksCount = { '7D': 7, '1M': 12, '1Y': 30, ALL: 12 }[period] + + return [...Array(ticksCount).keys()].reverse().map((key) => { + const cur = new Date() + return Math.round(cur.setDate(cur.getDate() - key) / 86400000) + // .toLocaleString( + // 'default', + // { dateStyle: 'short' } + // ) + }) +} + +export function HistoricalChart({ subgraphData, filter }) { + const [series, setSeries] = useState([]) + const [xaxis, setXaxis] = useState(undefined) + + console.log({ subgraphData }) + + useEffect(() => { + 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, + // }) + const timestamps = getTimestamps(filter) + console.log(subgraphData) + // const renderData = parseRenderData(subgraphData, timestamps) + // setSeries([ + // { + // name: 'Keys (Memberships) Minted', + // data: renderData.map(({ keys }) => keys), + // }, + // { + // name: 'Active Locks', + // data: renderData.map(({ activeLocks }) => activeLocks), + // }, + // { + // name: 'Locks Deployed', + // data: renderData.map(({ allLocks }) => allLocks), + // }, + // ]) + }, [subgraphData, filter]) + + 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..e3ad523ec4a --- /dev/null +++ b/unlock-protocol-com/src/components/pages/State/sections/gnp.tsx @@ -0,0 +1,50 @@ +import React, { useEffect, useState } from 'react' + +import numeral from 'numeral' +import { CryptoIcon } from '@unlock-protocol/crypto-icon' +import { getGNPs } from '../../../../utils/apiRequest' + +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((item) => !item.network.isTestNetwork) + .map(({ total, network }, index) => ( +
+
+

{network.name}

+
+ +
+ +

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

+

+ {network.nativeCurrency.symbol} +

+
+
+ ))} +
+ ) +} 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..85fb5c8462c --- /dev/null +++ b/unlock-protocol-com/src/components/pages/State/sections/overview.tsx @@ -0,0 +1,97 @@ +import React, { useEffect, useState } from 'react' +import { IconBaseProps } from 'react-icons' +import { ActiveLock, Lock, Key } from '../../../icons' +import numeral from 'numeral' +import { utils } from 'ethers' + +type IOverView = { + Icon: (props: IconBaseProps) => JSX.Element + value: number + title: string + description: string +} + +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 + ) + .map((item) => item.activeLocks) + .flatMap((data) => data) + return [...new Set(activeLockList)].length +} + +export function Overview({ subgraphData }) { + const [overViewData, setOverViewData] = useState([]) + + 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) + } + }, [subgraphData]) + + return ( +
+ {overViewData && + overViewData.map(({ value, title, description, Icon }, index) => ( +
+

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

+

+ {title} +

+
+ {description} + +
+
+ ))} +
+ ) +} From a87acfe112abd7fe04a6052e100b642df688d6d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Thu, 28 Mar 2024 15:57:22 +0100 Subject: [PATCH 02/13] working version --- unlock-protocol-com/package.json | 3 +- .../src/components/pages/State/index.tsx | 200 ++++--- .../components/pages/State/sections/chart.tsx | 325 ++++------- .../pages/State/sections/overview.tsx | 61 +- unlock-protocol-com/src/hooks/useSubgraph.ts | 66 +-- yarn.lock | 520 ++++++++++++++---- 6 files changed, 659 insertions(+), 516 deletions(-) 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 036f6b0d056..f656ee790e5 100644 --- a/unlock-protocol-com/src/components/pages/State/index.tsx +++ b/unlock-protocol-com/src/components/pages/State/index.tsx @@ -1,80 +1,70 @@ -import { Button } from '@unlock-protocol/ui' import React, { useEffect, useState } from 'react' -import numeral from 'numeral' -import { useQuery } from '@tanstack/react-query' import { networks } from '@unlock-protocol/networks' import { getSubgraph4GNP } from 'src/hooks/useSubgraph' -import { utils } from 'ethers' // sections components import { Overview } from './sections/overview' import { GNP } from './sections/gnp' import { HistoricalChart } from './sections/chart' -type INetworkSubgraph = { - lockStats: { - totalKeysSold: string - totalLocksDeployed: string - } - unlockDailyDatas: { - activeLocks: string[] - id: number - totalKeysSold: string - totalLockDeployed: string - }[] +type IDailyStats = { + name: string + id: number + date: Date + activeLocks: string[] + totalKeysSold: string + totalLockDeployed: string } -type IGNPSum = { +type ILockStats = { name: string - gnpSum: number + id: number + totalKeysSold: string + totalLocksDeployed: string + activeLocks: number } -const filters = ['7D', '1M', '1Y', 'All'] type IFilter = { - period: string - selectedNetwork?: string | undefined + period: number + selectedNetwork?: number | undefined } -function filterData({ subgraphData, filter }) { - const { period, selectedNetwork } = filter +const filters = [ + { label: 'ALL', period: 1000 }, + { label: '7 Days', period: 7 }, + { label: '1 Month', period: 30 }, + { label: '1 Year', period: 365 }, +] - const currentDay = Math.round(new Date().getTime() / 86400000) - const days = { - '7D': 8, - '1M': 31, - '1Y': 360, - ALL: 0, - }[period] - const upperLimit = currentDay - days - - const filterTime = ({ name, data }) => { - console.log({ name, data }) - return { - name, - data: { - ...data, - unlockDailyDatas: period - ? data.unlockDailyDatas.filter(({ id }) => id >= upperLimit) - : data.unlockDailyDatas, - }, - } - } - - // aggregate data - console.log(selectedNetwork) - if (!selectedNetwork || selectedNetwork === 'ALL') { - return subgraphData.map((row) => { - filterTime(row) - }) - } else { - return subgraphData - .filter(({ name }) => - selectedNetwork ? name === filter.selectedNetwork : true - ) - .map(filterTime) - } +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, selectedNetwork } = filter + return dailyStats.filter(({ name, date }) => + isWithin(date, period) && (!selectedNetwork || selectedNetwork === 'ALL') + ? true + : name === selectedNetwork + ) +} + +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 DateFilter({ filter, setFilter, @@ -84,20 +74,20 @@ function DateFilter({ }) { return (
- {filters.map((item, index) => ( + {filters.map(({ label, period }, index) => (
setFilter({ ...filter, period: item })} + onClick={() => setFilter({ ...filter, period })} key={index} >

- {item} + {label}

))} @@ -125,14 +115,11 @@ function NetworkPicker({ - {Object.keys(networks) - .map((id) => networks[id]) - .filter(({ isTestNetwork }) => !isTestNetwork) - .map(({ name }, index) => ( - - ))} + {supportedNetworks.map(({ name, chain }, index) => ( + + ))}
) @@ -140,33 +127,72 @@ function NetworkPicker({ export function State() { const currentDay = Math.round(new Date().getTime() / 86400000) - const [subgraphData, setSubgraphData] = useState([]) - const [filter, setFilter] = useState({ period: '7D' }) - const [filteredData, setFilteredData] = useState([]) + const [dailyStats, setDailyStats] = useState([]) + const [lockStats, setLockStats] = useState([]) + const [filter, setFilter] = useState({ period: 1000 }) + const [filteredData, setFilteredData] = useState([]) - // get subgraphData + // get data from all subgraphs 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 allData = await Promise.all( + supportedNetworks.map(async ({ name, id, subgraphURI }) => { + const data = await getSubgraph4GNP(subgraphURI, currentDay - 1000) + return { + name, + id, + data, } }) ) - setSubgraphData(subgraphData.filter((item) => item && item.data)) + + const dailyStats = allData.reduce( + (obj, { data: { unlockDailyDatas }, name, id }) => { + unlockDailyDatas.forEach(({ date, ...datum }, i) => { + obj = [ + ...obj, + { + date, + name, + 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 + }, + [] + ) + setDailyStats(dailyStats) + + const lockStats = allData.map( + ({ data: { lockStats, unlockDailyDatas }, name, id }) => ({ + name, + id, + ...lockStats, + activeLocks: unlockDailyDatas + .map(({ activeLocks }) => activeLocks) + .reduce((pv, a) => pv + a, 0), + }) + ) + setLockStats(lockStats) } run() }, [currentDay]) // filter data properly useEffect(() => { - setFilteredData(filterData({ filter, subgraphData })) - }, [filter, subgraphData]) + setFilteredData(filterData({ filter, dailyStats })) + }, [filter, dailyStats]) return (
@@ -176,7 +202,7 @@ export function State() {

Overview

- +

Activity over time

@@ -185,12 +211,12 @@ export function State() {
{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 index 4de9f57c184..e44ece8d5ef 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -1,6 +1,5 @@ -import React, { useEffect, useState } from 'react' -import dynamic from 'next/dynamic' -const ReactApexChart = dynamic(() => import('react-apexcharts'), { ssr: false }) +import React, { useRef, useEffect, useState } from 'react' +import * as Plot from '@observablehq/plot' type ISeries = { name: string @@ -10,238 +9,116 @@ type IXaxis = { categories: string[] } -function parseRenderData(subgraphData, timestampArray: number[]) { - console.log(timestampArray) - console.log(subgraphData) - return timestampArray.map((dayId) => { - const dayDatas = unlockDailyDatas.filter( - (item) => item.id >= dayId - 1 && item.id < dayId - ) - - const keys = dayDatas.reduce((x, y) => x + Number(y.totalKeysSold), 0) +interface IViewFilter { + label: string + value: string +} - const lastMonthActiveLocks = unlockDailyDatas.unlockDailyDatas - .filter((item) => item.id > dayId - 30 && item.id <= dayId) - .map((item) => item.activeLocks) - .flatMap((lock) => lock) - const activeLocks = [...new Set(lastMonthActiveLocks)].length +const views = [ + { + label: 'Locks deployed', + value: 'lockDeployed', + }, + { + label: 'Locks active', + value: 'activeLocks', + }, + { + label: 'Keys', + value: 'keySold', + }, + { + label: 'Locks deployed (cumulative)', + value: 'totalLockDeployed', + }, + { + label: 'Keys (cumulative)', + value: 'totalKeysSold', + }, +] - const allLocks = dayDatas.reduce( - (x, y) => x + Number(y.totalLockDeployed), - 0 - ) - return { - keys, - activeLocks, - allLocks, - } - }) +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 - } +export function HistoricalChart({ dailyStats, filter }) { + const ref = useRef() + const [viewFilter, setViewFilter] = useState(views[1]) - const chartOptions = { - options: { - chart: { zoom: { enabled: false } }, - stroke: { - curve: 'smooth' as 'smooth' | 'straight' | 'stepline', - width: 3, - }, - dataLabels: { - enabled: false, + useEffect(() => { + console.log(viewFilter) + const barChart = Plot.plot({ + title: `${viewFilter.label}`, + width: 1200, + height: 500, + marginLeft: 50, + marginTop: 50, + marginBottom: 50, + y: { + grid: true, + axis: 'left', + label: `${viewFilter.label}`, }, - markers: { - size: 0, - hover: { - sizeOffset: 6, - }, + color: { + type: 'categorical', + scheme: 'Tableau10', + legend: true, + // width: 628, + label: 'Networks', }, - 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) + marks: [ + // locks deployed + Plot.rectY( + dailyStats, + Plot.binX( + { + y: 'sum', }, - }, - }, + { + x: 'date', + y: viewFilter.value, + fill: 'name', + interval: filter.period === 7 ? 'day' : 'week', + } + ) + ), ], - 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 } }, - }, - }, - } + }) + + ref.current?.append(barChart) + return () => barChart.remove() + }, [dailyStats, viewFilter]) return ( -
- +
+ +
) } - -function getTimestamps({ period }) { - const ticksCount = { '7D': 7, '1M': 12, '1Y': 30, ALL: 12 }[period] - - return [...Array(ticksCount).keys()].reverse().map((key) => { - const cur = new Date() - return Math.round(cur.setDate(cur.getDate() - key) / 86400000) - // .toLocaleString( - // 'default', - // { dateStyle: 'short' } - // ) - }) -} - -export function HistoricalChart({ subgraphData, filter }) { - const [series, setSeries] = useState([]) - const [xaxis, setXaxis] = useState(undefined) - - console.log({ subgraphData }) - - useEffect(() => { - 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, - // }) - const timestamps = getTimestamps(filter) - console.log(subgraphData) - // const renderData = parseRenderData(subgraphData, timestamps) - // setSeries([ - // { - // name: 'Keys (Memberships) Minted', - // data: renderData.map(({ keys }) => keys), - // }, - // { - // name: 'Active Locks', - // data: renderData.map(({ activeLocks }) => activeLocks), - // }, - // { - // name: 'Locks Deployed', - // data: renderData.map(({ allLocks }) => allLocks), - // }, - // ]) - }, [subgraphData, filter]) - - return -} diff --git a/unlock-protocol-com/src/components/pages/State/sections/overview.tsx b/unlock-protocol-com/src/components/pages/State/sections/overview.tsx index 85fb5c8462c..3098cb5afa1 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/overview.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/overview.tsx @@ -11,69 +11,48 @@ type IOverView = { description: string } -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 - ) - .map((item) => item.activeLocks) - .flatMap((data) => data) - return [...new Set(activeLockList)].length -} - -export function Overview({ subgraphData }) { +export function Overview({ lockStats }) { const [overViewData, setOverViewData] = useState([]) useEffect(() => { - if (subgraphData !== undefined && subgraphData.length > 0) { + if (lockStats !== undefined && lockStats.length > 0) { const overview_contents: IOverView[] = [ { - value: subgraphData.reduce( - (pv, b) => pv + parseInt(b?.data?.lockStats?.totalLocksDeployed), - 0 - ), + value: lockStats.reduce((pv, b) => pv + b?.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 - ), + value: lockStats.reduce((pv, b) => pv + b?.totalKeysSold, 0), title: 'Total of Keys Sold', description: 'All Time, production networks only', Icon: Key, }, { - value: CalcActiveLocksCount(subgraphData), + 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, }, ] - 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' - ) - ), - })) + // const gnpDataByNetworks = lockStats.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) } - }, [subgraphData]) + }, [lockStats]) return (
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/yarn.lock b/yarn.lock index dfe2898f012..8fd140fd391 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" @@ -26273,6 +26268,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" @@ -26301,13 +26303,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" @@ -27514,6 +27509,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" @@ -27937,6 +28250,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" @@ -35108,21 +35430,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 @@ -35501,6 +35823,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" @@ -35508,6 +35837,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" @@ -36622,6 +36960,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" @@ -46008,18 +46353,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" @@ -47861,6 +48194,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" @@ -48110,6 +48450,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" @@ -50736,77 +51083,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" From b07ae4d08c60117bab325f05b20c7d52a7ab283a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Thu, 28 Mar 2024 15:58:38 +0100 Subject: [PATCH 03/13] remove unsuned code --- .../src/components/pages/State/sections/chart.tsx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx index e44ece8d5ef..a6434d044b5 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -1,14 +1,6 @@ import React, { useRef, useEffect, useState } from 'react' import * as Plot from '@observablehq/plot' -type ISeries = { - name: string - data: number[] -} -type IXaxis = { - categories: string[] -} - interface IViewFilter { label: string value: string From b2b51ebffca7883aa201ebc5a17065110c1ddaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Thu, 28 Mar 2024 16:08:33 +0100 Subject: [PATCH 04/13] cosmetics --- .../src/components/pages/State/index.tsx | 44 +++++++++---------- .../components/pages/State/sections/chart.tsx | 6 +-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/unlock-protocol-com/src/components/pages/State/index.tsx b/unlock-protocol-com/src/components/pages/State/index.tsx index f656ee790e5..60d3605e2d9 100644 --- a/unlock-protocol-com/src/components/pages/State/index.tsx +++ b/unlock-protocol-com/src/components/pages/State/index.tsx @@ -31,8 +31,8 @@ type IFilter = { const filters = [ { label: 'ALL', period: 1000 }, - { label: '7 Days', period: 7 }, { label: '1 Month', period: 30 }, + { label: '6 Months', period: 180 }, { label: '1 Year', period: 365 }, ] @@ -103,25 +103,23 @@ function NetworkPicker({ setFilter: (value: IFilter) => void }) { return ( -
- { + setFilter({ ...filter, selectedNetwork: e.target.value }) + }} + > + + {supportedNetworks.map(({ name, chain }, index) => ( + - {supportedNetworks.map(({ name, chain }, index) => ( - - ))} - -
+ ))} + ) } @@ -206,10 +204,12 @@ export function State() {

Activity over time

- - +
+ + +
-
+
{filteredData.length && ( )} diff --git a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx index a6434d044b5..a401aea1046 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -37,7 +37,7 @@ function ViewFilter({ setViewFilter: (value: IViewFilter) => void }) { return ( -
+
{views.map((view, index) => (
{ console.log(viewFilter) const barChart = Plot.plot({ - title: `${viewFilter.label}`, + // title: `${viewFilter.label}`, width: 1200, height: 500, marginLeft: 50, @@ -96,7 +96,7 @@ export function HistoricalChart({ dailyStats, filter }) { x: 'date', y: viewFilter.value, fill: 'name', - interval: filter.period === 7 ? 'day' : 'week', + interval: filter.period <= 180 ? 'day' : 'week', } ) ), From 559212db564ce29fa801143ecddb1b73c911183c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Thu, 28 Mar 2024 16:19:03 +0100 Subject: [PATCH 05/13] fix network selector --- .../src/components/pages/State/index.tsx | 36 ++++++++++--------- .../components/pages/State/sections/chart.tsx | 4 +-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/unlock-protocol-com/src/components/pages/State/index.tsx b/unlock-protocol-com/src/components/pages/State/index.tsx index 60d3605e2d9..9a160c033db 100644 --- a/unlock-protocol-com/src/components/pages/State/index.tsx +++ b/unlock-protocol-com/src/components/pages/State/index.tsx @@ -29,13 +29,23 @@ type IFilter = { selectedNetwork?: number | undefined } -const filters = [ - { label: 'ALL', period: 1000 }, +const timeFilters = [ { label: '1 Month', period: 30 }, { label: '6 Months', period: 180 }, { label: '1 Year', period: 365 }, + { label: 'ALL', period: 1000 }, ] +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() @@ -48,23 +58,13 @@ function isWithin(date, days) { function filterData({ dailyStats, filter }) { const { period, selectedNetwork } = filter - return dailyStats.filter(({ name, date }) => + return dailyStats.filter(({ chain, date }) => isWithin(date, period) && (!selectedNetwork || selectedNetwork === 'ALL') ? true - : name === selectedNetwork + : chain === selectedNetwork ) } -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 DateFilter({ filter, setFilter, @@ -74,7 +74,7 @@ function DateFilter({ }) { return (
- {filters.map(({ label, period }, index) => ( + {timeFilters.map(({ label, period }, index) => (
setFilter({ ...filter, period })} @@ -134,24 +134,26 @@ export function State() { useEffect(() => { const run = async () => { const allData = await Promise.all( - supportedNetworks.map(async ({ name, id, subgraphURI }) => { + supportedNetworks.map(async ({ name, id, chain, subgraphURI }) => { const data = await getSubgraph4GNP(subgraphURI, currentDay - 1000) return { name, id, data, + chain, } }) ) const dailyStats = allData.reduce( - (obj, { data: { unlockDailyDatas }, name, id }) => { + (obj, { data: { unlockDailyDatas }, name, id, chain }) => { unlockDailyDatas.forEach(({ date, ...datum }, i) => { obj = [ ...obj, { date, name, + chain, id, // compute locks per day lockDeployed: i diff --git a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx index a401aea1046..100141c86a1 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -64,9 +64,7 @@ export function HistoricalChart({ dailyStats, filter }) { const [viewFilter, setViewFilter] = useState(views[1]) useEffect(() => { - console.log(viewFilter) const barChart = Plot.plot({ - // title: `${viewFilter.label}`, width: 1200, height: 500, marginLeft: 50, @@ -96,7 +94,7 @@ export function HistoricalChart({ dailyStats, filter }) { x: 'date', y: viewFilter.value, fill: 'name', - interval: filter.period <= 180 ? 'day' : 'week', + interval: filter.period <= 365 ? 'day' : 'week', } ) ), From d2b1f1740c19b050336f8fb03eb2e655a4f7e08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Thu, 28 Mar 2024 16:27:23 +0100 Subject: [PATCH 06/13] looks better --- .../src/components/pages/State/index.tsx | 31 ++++++++++--------- .../components/pages/State/sections/chart.tsx | 2 +- .../pages/State/sections/overview.tsx | 15 --------- 3 files changed, 18 insertions(+), 30 deletions(-) diff --git a/unlock-protocol-com/src/components/pages/State/index.tsx b/unlock-protocol-com/src/components/pages/State/index.tsx index 9a160c033db..a79871a1c7c 100644 --- a/unlock-protocol-com/src/components/pages/State/index.tsx +++ b/unlock-protocol-com/src/components/pages/State/index.tsx @@ -30,10 +30,10 @@ type IFilter = { } const timeFilters = [ - { label: '1 Month', period: 30 }, - { label: '6 Months', period: 180 }, - { label: '1 Year', period: 365 }, { label: 'ALL', period: 1000 }, + { label: '1 Year', period: 365 }, + { label: '6 Months', period: 180 }, + { label: '1 Month', period: 30 }, ] const supportedNetworks = Object.keys(networks) @@ -200,24 +200,27 @@ export function State() {

State of Unlock

-
-

Overview

+
-
-

Activity over time

+
+

+ Activity over time +

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

Gross Network Product

+
+

+ 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 index 100141c86a1..78f86f738cb 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -37,7 +37,7 @@ function ViewFilter({ setViewFilter: (value: IViewFilter) => void }) { return ( -
+
{views.map((view, index) => (
JSX.Element @@ -36,20 +35,6 @@ export function Overview({ lockStats }) { Icon: ActiveLock, }, ] - // const gnpDataByNetworks = lockStats.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) } }, [lockStats]) From 1446e3a4874b78f55365aa7c9eb89a8a1caebeea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Thu, 28 Mar 2024 17:21:23 +0100 Subject: [PATCH 07/13] clickable caption --- .../src/components/pages/State/index.tsx | 145 ++++++++++++++---- .../components/pages/State/sections/chart.tsx | 67 +------- 2 files changed, 121 insertions(+), 91 deletions(-) diff --git a/unlock-protocol-com/src/components/pages/State/index.tsx b/unlock-protocol-com/src/components/pages/State/index.tsx index a79871a1c7c..f4a8b633f22 100644 --- a/unlock-protocol-com/src/components/pages/State/index.tsx +++ b/unlock-protocol-com/src/components/pages/State/index.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useState } from 'react' import { networks } from '@unlock-protocol/networks' import { getSubgraph4GNP } from 'src/hooks/useSubgraph' +import * as Plot from '@observablehq/plot' // sections components import { Overview } from './sections/overview' @@ -26,14 +27,72 @@ type ILockStats = { type IFilter = { period: number - selectedNetwork?: number | undefined + selectedNetworks: string[] +} + +interface IViewFilter { + label: string + value: string +} + +const views = [ + { + label: 'Locks deployed', + value: 'lockDeployed', + }, + { + label: 'Locks active', + value: 'activeLocks', + }, + { + label: 'Keys', + value: 'keySold', + }, + { + label: 'Locks deployed (cumulative)', + value: 'totalLockDeployed', + }, + { + label: 'Keys (cumulative)', + value: 'totalKeysSold', + }, +] + +function ViewFilter({ + viewFilter, + setViewFilter, +}: { + viewFilter: IViewFilter + setViewFilter: (value: IViewFilter) => void +}) { + return ( +
+ {views.map((view, index) => ( +
setViewFilter(view)} + key={index} + > +

+ {view.label} +

+
+ ))} +
+ ) } const timeFilters = [ - { label: 'ALL', period: 1000 }, - { label: '1 Year', period: 365 }, - { label: '6 Months', period: 180 }, { label: '1 Month', period: 30 }, + { label: '6 Months', period: 180 }, + { label: '1 Year', period: 365 }, + { label: 'ALL', period: 1000 }, ] const supportedNetworks = Object.keys(networks) @@ -57,11 +116,11 @@ function isWithin(date, days) { } function filterData({ dailyStats, filter }) { - const { period, selectedNetwork } = filter + const { period, selectedNetworks } = filter return dailyStats.filter(({ chain, date }) => - isWithin(date, period) && (!selectedNetwork || selectedNetwork === 'ALL') + isWithin(date, period) && !selectedNetworks.length ? true - : chain === selectedNetwork + : selectedNetworks.includes(chain) ) } @@ -73,7 +132,7 @@ function DateFilter({ setFilter: (value: IFilter) => void }) { return ( -
+
{timeFilters.map(({ label, period }, index) => (

void }) { + const handleOnChange = (selectedChain) => { + const updatedSelectedNetworks = filter.selectedNetworks.includes( + selectedChain + ) + ? filter.selectedNetworks.filter((chain) => chain !== selectedChain) + : [...filter.selectedNetworks, selectedChain] + console.log({ updatedSelectedNetworks }) + setFilter({ ...filter, selectedNetworks: updatedSelectedNetworks }) + } + + const color = Plot.scale({ + color: { + scheme: 'Tableau10', + domain: supportedNetworks.map((_, i) => i), + }, + }) + return ( - handleOnChange(chain)} + /> {name} - + ))} - +

) } @@ -127,7 +202,11 @@ export function State() { const currentDay = Math.round(new Date().getTime() / 86400000) const [dailyStats, setDailyStats] = useState([]) const [lockStats, setLockStats] = useState([]) - const [filter, setFilter] = useState({ period: 1000 }) + const [filter, setFilter] = useState({ + period: 1000, + selectedNetworks: [], + }) + const [viewFilter, setViewFilter] = useState(views[1]) const [filteredData, setFilteredData] = useState([]) // get data from all subgraphs @@ -207,15 +286,21 @@ export function State() {

Activity over time

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

diff --git a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx index 78f86f738cb..2bddb91573c 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -1,67 +1,13 @@ import React, { useRef, useEffect, useState } from 'react' import * as Plot from '@observablehq/plot' -interface IViewFilter { - label: string - value: string -} - -const views = [ - { - label: 'Locks deployed', - value: 'lockDeployed', - }, - { - label: 'Locks active', - value: 'activeLocks', - }, - { - label: 'Keys', - value: 'keySold', - }, - { - label: 'Locks deployed (cumulative)', - value: 'totalLockDeployed', - }, - { - label: 'Keys (cumulative)', - value: 'totalKeysSold', - }, -] - -function ViewFilter({ +export function HistoricalChart({ + dailyStats, + filter, + supportedNetworks, viewFilter, - setViewFilter, -}: { - viewFilter: IViewFilter - setViewFilter: (value: IViewFilter) => void }) { - return ( -

- {views.map((view, index) => ( -
setViewFilter(view)} - key={index} - > -

- {view.label} -

-
- ))} -
- ) -} - -export function HistoricalChart({ dailyStats, filter }) { const ref = useRef() - const [viewFilter, setViewFilter] = useState(views[1]) useEffect(() => { const barChart = Plot.plot({ @@ -78,8 +24,8 @@ export function HistoricalChart({ dailyStats, filter }) { color: { type: 'categorical', scheme: 'Tableau10', - legend: true, - // width: 628, + legend: false, + domain: supportedNetworks.map(({ name }) => name), label: 'Networks', }, marks: [ @@ -107,7 +53,6 @@ export function HistoricalChart({ dailyStats, filter }) { return (
-
) From a8ba62f5b85a63984ca70da09218df2f36957e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Thu, 28 Mar 2024 17:29:23 +0100 Subject: [PATCH 08/13] deafult to all checked --- unlock-protocol-com/src/components/pages/State/index.tsx | 6 +++--- .../src/components/pages/State/sections/chart.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/unlock-protocol-com/src/components/pages/State/index.tsx b/unlock-protocol-com/src/components/pages/State/index.tsx index f4a8b633f22..f0adbcbef8b 100644 --- a/unlock-protocol-com/src/components/pages/State/index.tsx +++ b/unlock-protocol-com/src/components/pages/State/index.tsx @@ -204,7 +204,7 @@ export function State() { const [lockStats, setLockStats] = useState([]) const [filter, setFilter] = useState({ period: 1000, - selectedNetworks: [], + selectedNetworks: supportedNetworks.map(({ chain }) => chain), }) const [viewFilter, setViewFilter] = useState(views[1]) const [filteredData, setFilteredData] = useState([]) @@ -299,10 +299,10 @@ export function State() { /> )}
-
+
-
+

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 index 2bddb91573c..5f79b124681 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -52,7 +52,7 @@ export function HistoricalChart({ }, [dailyStats, viewFilter]) return ( -
+
) From ed60f0030225546edfc3b7f74edebbe38b2234c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Thu, 28 Mar 2024 17:46:57 +0100 Subject: [PATCH 09/13] add tooltip --- unlock-protocol-com/next.config.js | 2 +- .../src/components/pages/State/sections/chart.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/unlock-protocol-com/next.config.js b/unlock-protocol-com/next.config.js index 5aa81c2d853..c8f395d75fc 100644 --- a/unlock-protocol-com/next.config.js +++ b/unlock-protocol-com/next.config.js @@ -70,7 +70,7 @@ Object.keys(requiredConfigVariables).forEach((configVariableName) => { const nextConfig = { output: 'export', - distDir: 'out', + // distDir: 'out', images: { unoptimized: true, }, diff --git a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx index 5f79b124681..787b9b6727e 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -41,6 +41,7 @@ export function HistoricalChart({ y: viewFilter.value, fill: 'name', interval: filter.period <= 365 ? 'day' : 'week', + tip: 'x', } ) ), From 6e7f2513a7b6389d78a0d8f59f6503c6d8241f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Fri, 29 Mar 2024 10:13:18 +0100 Subject: [PATCH 10/13] better typing --- .../components/pages/State/sections/chart.tsx | 6 +-- .../components/pages/State/sections/gnp.tsx | 21 +++++--- unlock-protocol-com/src/utils/apiRequest.ts | 52 ++++++++++++++----- 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx index 787b9b6727e..745027ee30c 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -1,4 +1,4 @@ -import React, { useRef, useEffect, useState } from 'react' +import React, { useRef, useEffect } from 'react' import * as Plot from '@observablehq/plot' export function HistoricalChart({ @@ -7,7 +7,7 @@ export function HistoricalChart({ supportedNetworks, viewFilter, }) { - const ref = useRef() + const ref = useRef() useEffect(() => { const barChart = Plot.plot({ @@ -50,7 +50,7 @@ export function HistoricalChart({ ref.current?.append(barChart) return () => barChart.remove() - }, [dailyStats, viewFilter]) + }, [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 index e3ad523ec4a..de59a4c5e2c 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/gnp.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/gnp.tsx @@ -4,12 +4,21 @@ 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([]) + const [gnpValues, setGNPValues] = useState([]) useEffect(() => { const run = async () => { const values = await getGNPs() + console.log(values) values.sort((a, b) => { if (a.total < b.total) return 1 if (a.total > b.total) return -1 @@ -23,24 +32,24 @@ export function GNP() { return (
{gnpValues - .filter((item) => !item.network.isTestNetwork) - .map(({ total, network }, index) => ( + .filter(({ isTestNetwork }) => !isTestNetwork) + .map(({ total, name, nativeCurrencySymbol }, index) => (
-

{network.name}

+

{name}

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

- {network.nativeCurrency.symbol} + {nativeCurrencySymbol}

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) From bb471f7462a820dbf413c99543842217438e6633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Fri, 29 Mar 2024 10:53:32 +0100 Subject: [PATCH 11/13] fix time selector --- unlock-protocol-com/src/components/pages/State/index.tsx | 9 ++++----- .../src/components/pages/State/sections/chart.tsx | 1 - .../src/components/pages/State/sections/gnp.tsx | 1 - 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/unlock-protocol-com/src/components/pages/State/index.tsx b/unlock-protocol-com/src/components/pages/State/index.tsx index f0adbcbef8b..d4d22fc3818 100644 --- a/unlock-protocol-com/src/components/pages/State/index.tsx +++ b/unlock-protocol-com/src/components/pages/State/index.tsx @@ -117,10 +117,10 @@ function isWithin(date, days) { function filterData({ dailyStats, filter }) { const { period, selectedNetworks } = filter - return dailyStats.filter(({ chain, date }) => - isWithin(date, period) && !selectedNetworks.length - ? true - : selectedNetworks.includes(chain) + return dailyStats.filter( + ({ chain, date }) => + isWithin(date, period) && + (!selectedNetworks.length ? true : selectedNetworks.includes(chain)) ) } @@ -167,7 +167,6 @@ function NetworkRadioPicker({ ) ? filter.selectedNetworks.filter((chain) => chain !== selectedChain) : [...filter.selectedNetworks, selectedChain] - console.log({ updatedSelectedNetworks }) setFilter({ ...filter, selectedNetworks: updatedSelectedNetworks }) } diff --git a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx index 745027ee30c..bf260f438ea 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -8,7 +8,6 @@ export function HistoricalChart({ viewFilter, }) { const ref = useRef() - useEffect(() => { const barChart = Plot.plot({ width: 1200, diff --git a/unlock-protocol-com/src/components/pages/State/sections/gnp.tsx b/unlock-protocol-com/src/components/pages/State/sections/gnp.tsx index de59a4c5e2c..abdbeb5c3eb 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/gnp.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/gnp.tsx @@ -18,7 +18,6 @@ export function GNP() { useEffect(() => { const run = async () => { const values = await getGNPs() - console.log(values) values.sort((a, b) => { if (a.total < b.total) return 1 if (a.total > b.total) return -1 From 0878b4fc36c402463bda231eba9ac3556a125dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Fri, 29 Mar 2024 14:52:37 +0100 Subject: [PATCH 12/13] show active locks from last 30 days only --- unlock-protocol-com/src/components/pages/State/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/unlock-protocol-com/src/components/pages/State/index.tsx b/unlock-protocol-com/src/components/pages/State/index.tsx index d4d22fc3818..57ffe831234 100644 --- a/unlock-protocol-com/src/components/pages/State/index.tsx +++ b/unlock-protocol-com/src/components/pages/State/index.tsx @@ -258,6 +258,7 @@ export function State() { id, ...lockStats, activeLocks: unlockDailyDatas + .filter(({ date }) => isWithin(date, 30)) // last 30 days .map(({ activeLocks }) => activeLocks) .reduce((pv, a) => pv + a, 0), }) From d1cf5c871098503945b91763fd1969645d8c8745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renaud?= Date: Fri, 29 Mar 2024 15:56:41 +0100 Subject: [PATCH 13/13] use native cumulative option --- unlock-protocol-com/src/components/pages/State/index.tsx | 7 +++++-- .../src/components/pages/State/sections/chart.tsx | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/unlock-protocol-com/src/components/pages/State/index.tsx b/unlock-protocol-com/src/components/pages/State/index.tsx index 57ffe831234..f492b30311e 100644 --- a/unlock-protocol-com/src/components/pages/State/index.tsx +++ b/unlock-protocol-com/src/components/pages/State/index.tsx @@ -33,6 +33,7 @@ type IFilter = { interface IViewFilter { label: string value: string + cumulative?: boolean } const views = [ @@ -50,11 +51,13 @@ const views = [ }, { label: 'Locks deployed (cumulative)', - value: 'totalLockDeployed', + value: 'lockDeployed', + cumulative: true, }, { label: 'Keys (cumulative)', - value: 'totalKeysSold', + value: 'keySold', + cumulative: true, }, ] diff --git a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx index bf260f438ea..66dd63d5bda 100644 --- a/unlock-protocol-com/src/components/pages/State/sections/chart.tsx +++ b/unlock-protocol-com/src/components/pages/State/sections/chart.tsx @@ -41,6 +41,7 @@ export function HistoricalChart({ fill: 'name', interval: filter.period <= 365 ? 'day' : 'week', tip: 'x', + cumulative: viewFilter.cumulative, } ) ),