Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8e35750
feat(pages/resources): get blobscan api data
TylerAPfledderer Apr 21, 2025
25597af
feat(pages/resources): add pectra schedule
TylerAPfledderer Apr 22, 2025
b9158d7
refactor(page/resources): show average blob fee in usd
TylerAPfledderer Apr 28, 2025
a504bc1
fix(useResources): to avg blob fee conversion from wei
TylerAPfledderer Apr 28, 2025
55a27de
Merge remote-tracking branch 'upstream/dev' into feat/dashboard-pectr…
TylerAPfledderer May 7, 2025
d31aa0e
add mock data for blobscanOverallStats
pettinarip May 8, 2025
040d7bb
refactor(useResources): simplify formatSmallUSD
TylerAPfledderer May 8, 2025
eba75bf
refactor(useResources): add countdown for scaling upgrade
TylerAPfledderer May 9, 2025
9771acf
refactor(useResources): set link for Pectra page
TylerAPfledderer May 9, 2025
472b762
Merge remote-tracking branch 'upstream/dev' into feat/dashboard-pectr…
TylerAPfledderer May 18, 2025
15408bb
Merge remote-tracking branch 'upstream/dev' into feat/dashboard-pectr…
TylerAPfledderer May 23, 2025
bf9423a
refactor(useResources): update label for latest scaling upgrade
TylerAPfledderer May 23, 2025
c35f66d
Merge branch 'dev' into pr/15324
wackerow Oct 31, 2025
2aaa16f
refactor: extract client-side component
wackerow Oct 31, 2025
69de9e1
fix: blobstats fetch data struct
wackerow Oct 31, 2025
195836c
refactor: use humanize-duration
wackerow Oct 31, 2025
1dd199b
patch: typo
wackerow Oct 31, 2025
bbfe6eb
fix(ui): layout padding, use BigNumber
wackerow Nov 4, 2025
edd4626
i18n: extract strings
wackerow Nov 4, 2025
2a924eb
i18n: localize humanizeDuration options
wackerow Nov 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions app/[locale]/resources/_components/SlotCountdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,18 @@ const SlotCountdownChart = ({ children }: { children: string }) => {
}, [])

return (
<RadialChart
value={timeToNextBlock}
totalValue={12}
displayValue={new Intl.NumberFormat(locale, {
style: "unit",
unit: "second",
unitDisplay: "narrow",
}).format(timeToNextBlock)}
label={children}
/>
<div className="pb-8 pt-4">
<RadialChart
value={timeToNextBlock}
totalValue={12}
displayValue={new Intl.NumberFormat(locale, {
style: "unit",
unit: "second",
unitDisplay: "narrow",
}).format(timeToNextBlock)}
label={children}
/>
</div>
)
}

Expand Down
117 changes: 117 additions & 0 deletions app/[locale]/resources/_components/UpgradeCountdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"use client"

import { useEffect, useState } from "react"
import humanizeDuration from "humanize-duration"
import { useLocale } from "next-intl"

import type { NetworkUpgradeDetails } from "@/lib/types"

import { BaseLink } from "@/components/ui/Link"

import networkUpgradeSummaryData from "@/data/networkUpgradeSummaryData"

const getLatestNetworkUpgradeDate = () => {
const entries = Object.entries(networkUpgradeSummaryData) as [
string,
NetworkUpgradeDetails,
][]

const result = entries.reduce<[string | null, string | null]>(
(acc, [network, details]) => {
// include pending entries as long as they have a valid date string
if (typeof details.dateTimeAsString !== "string") return acc

const candidateTime = Date.parse(details.dateTimeAsString)
if (isNaN(candidateTime)) return acc

const [, accDate] = acc
if (!accDate) return [network, details.dateTimeAsString]

const accTime = Date.parse(accDate)
if (isNaN(accTime) || candidateTime > accTime) {
return [network, details.dateTimeAsString]
}

return acc
},
[null, null]
)

return result
}

