Skip to content

Commit 886c8be

Browse files
committed
feat: initialize ActivityStats with stablecoins mcap
template remaining items
1 parent 21d9531 commit 886c8be

File tree

9 files changed

+224
-15
lines changed

9 files changed

+224
-15
lines changed

app/[locale]/enterprise/page.tsx

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { getTranslations } from "next-intl/server"
33

44
import type { Lang } from "@/lib/types"
55

6+
import ActivityStats from "@/components/ActivityStats"
67
import { HubHero } from "@/components/Hero"
78
import Checkmark from "@/components/icons/checkmark.svg"
89
import Adidas from "@/components/icons/enterprise/adidas.svg"
@@ -37,17 +38,20 @@ import Walmart from "@/components/icons/enterprise/walmart.svg"
3738
import WFP from "@/components/icons/enterprise/wfp.svg"
3839
import MainArticle from "@/components/MainArticle"
3940
import { ButtonLink } from "@/components/ui/buttons/Button"
40-
import { Skeleton } from "@/components/ui/skeleton"
4141

4242
import { cn } from "@/lib/utils/cn"
43+
// import { dataLoader } from "@/lib/utils/data/dataLoader"
4344
import { getMetadata } from "@/lib/utils/metadata"
4445

46+
// import { BASE_TIME_UNIT } from "@/lib/constants"
4547
import CasesColumn from "./_components/CasesColumn"
4648
import FeatureCard from "./_components/FeatureCard"
4749
import { ENTERPRISE_MAILTO } from "./constants"
4850
import SwiperHangerLoading from "./SwiperHangerLoading"
4951
import type { Case, EcosystemPlayer, Feature } from "./types"
52+
import { parseActivity } from "./utils"
5053

54+
import { fetchEthereumStablecoinsMcap } from "@/lib/api/fetchEthereumStablecoinsMcap"
5155
import EthGlyph from "@/public/images/assets/svgs/eth-diamond-rainbow.svg"
5256
import heroImage from "@/public/images/heroes/enterprise-hero-white.png"
5357

@@ -61,10 +65,29 @@ const CasesSwiper = dynamic(() => import("./_components/CasesSwiper"), {
6165
loading: () => <SwiperHangerLoading />,
6266
})
6367

68+
// TODO: Switch back to this for cache and mock-data dev fallback
69+
// const loadData = dataLoader(
70+
// [["ethereumStablecoinsResponse", fetchEthereumStablecoinsMcap]],
71+
// BASE_TIME_UNIT * 1000
72+
// )
73+
6474
const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
6575
const { locale } = await params
76+
6677
const t = await getTranslations({ locale, namespace: "page-enterprise" })
6778

79+
// const [ethereumStablecoinsResponse] = await loadData()
80+
const ethereumStablecoinsResponse = await fetchEthereumStablecoinsMcap()
81+
82+
const metrics = await parseActivity(
83+
{
84+
// dailyTxCount,
85+
stablecoinMarketCap: ethereumStablecoinsResponse,
86+
// totalCapitalSecured,
87+
},
88+
locale
89+
)
90+
6891
const features: Feature[] = [
6992
{
7093
header: t("page-enterprise-features-1-header"),
@@ -234,11 +257,14 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
234257
},
235258
},
236259
]}
237-
className="[&_[data-label='breadcrumb']]:xl:text-body-light [&_[data-label='hero-content']]:xl:bg-accent-a [&_[data-label='hero-content']]:xl:text-background [&_a:hover]:bg-body [&_a:hover]:!text-background [&_a]:font-bold [&_a]:xl:bg-background [&_a]:xl:text-accent-a [&_img]:dark:invert"
260+
className="[&_[data-label='breadcrumb']]:xl:text-body-light [&_[data-label='hero-content']]:xl:bg-accent-a [&_[data-label='hero-content']]:xl:text-background xl:[&_a:hover]:bg-accent-a-hover xl:[&_a:hover]:!text-background [&_a]:font-bold [&_a]:xl:bg-background [&_a]:xl:text-accent-a [&_img]:dark:invert"
238261
/>
239262

