feat(landing): upgrade built-in templates to live-data widgets (#429) - #488
Conversation
Set useLiveStats on all 14 StatsCounter instances (Puck Render does not backfill defaultProps for template content, so the flag must be explicit), add courseIds: [] to every CourseGrid to document the latest-courses curation contract, and swap the two dedicated catalog pages' static "All Courses" CourseGrid for the live CatalogBrowser with search and price filters. Static testimonial/team/pricing arrays stay as the no-data fallback — the live path already overrides them when tenant data exists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Visual verification — before / afterAll captures are from the admin preview route on the seeded Code Academy tenant (2 real courses, 2 real plans, 1 student). Before-shots were taken in a dark-theme session and after-shots in a light-theme session — the theme difference is incidental; compare the data in each section. Reviewer: please verify these visually before merging. Language School — Home: stats bandBefore — hard-coded placeholder stats ("8,000+ active students, 6 languages, 120+ native teachers") no matter which tenant applies the template: After — live tenant stats (1 student / 2 courses / 0 completions): Course Catalog: "All Courses" sectionBefore — plain static After — live Code School — About: statsBefore — fake story numbers ("12,000+ students, 40+ countries, 85% placement, founded 2019"): After — live tenant stats: Flow recordingThe GIF walks the upgraded "Language School — Home" page top to bottom (live stats → live courses → live pricing), then the upgraded "Course Catalog" page, including typing "python" into the new catalog search and clearing it: |
|
Shipped — squash-merged to master as 2b67ac0. Final scope, unchanged from the review body: QA record: |







Description
Upgrades all 33 static built-in landing templates to the live-data widgets shipped in #430, so a tenant applying any template sees their real courses, plans, and stats instead of fake placeholder numbers.
The survey behind this change found the gap was narrower than the issue assumed:
TestimonialGrid,TeamGrid, andPricingTablealready prefer live tenant data whenever it exists (live.length > 0 ? live : items) — their hard-coded arrays only ever render as the no-data fallback, which acceptance criterion 5 wants kept. The real bug was the stats blocks:StatsCounteronly goes live whenuseLiveStats === true, and Puck's<Render>does not backfilldefaultPropsfor content stored inpuck_data, so every applied template rendered fake numbers ("8,000+ students", "Founded 2019") forever.Changes made
useLiveStats: trueon all 14StatsCounterinstances (4 inindex.ts, 2 in each of the 5 vertical packs). Hard-codeditemsstay as the no-data fallback.courseIds: []on all 9 remainingCourseGridinstances — documents the "latest courses" curation contract and matches thefree-course-schoolreference template.CatalogBrowser: the "Course Catalog" and "Code School — Courses" templates swap their staticmaxItems: 12"All Courses"CourseGridfor the liveCatalogBrowser(search + Free/Paid filter + pagination), keeping each page's title/subtitle.SocialProof(already per-field live-aware);EnrollCtanot added — every home template already closes with a CTA block, andEnrollCtaonly adds value once an admin curates a specific course in the editor.No component, schema, or query changes — template data only. Existing saved
landing_pagesrows are snapshots and are unaffected; only pages created from templates after this change pick it up.Type of change
Relationship
Closes #429
Testing
npm run build— exit 0 (only pre-existingbigintbinding warnings)npm run gen:puck-fields— no diff (manifest derives fromlib/puck/config.ts, not templates; verified anyway)CatalogBrowser, and testimonial/team/pricing fallbacks still render for data the tenant lacks (reviews/instructors).QA verification steps
creator@codeacademy.com/password123oncode-academy.lvh.me:3005).Screenshots
Before/after screenshots and a verification GIF follow in a PR comment (private repo — uploaded as attachments).