const UpgradeCountdown = () => {
const locale = useLocale()
const [scalingUpgradeCountdown, setUpgradeCountdown] = useState<
string | null
>("Loading...")
const [upgrade, upgradeDate] = getLatestNetworkUpgradeDate()

useEffect(() => {
// Countdown time for Scaling Upgrade to the final date of May 7 2025
// const scalingUpgradeDate = new Date("2025-05-07T00:00:00Z")

const scalingUpgradeDate = new Date(upgradeDate || "2025-05-07T00:00:00Z")
const scalingUpgradeDateTime = scalingUpgradeDate.getTime()
const SECONDS = 1000

const countdown = () => {
const now = Date.now()
const timeLeft = scalingUpgradeDateTime - now

// If the date has past, set the countdown to null
if (timeLeft < 0) return setUpgradeCountdown(null)

const baseOptions = {
units: ["d", "h", "m", "s"],
round: true,
}

try {
setUpgradeCountdown(
humanizeDuration(timeLeft, {
...baseOptions,
language: locale,
})
)
} catch {
setUpgradeCountdown(humanizeDuration(timeLeft, baseOptions))
}
}
countdown()

let interval: NodeJS.Timeout | undefined

if (scalingUpgradeCountdown !== null) {
// Only run the interval if the date has not passed
interval = setInterval(countdown, SECONDS)
}

return () => clearInterval(interval)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

if (!upgrade || !upgradeDate) return "—"
return (
<>
<BaseLink
href={`/roadmap/${upgrade}/`}
className="text-5xl font-bold text-body no-underline hover:text-primary"
>
{upgrade.slice(0, 1).toUpperCase() + upgrade.slice(1)}
</BaseLink>
<div className="text-xl font-bold text-body-medium">
{scalingUpgradeCountdown ? (
scalingUpgradeCountdown
) : (
<div className="rounded-full bg-success px-2 py-1 text-xs font-normal uppercase text-success-light">
Live Since{" "}
{new Intl.DateTimeFormat(locale, {}).format(new Date(upgradeDate))}
</div>
)}
</div>
</>
)
}

export default UpgradeCountdown
28 changes: 25 additions & 3 deletions app/[locale]/resources/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { ResourceItem, ResourcesContainer } from "./_components/ResourcesUI"
import ResourcesPageJsonLD from "./page-jsonld"
import { getResources } from "./utils"

import { fetchBlobscanStats } from "@/lib/api/fetchBlobscanStats"
import { fetchGrowThePie } from "@/lib/api/fetchGrowThePie"
import heroImg from "@/public/images/heroes/guides-hub-hero.jpg"

Expand All @@ -34,7 +35,10 @@ const REVALIDATE_TIME = BASE_TIME_UNIT * 1
const EVENT_CATEGORY = "dashboard"

const loadData = dataLoader(
[["growThePieData", fetchGrowThePie]],
[
["growThePieData", fetchGrowThePie],
["blobscanOverallStats", fetchBlobscanStats],
],
REVALIDATE_TIME * 1000
)

Expand All @@ -44,10 +48,28 @@ const Page = async ({ params }: { params: PageParams }) => {
const t = await getTranslations({ locale, namespace: "page-resources" })

// Load data
const [growThePieData] = await loadData()
const [growThePieData, blobscanOverallStats] = await loadData()

const { txCostsMedianUsd } = growThePieData

const resourceSections = await getResources({ txCostsMedianUsd })
const blobStats =
"error" in blobscanOverallStats
? {
avgBlobFee: "—",
totalBlobs: "—",
}
: {
avgBlobFee: blobscanOverallStats.value.avgBlobFee,
totalBlobs: new Intl.NumberFormat(undefined, {
notation: "compact",
maximumFractionDigits: 1,
}).format(blobscanOverallStats.value.totalBlobs),
}

const resourceSections = await getResources({
txCostsMedianUsd,
...blobStats,
})

const commitHistoryCache: CommitHistory = {}
const { contributors } = await getAppPageContributorInfo(
Expand Down
56 changes: 52 additions & 4 deletions app/[locale]/resources/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { getLocale, getTranslations } from "next-intl/server"

import { Lang } from "@/lib/types"

import BigNumber from "@/components/BigNumber"
import SectionIconArrowsFullscreen from "@/components/icons/arrows-fullscreen.svg"
import SectionIconEthGlyph from "@/components/icons/eth-glyph.svg"
import SectionIconEthWallet from "@/components/icons/eth-wallet.svg"
Expand All @@ -13,10 +14,9 @@ import { Spinner } from "@/components/ui/spinner"
import { formatSmallUSD } from "@/lib/utils/numbers"
import { getLocaleForNumberFormat } from "@/lib/utils/translations"

import BigNumber from "../../../src/components/BigNumber"

import type { DashboardBox, DashboardSection } from "./types"

import { fetchEthPrice } from "@/lib/api/fetchEthPrice"
import IconBeaconchain from "@/public/images/resources/beaconcha-in.png"
import IconBlobsGuru from "@/public/images/resources/blobsguru.png"
import IconBlocknative from "@/public/images/resources/blocknative.png"
Expand Down Expand Up @@ -65,13 +65,42 @@ const SlotCountdownChart = dynamic(
),
}
)

const UpgradeCountdownFigure = dynamic(
() => import("./_components/UpgradeCountdown"),
{
ssr: false,
loading: () => (
<div className="grid h-32 place-items-center">
<Spinner />
</div>
),
}
)

export const getResources = async ({
txCostsMedianUsd,
totalBlobs,
avgBlobFee,
}): Promise<DashboardSection[]> => {
const locale = await getLocale()
const t = await getTranslations({ locale, namespace: "page-resources" })
const localeForNumberFormat = getLocaleForNumberFormat(locale as Lang)

const ethPrice = await fetchEthPrice()

const avgBlobFeeUsd =
"error" in ethPrice
? { error: ethPrice.error }
: {
...ethPrice,
value: formatSmallUSD(
// Converting value from wei to USD
avgBlobFee * 1e-18 * ethPrice.value,
localeForNumberFormat
),
}

const medianTxCost =
"error" in txCostsMedianUsd
? { error: txCostsMedianUsd.error }
Expand Down Expand Up @@ -351,7 +380,14 @@ export const getResources = async ({
const scalingBoxes: DashboardBox[] = [
{
title: t("page-resources-roadmap-title"),
// TODO: Add metric
metric: (
<div className="grid place-items-center py-8">
<div className="text-sm">
{t("page-resources-roadmap-metric-label")}
</div>
<UpgradeCountdownFigure />
</div>
),
items: [
{
title: "Ethereum Roadmap",
Expand All @@ -363,7 +399,19 @@ export const getResources = async ({
},
{
title: t("page-resources-blobs-title"),
// TODO: Add metric
metric: (
<div className="flex gap-4">
<BigNumber className="items-center" value={totalBlobs}>
{t("page-resources-blobs-metric-total-label")}
</BigNumber>
<BigNumber
className="items-center"
value={"value" in avgBlobFeeUsd ? avgBlobFeeUsd.value : "—"}
>
{t("page-resources-blobs-metric-fee-label")}
</BigNumber>
</div>
),
items: [
{
title: "Blob Scan",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"gray-matter": "^4.0.3",
"howler": "^2.2.4",
"htmr": "^1.0.2",
"humanize-duration": "^3.33.1",
"lodash": "^4.17.21",
"lucide-react": "^0.516.0",
"next": "^14.2.32",
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions src/components/History/NetworkUpgradeSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { Flex, Stack } from "@/components/ui/flex"

import { getLocaleForNumberFormat } from "@/lib/utils/translations"

import NetworkUpgradeSummaryData from "../../data/NetworkUpgradeSummaryData"
import networkUpgradeSummaryData from "@/data/networkUpgradeSummaryData"

import Emoji from "../Emoji"
import InlineLink from "../ui/Link"

Expand All @@ -32,7 +33,7 @@ const NetworkUpgradeSummary = ({ name }: NetworkUpgradeSummaryProps) => {
blockNumber,
epochNumber,
slotNumber,
} = NetworkUpgradeSummaryData[name]
} = networkUpgradeSummaryData[name]
// TODO fix dateTimeAsString

// calculate date format only on the client side to avoid hydration issues
Expand Down
18 changes: 18 additions & 0 deletions src/data/mocks/blobscanOverallStats.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"avgBlobAsCalldataFee": 18402670294113620,
"avgBlobFee": 1337454615991715,
"avgBlobGasPrice": 4657716809.805255,
"avgMaxBlobGasFee": 19666167416.48503,
"totalBlobGasUsed": "875492278272",
"totalBlobAsCalldataGasUsed": "12165759474144",
"totalBlobFee": "4174952855822794358784",
"totalBlobAsCalldataFee": "57445149899315095107588",
"totalBlobs": 6679476,
"totalBlobSize": "875492278272",
"totalBlocks": 1664933,
"totalTransactions": 3121566,
"totalUniqueBlobs": 6575105,
"totalUniqueReceivers": 5361,
"totalUniqueSenders": 5941,
"updatedAt": "2025-03-25T11:45:00.590Z"
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { NetworkUpgradeData } from "@/lib/types"

const NetworkUpgradeSummaryData: NetworkUpgradeData = {
const networkUpgradeSummaryData: NetworkUpgradeData = {
pectra: {
dateTimeAsString: "2025-05-07T10:05:11.000Z",
ethPriceInUSD: 2222,
Expand Down Expand Up @@ -228,4 +228,4 @@ const NetworkUpgradeSummaryData: NetworkUpgradeData = {
},
}

export default NetworkUpgradeSummaryData
export default networkUpgradeSummaryData
3 changes: 3 additions & 0 deletions src/intl/en/page-resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,11 @@
"page-resources-adoption-cryptowerk-description": "Ethereum adoption analytics based on Cryptwerk merchants database - map, countries, companies, businesses, categories, rating.",
"page-resources-adoption-reserves-description": "A dashboard for the Strategic Ethereum Reserve initiative.",
"page-resources-roadmap-title": "Ethereum Roadmap",
"page-resources-roadmap-metric-label": "Latest upgrade",
"page-resources-roadmap-ethroadmap-description": "Detailed visualization on Ethereum roadmap and the next network upgrade.",
"page-resources-blobs-title": "Blobs",
"page-resources-blobs-metric-total-label": "Total blobs",
"page-resources-blobs-metric-fee-label": "Average Blob Fee",
"page-resources-blobs-blobscan-description": "Comprehensive blob scanner.",
"page-resources-blobs-blobsguru-description": "Ethereum Blobs Explorer: Analyze L2 transactions & EIP-4844 data.",
"page-resources-nodes-title": "Nodes",
Expand Down
Loading