diff --git a/src/api/LatestDataApi.ts b/src/api/LatestDataApi.ts index a583994f..8f9cc848 100644 --- a/src/api/LatestDataApi.ts +++ b/src/api/LatestDataApi.ts @@ -14,7 +14,13 @@ import { MAIN_LATEST_TRANSACTION_URL, wrapResponse, } from "./index"; -import { BlockProps, RawTransactionI } from "./types"; +import { + BlockProps, + ChartDataProps, + DashboardStatsProps, + RawTransactionI, + SmartContractStatsProps, +} from "./types"; const MAX_ROW = 5; @@ -76,4 +82,25 @@ export default { }; }); }, + getDashboardStats: async ( + network: NetworkConnection + ): Promise => { + const baseUrl = getBaseUrl(network); + const res = await fetch(`${baseUrl}/api/v2/stats`); + return wrapResponse(res); + }, + getSmartContractStats: async ( + network: NetworkConnection + ): Promise => { + const baseUrl = getBaseUrl(network); + const res = await fetch(`${baseUrl}/api/v2/smart-contracts/counters`); + return wrapResponse(res); + }, + getTxnChartsData: async ( + network: NetworkConnection + ): Promise => { + const baseUrl = getBaseUrl(network); + const res = await fetch(`${baseUrl}/api/v2/stats/charts/transactions`); + return wrapResponse(res); + }, }; diff --git a/src/api/types.ts b/src/api/types.ts index b2461cb9..97e31a69 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -246,6 +246,43 @@ export interface RawTransactionV1 { status: string; } +export interface DashboardStatsProps { + average_block_time: number; + coin_price: string; + gas_prices: { + average: number; + fast: number; + slow: number; + }; + average: number; + fast: number; + slow: number; + gas_used_today: string; + market_cap: string; + network_utilization_percentage: number; + static_gas_price: string | null; + total_addresses: string; + total_blocks: string; + total_gas_used: string; + total_transactions: string; + transactions_today: string; +} + +export interface SmartContractStatsProps { + new_smart_contracts_24h: string; + new_verified_smart_contracts_24h: string; + smart_contracts: string; + verified_smart_contracts: string; +} +export interface ChartDataI { + date: string; + tx_count: number; +} + +export interface ChartDataProps { + chart_data: ChartDataI[]; +} + export interface AddressProps { hash: string; implementation_name: string | null; diff --git a/src/components/GroupStatisticCard.tsx b/src/components/GroupStatisticCard.tsx index 3104ccd1..172b3b83 100644 --- a/src/components/GroupStatisticCard.tsx +++ b/src/components/GroupStatisticCard.tsx @@ -1,34 +1,120 @@ -import React from "react"; +import { useState, useEffect } from "react"; import StatisticCard from "@components/commons/StatisticCard"; +import clsx from "clsx"; +import { MdCheckCircle } from "react-icons/md"; +import LatestDataApi from "@api/LatestDataApi"; +import { useNetwork } from "@contexts/NetworkContext"; +import BigNumber from "bignumber.js"; +import { DashboardStatsProps, SmartContractStatsProps } from "@api/types"; +import { GWEI_SYMBOL } from "shared/constants"; +import NumericFormat from "./commons/NumericFormat"; + +export default function GroupStatisticCard() { + const { connection } = useNetwork(); + const [isLoading, setIsLoading] = useState(false); + const [dashboardStats, setDashboardStats] = useState(); + const [smartContractStats, setSmartContractStats] = + useState(); + const fetchStats = async () => { + setIsLoading(true); + const dashStats = await LatestDataApi.getDashboardStats(connection); + setDashboardStats(dashStats); + const scStats = await LatestDataApi.getSmartContractStats(connection); + setSmartContractStats(scStats); + setIsLoading(false); + }; + + useEffect(() => { + fetchStats(); + }, []); -function GroupStatisticCard() { - const groupStatsCardContent = [ - { - title: "24h total value locked", - body: "3232400000", - footer: "+2.34%", - testId: "24h-total-value-locked", - }, - { - title: "24h transactions", - body: "32324000000", - footer: "-0.02%", - testId: "24h-total-transactions", - }, - ]; return ( -
- {groupStatsCardContent.map((card) => ( +
+
- ))} + title="Blocks" + value={new BigNumber(dashboardStats?.total_blocks ?? 0)} + testId="blocks" + isLoading={isLoading} + > + + {`Avg. speed: ${new BigNumber( + dashboardStats?.average_block_time ?? 0 + ) + .dividedBy(1000) + .toFixed(1)} sec`} + + + + + + + + + + + + + + + + + + +
); } - -export default GroupStatisticCard; diff --git a/src/components/TokenStatsDisplay.tsx b/src/components/TokenStatsDisplay.tsx index 6fc6daa1..6f40b888 100644 --- a/src/components/TokenStatsDisplay.tsx +++ b/src/components/TokenStatsDisplay.tsx @@ -1,9 +1,8 @@ -import clsx from "clsx"; -import TokenStatsApi from "@api/TokenStatsApi"; -import { useUnitSuffix } from "hooks/useUnitSuffix"; -import { DMX_TOKEN_SYMBOL } from "shared/constants"; -import TrendLineChart, { LineData } from "./TrendLineChart"; -import GradientCardContainer from "./commons/GradientCardContainer"; +import { useState, useEffect } from "react"; +import LatestDataApi from "@api/LatestDataApi"; +import { useNetwork } from "@contexts/NetworkContext"; +import { ChartDataI } from "@api/types"; +import TransactionsLineChart from "./TransactionsLineChart"; export interface TokenStats { tokenPrice: number; @@ -14,87 +13,32 @@ export interface TokenStats { } export default function TokenStatsDisplay(): JSX.Element { - const stats: TokenStats = TokenStatsApi.useTokenStats(); - const priceHistory = TokenStatsApi.useTokenPriceHistory(); + const { connection } = useNetwork(); + const [chartData, setChartData] = useState([]); - const trendLineData: LineData[] = priceHistory.map((data) => ({ - value: data.price, - })); + const fetchStats = async () => { + const data = await LatestDataApi.getTxnChartsData(connection); + setChartData(data.chart_data?.reverse()); + }; - return ( -
- -
-
- -
-
- -
-
- -
-
-
-
- ); -} + useEffect(() => { + fetchStats(); + }, []); -function TokenPriceSection({ data }: { data: TokenStats }) { return ( - <> -
-
-
-
- DefiMetaChain Token -
-
- {DMX_TOKEN_SYMBOL} -
-
-
-
- ${data.tokenPrice} -
-
- {data.percentChange >= 0 ? "+" : ""} - {data.percentChange}% -
+
+
+
+ + {" "} + Transaction history + + in 30 days
+
+ +
- - ); -} - -function DetailsSection({ data }: { data: TokenStats }) { - const circulation = useUnitSuffix(data.circulation); - const last24hVolume = useUnitSuffix(data.last24hVolume); - const marketCap = useUnitSuffix(data.marketCap); - return ( -
- - - -
- ); -} - -function DetailRow({ label, value }: { label: string; value: string }) { - const labelStyle = "text-white-700 md:pr-2"; - const valueStyle = "text-right text-white-50"; - return ( -
-
{label}
-
{value}
); } diff --git a/src/components/TransactionsLineChart.tsx b/src/components/TransactionsLineChart.tsx new file mode 100644 index 00000000..1499c288 --- /dev/null +++ b/src/components/TransactionsLineChart.tsx @@ -0,0 +1,104 @@ +import { ChartDataI } from "@api/types"; +import { + LineChart, + Line, + ResponsiveContainer, + XAxis, + YAxis, + Tooltip, + CartesianGrid, +} from "recharts"; +import dayjs from "dayjs"; +import NumericFormat from "./commons/NumericFormat"; + +function CustomizedTickX(props) { + const { x, y, payload } = props; + return ( + + + + {dayjs(payload.value).format("MMM D")} + + + + ); +} + +function CustomizedTickY(props) { + const { x, y, payload } = props; + const formatter = Intl.NumberFormat("en", { notation: "compact" }); + return ( + + + + {formatter.format(payload.value)} + + + + ); +} + +function CustomTooltip({ active, payload, label }) { + if (active && payload && payload.length) { + return ( +
+
+ {dayjs(label).format("MMM D, YYYY")} +
+ {payload.map((pld) => ( +
+ Transactions: + +
+ ))} +
+ ); + } + return null; +} + +export default function TransactionsLineChart({ + data, +}: { + data: ChartDataI[]; +}) { + return ( + + + } + /> + } + /> + + + + + + ); +} diff --git a/src/components/commons/StatisticCard.tsx b/src/components/commons/StatisticCard.tsx index 18ff82c7..75a1817a 100644 --- a/src/components/commons/StatisticCard.tsx +++ b/src/components/commons/StatisticCard.tsx @@ -1,38 +1,57 @@ -import React from "react"; -import clsx from "clsx"; -import { useUnitSuffix } from "hooks/useUnitSuffix"; +import React, { PropsWithChildren } from "react"; +import BigNumber from "bignumber.js"; import GradientCardContainer from "./GradientCardContainer"; +import NumericFormat from "./NumericFormat"; interface StatsCardProps { title: string; - body: string; - footer: string; + value: BigNumber; testId: string; + isLoading: boolean; + suffix?: string; } -function StatisticCard({ title, body, footer, testId }: StatsCardProps) { - const valueToUnitSuffix = useUnitSuffix(body); - +export default function StatisticCard({ + title, + value, + children, + suffix, + testId, + isLoading, +}: PropsWithChildren) { return ( - -
-
+ +
+
{title}
-
- {valueToUnitSuffix} +
+ {isLoading ? ( +
+
+
+ ) : ( + + )}
-
+ {isLoading ? ( +
+
+
+ ) : ( +
+ {children} +
)} - > - {footer}
); } - -export default StatisticCard; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 2971bba1..b6410e6a 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,11 +1,11 @@ -// import GroupStatisticCard from "@components/GroupStatisticCard"; -// import TokenStatsDisplay from "@components/TokenStatsDisplay"; import HomeTitle from "@components/HomeTitle"; import { SearchBar } from "layouts/components/searchbar/SearchBar"; import { GetServerSidePropsResult, InferGetServerSidePropsType } from "next"; import { RowData } from "@components/types"; import LatestDataTable from "@components/LatestDataTable"; import LatestDataApi from "@api/LatestDataApi"; +import GroupStatisticCard from "@components/GroupStatisticCard"; +import TokenStatsDisplay from "@components/TokenStatsDisplay"; export default function Home({ latestTransactions, @@ -17,9 +17,8 @@ export default function Home({
- {/* */} - {/* */} - {/* TODO: Add blocks and txs summary card */} + +