refactor: inline single-child _components/ wrappers into page.tsx#18078
Conversation
✅ Deploy Preview for ethereumorg ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
c33e3da to
8b56811
Compare
Apply the server-first page composition convention across 8 routes: staking, community, gas, layer-2, layer-2/learn, run-a-node, roadmap/_vision, and contributing/translation-program/contributors. Each page previously delegated to a single ./_components/<name>.tsx client wrapper that only used useTranslation. Inlined the UI into the page-level async server component, replacing the client useTranslation hook with next-intl's getTranslations. Where the wrapper used usePathname only to feed Breadcrumbs, replaced it with a literal SLUG constant. Add "use client" to StakingHierarchy since its onClick handlers previously inherited client-ness from the staking wrapper.
c4b1f71 to
793b1ac
Compare
There was a problem hiding this comment.
Nice cleanup overall — the convention reads well and the wrappers were carrying their weight in client bundle for not much reason. One blocker before this can ship.
Cross-namespace t() calls in app/[locale]/gas/page.tsx
The old wrapper used the project's custom useTranslation hook (src/hooks/useTranslation.ts), which splits keys on : to support lookups across namespaces. next-intl's stock getTranslations does not, so two calls in gas/page.tsx will render their literal key strings in production:
- Line 415:
alt={t("page-community:page-community-explore-dapps-alt")} - Line 422:
{t("page-community:page-community-explore-dapps")}
page-community-explore-dapps-alt and page-community-explore-dapps live in page-community.json, not page-gas.json, so the lookup misses inside the page-gas scope. getMessageFallback then returns the segment after the last ., which (since neither key contains a .) is the whole literal — the alt text and button label both render as "page-community:page-community-explore-dapps-..." strings.
Suggested fix:
const t = await getTranslations("page-gas")
const tCommunity = await getTranslations("page-community")
// ...
alt={tCommunity("page-community-explore-dapps-alt")}
// ...
{tCommunity("page-community-explore-dapps")}The other seven migrations look clean on this front — multi-namespace useTranslation([...]) was correctly split into multiple getTranslations() calls with every call site rewritten.
Minor — ExpandableCard icon spacing
The svg prop change from React.FC to ReactNode is a reasonable simplification, and the only caller (run-a-node) was updated. One side-effect worth eyeballing on the deploy preview: the icon used to be rendered with a forced mr-6 (1.5rem) inside ExpandableCard; that's now replaced by gap-8 (2rem) on the parent HStack, so the icon-to-title spacing changes very slightly. Probably fine, but worth a quick look.
Reviewed by Claude Opus 4.7
wackerow
left a comment
There was a problem hiding this comment.
Pushed a patch for above issue -- good to go, thanks @pettinarip!

Summary
Apply the server-first page composition convention across 8 routes that each delegated their entire UI to a single
./_components/<name>.tsxclient wrapper:stakingcommunitygaslayer-2layer-2/learnrun-a-noderoadmap/_visioncontributing/translation-program/contributorsEach previous wrapper was
"use client"only because of the customuseTranslationhook. Inlined the UI into the page-level async server component and swapped to next-intl'sgetTranslations. Where the wrapper usedusePathnameonly to feed<Breadcrumbs>, replaced it with a literalSLUGconstant.Net effect: -217 lines, 7 client-bundle wrappers removed, all 8 pages now render as server components.
Why
A single nested wrapper turned each page into a stub that just forwarded params. Readers had to open two files to understand one route, and the wrapper reflexively pulled the entire UI into the client bundle when most of it could render on the server.
app/[locale]/bug-bounty/page.tsxwas the canonical counter-example; these 8 now follow it.Notes
StakingHierarchygained"use client"since itsonClickhandlers previously inherited client-ness from the removed staking wrapper.assets,acknowledgements,quizzes,staking/deposit-contract) were intentionally left alone — they useuseColorModeValue,useState,useEffect, or click handlers, so the wrapper is justified per the convention.Test plan
pnpm buildsucceeds/contributing/translation-program/contributors,/layer-2/learn,and/roadmap/visionen