240263
<MainArticle className="space-y-12 px-4 md:space-y-20 md:px-10">
241-
<section id="metrics" className="flex flex-col gap-6 md:flex-row">
264+
<section
265+
id="activity"
266+
className="flex flex-col justify-between gap-6 md:flex-row"
267+
>
242268
<div className="max-w-prose space-y-4">
243269
<h2>{t("page-enterprise-metrics-header")}</h2>
244270
<p>
@@ -250,11 +276,24 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
250276
economy.
251277
</p>
252278
</div>
253-
<div className="TODO:METRICS flex max-w-[min(41rem,100%)] gap-6 md:ms-auto">
279+
280+
<ActivityStats
281+
metrics={metrics}
282+
locale={locale}
283+
className={cn(
284+
"w-fit max-w-xl shrink-0 gap-8 sm:max-md:grid-cols-2",
285+
"[&_[data-label='big-number']]:border-none [&_[data-label='big-number']]:p-0",
286+
"[&_[data-label='big-number']:nth-of-type(1)_[data-label='value']]:text-accent-a",
287+
"[&_[data-label='big-number']:nth-of-type(2)_[data-label='value']]:text-accent-b",
288+
"[&_[data-label='big-number']:nth-of-type(3)_[data-label='value']]:text-accent-c"
289+
)}
290+
/>
291+
292+
{/* <div className="TODO:METRICS flex max-w-[min(41rem,100%)] gap-6 md:ms-auto">
254293
<Skeleton className="h-32 w-64 rounded-2xl" />
255294
<Skeleton className="h-32 w-64 rounded-2xl" />
256295
<Skeleton className="h-32 w-64 rounded-2xl" />
257-
</div>
296+
</div> */}
258297
</section>
259298

260299
<section id="features">

app/[locale]/enterprise/utils.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { getTranslations } from "next-intl/server"
2+
3+
import type {
4+
AllEnterpriseActivityData,
5+
Lang,
6+
StatsBoxMetric,
7+
} from "@/lib/types"
8+
9+
import { /* formatLargeNumber, */ formatLargeUSD } from "@/lib/utils/numbers"
10+
import { getLocaleForNumberFormat } from "@/lib/utils/translations"
11+
12+
// Convert numerical value to formatted values
13+
export const parseActivity = async (
14+
{
15+
// dailyTxCount,
16+
stablecoinMarketCap,
17+
// totalCapitalSecured,
18+
}: AllEnterpriseActivityData,
19+
locale: Lang
20+
): Promise<StatsBoxMetric[]> => {
21+
const t = await getTranslations("page-enterprise")
22+
23+
const localeForNumberFormat = getLocaleForNumberFormat(locale)
24+
25+
// const dailyTxCountFormatted =
26+
// "error" in dailyTxCount
27+
// ? { error: dailyTxCount.error }
28+
// : {
29+
// ...dailyTxCount,
30+
// value: formatLargeNumber(dailyTxCount.value, localeForNumberFormat),
31+
// }
32+
33+
const stablecoinMarketCapFormatted =
34+
"error" in stablecoinMarketCap
35+
? { error: stablecoinMarketCap.error }
36+
: {
37+
...stablecoinMarketCap,
38+
value: formatLargeUSD(
39+
stablecoinMarketCap.value,
40+
localeForNumberFormat
41+
),
42+
}
43+
44+
// const totalCapitalSecuredFormatted =
45+
// "error" in totalCapitalSecured
46+
// ? { error: totalCapitalSecured.error }
47+
// : {
48+
// ...totalCapitalSecured,
49+
// value: formatLargeUSD(
50+
// totalCapitalSecured.value,
51+
// localeForNumberFormat
52+
// ),
53+
// }
54+
55+
const metrics: StatsBoxMetric[] = [
56+
// {
57+
// // TODO
58+
// label: t("page-enterprise-activity-daily-tx"),
59+
// apiProvider: "TBD",
60+
// apiUrl: "https://www.TBD.com",
61+
// state: dailyTxCountFormatted,
62+
// },
63+
{
64+
label: t("page-enterprise-activity-stablecoin-mktcap"),
65+
apiProvider: "CoinGecko",
66+
apiUrl: "https://www.coingecko.com/en/categories/stablecoins",
67+
state: stablecoinMarketCapFormatted,
68+
},
69+
// {
70+
// // TODO
71+
// label: t("page-enterprise-activity-total-secured"),
72+
// apiProvider: "TBD",
73+
// apiUrl: "https://www.TBD.com",
74+
// state: totalCapitalSecuredFormatted,
75+
// },
76+
]
77+
78+
return metrics
79+
}

app/[locale]/page.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import { getTranslations, setRequestLocale } from "next-intl/server"
55
import { FaDiscord, FaGithub } from "react-icons/fa6"
66
import { FaXTwitter } from "react-icons/fa6"
77

8-
import type { AllMetricData, CommunityBlog, ValuesPairing } from "@/lib/types"
8+
import type {
9+
AllHomepageActivityData,
10+
CommunityBlog,
11+
ValuesPairing,
12+
} from "@/lib/types"
913
import type { EventCardProps } from "@/lib/types"
1014
import type { Lang } from "@/lib/types"
1115
import { CodeExample } from "@/lib/interfaces"
1216

1317
import ActivityStats from "@/components/ActivityStats"
14-
import { getActivity } from "@/components/ActivityStats/getActivity"
1518
import BannerNotification from "@/components/Banners/BannerNotification"
1619
import { ChevronNext } from "@/components/Chevron"
1720
import HomeHero from "@/components/Hero/HomeHero"
@@ -78,6 +81,7 @@ import {
7881
} from "@/lib/constants"
7982

8083
import TenYearHomeBanner from "./10years/_components/TenYearHomeBanner"
84+
import { getActivity } from "./utils"
8185

8286
import SimpleDomainRegistryContent from "!!raw-loader!@/data/SimpleDomainRegistry.sol"
8387
import SimpleTokenContent from "!!raw-loader!@/data/SimpleToken.sol"
@@ -410,7 +414,7 @@ const Page = async ({ params }: { params: Promise<{ locale: Lang }> }) => {
410414
)
411415
.slice(0, 3) as EventCardProps[] // Show 3 events ending soonest
412416

413-
const metricResults: AllMetricData = {
417+
const metricResults: AllHomepageActivityData = {
414418
ethPrice,
415419
totalEthStaked,
416420
totalValueLocked,

src/components/ActivityStats/getActivity.tsx renamed to app/[locale]/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { getTranslations } from "next-intl/server"
77

8-
import type { AllMetricData, Lang, StatsBoxMetric } from "@/lib/types"
8+
import type { AllHomepageActivityData, Lang, StatsBoxMetric } from "@/lib/types"
99

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

@@ -44,7 +44,7 @@ export const getActivity = async (
4444
txCount,
4545
txCostsMedianUsd,
4646
ethPrice,
47-
}: AllMetricData,
47+
}: AllHomepageActivityData,
4848
locale: Lang
4949
): Promise<StatsBoxMetric[]> => {
5050
const t = await getTranslations("page-index")

src/components/ActivityStats/index.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
11
import type { StatsBoxMetric } from "@/lib/types"
22

3+
import { cn } from "@/lib/utils/cn"
4+
35
import BigNumber from "../BigNumber"
46

57
type ActivityStatsProps = {
68
metrics: StatsBoxMetric[]
79
locale: string
10+
className?: string
811
}
9-
const ActivityStats = async ({ metrics, locale }: ActivityStatsProps) => {
12+
const ActivityStats = async ({
13+
metrics,
14+
locale,
15+
className,
16+
}: ActivityStatsProps) => {
1017
const gridBorderClasses = [
1118
"border-b border-body-light xl:border-e xl:pe-8",
1219
"border-b border-body-light xl:ps-8",
1320
"border-b border-body-light xl:border-b-0 xl:border-e xl:pe-8",
1421
"xl:ps-8",
1522
]
1623
return (
17-
<div className="grid w-full grid-cols-1 xl:grid-cols-2">
24+
<div className={cn("grid w-full grid-cols-1 xl:grid-cols-2", className)}>
1825
{metrics.map(({ label, apiProvider, apiUrl, state }, idx) => (
1926
<BigNumber
2027
locale={locale}

src/intl/en/page-enterprise.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
{
22
"page-enterprise-": "",
3+
"page-enterprise-activity-daily-tx": "Daily transactions",
4+
"page-enterprise-activity-stablecoin-mktcap": "Stablecoin market cap",
5+
"page-enterprise-activity-total-secured": "Total capital secured",
36
"page-enterprise-ecosystem-cta": "See use cases",
47
"page-enterprise-ecosystem-description": "The question is not whether money will become programmable, but how quickly the transition will occur and which platforms will enable it.",
58
"page-enterprise-ecosystem-header": "Embrace the innovation",
69
"page-enterprise-features-1-content-1": "Ethereum is secured by thousands of independent validators worldwide, providing resilient, open-access infrastructure for digital assets and enterprise applications.",
7-
"page-enterprise-features-1-content-2": "",
810
"page-enterprise-features-1-header": "Proven Security and Decentralization",
911
"page-enterprise-features-2-content-1": "Ethereum offers great flexibility and powerful scaling options known as Layer 2s.",
1012
"page-enterprise-features-2-content-2": "Its Proof-of-Stake consensus also cuts energy use by ~99.5%, meeting ESG goals without sacrificing performance.",
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { MetricReturnData } from "../types"
2+
3+
export type LlamaStablecoinchainsResponseItem = {
4+
gecko_id: string | null
5+
totalCirculatingUSD: Record<string, number>
6+
tokenSymbol: string | null
7+
name: string
8+
}
9+
10+
export async function fetchEthereumStablecoinsMcap(): Promise<MetricReturnData> {
11+
const url = "https://stablecoins.llama.fi/stablecoinchains"
12+
13+
try {
14+
const response = await fetch(url)
15+
if (!response.ok) {
16+
console.log(response.status, response.statusText)
17+
throw new Error("Failed to fetch llama.fi stablecoin mcap data")
18+
}
19+
const data: LlamaStablecoinchainsResponseItem[] = await response.json()
20+
21+
const ethereumData = data.find(({ gecko_id }) => gecko_id === "ethereum")
22+
if (!ethereumData) throw new Error("Ethereum stablecoin data not found")
23+
24+
const value = Object.values(ethereumData.totalCirculatingUSD).reduce(
25+
(acc, value) => acc + value,
26+
0
27+
)
28+
29+
return { value }
30+
} catch (error) {
31+
// Will not currently break build; passes back error key
32+
console.error(error)
33+
return {
34+
error:
35+
"Something went wrong with requesting the Ethereum stablecoins data.",
36+
}
37+
}
38+
}

src/lib/types.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,13 +563,26 @@ export type GrowThePieData = Record<GrowThePieMetricKey, MetricReturnData> & {
563563
activeAddresses: Record<string, number | undefined>
564564
}
565565

566-
export type MetricName =
566+
export type HomepageActivityMetric =
567567
| "ethPrice" // Use with `totalEthStaked` to convert ETH to USD
568568
| "totalEthStaked"
569569
| "totalValueLocked"
570570
| GrowThePieMetricKey
571571

572-
export type AllMetricData = Record<MetricName, MetricReturnData>
572+
export type AllHomepageActivityData = Record<
573+
HomepageActivityMetric,
574+
MetricReturnData
575+
>
576+
577+
export type EnterpriseActivityMetric =
578+
// | "dailyTxCount"
579+
"stablecoinMarketCap"
580+
// | "totalCapitalSecured"
581+
582+
export type AllEnterpriseActivityData = Record<
583+
EnterpriseActivityMetric,
584+
MetricReturnData
585+
>
573586

574587
export type StatsBoxMetric = {
575588
label: string

src/lib/utils/numbers.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export const formatLargeUSD = (value: number, locale: string): string => {
2+
return new Intl.NumberFormat(locale, {
3+
style: "currency",
4+
currency: "USD",
5+
notation: "compact",
6+
minimumSignificantDigits: 3,
7+
maximumSignificantDigits: 4,
8+
}).format(value)
9+
}
10+
11+
export const formatSmallUSD = (value: number, locale: string): string => {
12+
return new Intl.NumberFormat(locale, {
13+
style: "currency",
14+
currency: "USD",
15+
notation: "compact",
16+
minimumSignificantDigits: 2,
17+
maximumSignificantDigits: 2,
18+
}).format(value)
19+
}
20+
21+
export const formatLargeNumber = (value: number, locale: string): string => {
22+
return new Intl.NumberFormat(locale, {
23+
notation: "compact",
24+
minimumSignificantDigits: 3,
25+
maximumSignificantDigits: 4,
26+
}).format(value)
27+
}

0 commit comments

Comments
 (0)