Skip to main content

HeroWithForm and leads API

This document describes how HeroWithForm submits lead data, how formType maps to backend routes in BootcampHero/api.js, and how to wire pages such as docs/autoanalytics-new/book-a-demo.md.

Step-by-step: New form on a new product page

Use this when you add a new product (or a new route) that should show HeroWithForm and post to a leads API. You do not create a second form component; you wire formType and (if needed) one block of API code.

Part A — Backend agreement (do this first)

  1. Confirm the HTTP contract with whoever owns the API:

    • Full path pattern (e.g. POST .../v1/leads/<slug> on local/dev/test and POST .../api/v1/leads/<slug> on live, if that matches your server).
    • Request JSON fields. Today HeroForm always sends the same shape as submitAemBuyerGuideForm: name, email, company, phoneNumber, message, consent, captchaToken, pageUrl. If the new product needs different fields, you must extend HeroForm.js (and possibly add a dedicated submit function) — that is outside the “same payload” path.
  2. Choose a stable formType string (lowercase, hyphenated), e.g. my-product. This value will appear in page frontmatter and in getHeroWithFormHandler.

Part B — Register a new formType in api.js (skip if an existing type already points to the right URL)

Only complete these when getHeroWithFormHandler does not yet list your product.

  1. Add paths for every environment in API_CONFIG (local, dev, test, live): add something like myProductPath: '/v1/leads/my-product' for non-live and /api/v1/leads/my-product for live, following the same pattern as trueMeasurePath / infracentralPath.

  2. Add an endpoint getter, e.g. getMyProductApiEndpoint(siteConfig), mirroring existing getters:

    • If siteConfig.customFields.myProductApiUrl is set → return it (full URL).
    • Else if siteConfig.customFields.leadsApiUrl is set → return `${leadsApiUrl}/my-product` (slug must match backend).
    • Else → `${config.baseUrl}${config.myProductPath}` using getEnvironment().
  3. Add a submit wrapper if the payload matches the shared hero payload: submitMyProductForm can delegate to submitAemBuyerGuideForm(formData, apiUrl) with apiUrl defaulted to getMyProductApiEndpoint().

  4. Wire the switch: in getHeroWithFormHandler, add a case 'my-product': returning { endpoint: getMyProductApiEndpoint(siteConfig), submit: submitMyProductForm }.

  5. Optional — docusaurus.config.js: expose myProductApiUrl under customFields if you need a full-URL override per environment (same idea as trueMeasureApiUrl / infracentralApiUrl).

Part C — Product markdown (source of truth for copy and formType)

  1. Create (or extend) a doc under the product’s docs tree, e.g. docs/<product-slug>/book-a-demo.md. The first fenced frontmatter block for the hero should look like:

    ---
    component: HeroWithForm
    formType: my-product
    formHeading: Book a Free Demo
    formId: <product>-book-a-demo-form
    successMessage: Thank you! We will contact you shortly.
    seo:
    description: <page meta description>
    ---
  2. Write the hero body below that frontmatter: headings, paragraphs, checkmark lines (✓ ...) as supported by LeftContent. Add further --- / component: ... sections for other blocks (stats, logos, etc.) if the page needs them.

  3. Uniqueness: formId must be unique on the page if multiple heroes or anchors exist; use a product-specific id (step 8).

Part D — Route and generated JSON (product pages that use content-data)

Many products render from src/pages/product/<product>/*.mdx, which import src/content-data/<product>/<file>.json. If your new page follows that pattern:

  1. Add or copy an MDX page under src/pages/product/<product>/, e.g. book-a-demo.mdx:

    • import sections from '@site/src/content-data/<product>/book-a-demo.json' (path must match the generator output).
    • Include HeroWithForm in componentMap (same pattern as src/pages/product/autoanalytics-new/book-a-demo.mdx).
  2. Regenerate section data so JSON matches the markdown. In this repo run npm run generate:content (runs node scripts/generate-section-data.mjs).

  3. Verify the generated file (e.g. src/content-data/<product>/book-a-demo.json): the first section with "component": "HeroWithForm" should show content.formType (and formId) exactly as in the doc frontmatter.

  4. Restart or hard-refresh if the dev server does not pick up JSON changes.

Part E — Local verification

  1. Run the site (npm run start / npm run serve). Open the new product URL.

  2. Submit the form and inspect Network: the request URL must match the environment (e.g. local → http://localhost:8000/api/v1/leads/<slug> when using default local config). If you use LEADS_API_URL or customFields, confirm the resolved URL.

  3. Fix env issues: ERR_CONNECTION_REFUSED on localhost:8000 means no API is listening locally — point LEADS_API_URL at a reachable dev API or run the backend.


Summary: New product page with an existing formType → do Part C (and E). New API slug → do Part A, B, then C and E.

Goals

  • One hero + form UI for multiple products (no duplicate form components).
  • Each page chooses which backend lead endpoint to use via formType.
  • Environment-specific base URLs (local, dev, test, live) stay centralized in api.js.

Component layout

FileRole
src/components/HeroWithForm/index.jsLayout: background, left column (LeftContent), right column (HeroForm). Reads formType, formId, formHeading, successMessage, downloadConfig from content / seo.
src/components/HeroWithForm/HeroForm.jsForm UI, validation, reCAPTCHA, submit. Calls getHeroWithFormHandler(formType, siteConfig) to get endpoint + submit.
src/components/HeroWithForm/LeftContent.jsRenders markdown-derived blocks (headings, paragraphs, lists).
src/components/HeroWithForm/HeroWithForm.module.cssSection and form styling.

Frontmatter and content

HeroWithForm expects the usual section shape: content includes hero copy and form settings.

FieldRequiredDefaultDescription
formTypeNotrue-measureSelects which lead API handler to use (see below).
formIdNotrue-measureDOM id on the form card; used for accessibility hooks on the success dialog. Use a unique value if multiple heroes exist on one page.
formHeadingNo(empty)Shown above the form. Can also be set under seo.formHeading.
successMessageNoGeneric thank-youMessage in the success dialog.
filepath, file, formatNo(empty)Optional post-submit asset download; if omitted, the form may resolve a download from resource-index.json when the current path matches a resource entry.

Example: Autoanalytics New book-a-demo

Source: docs/autoanalytics-new/book-a-demo.md

---
component: HeroWithForm
formType: true-measure
formHeading: Book a Free Demo
formId: book-a-demo-form
successMessage: Thank you! Your demo request has been received. Our experts will contact you shortly.
seo:
description: Schedule a consultation with our experts
---
  • Change formType to switch the API (e.g. infracentral, aem-buyer-guide) without changing React code.
  • formId can stay a stable marketing id (e.g. book-a-demo-form) as long as it is unique per page.

API layer: src/components/BootcampHero/api.js

Environment detection

getEnvironment() uses window.location.hostname to pick local, dev, test, or live, with a default of local.

Lead paths used by HeroWithForm

Per environment, API_CONFIG includes paths such as:

  • aemBuyerGuidePath: /v1/leads/aem-buyer-guide (local/dev/test) or /api/v1/leads/aem-buyer-guide (live).
  • trueMeasurePath: /v1/leads/true-measure or /api/v1/leads/true-measure.
  • infracentralPath: /v1/leads/infracentral or /api/v1/leads/infracentral.

Full URLs are built as baseUrl + path for the active environment.

getHeroWithFormHandler(formType, siteConfig)

This is the single switch used by HeroForm:

formType (case-insensitive)Endpoint helperSubmit function
true-measure (default)getTrueMeasureApiEndpointsubmitTrueMeasureForm
infracentralgetInfracentralApiEndpointsubmitInfracentralForm
aem-buyer-guidegetAemBuyerGuideApiEndpointsubmitAemBuyerGuideForm

submitTrueMeasureForm and submitInfracentralForm delegate to submitAemBuyerGuideForm with the resolved URL, so the JSON body is the same shape for these hero variants:

  • name, email, company, phoneNumber, message, consent, captchaToken, pageUrl

Optional overrides via docusaurus.config.js (customFields)

You can override endpoints without code changes when needed:

customFields keyUsed by
leadsApiUrlBase like .../v1/leads; TrueMeasure appends /true-measure, Infracentral appends /infracentral.
trueMeasureApiUrlFull URL for TrueMeasure.
infracentralApiUrlFull URL for Infracentral.
aemBuyerGuideApiUrlFull URL for AEM Buyer’s Guide.
captchaSiteKeyreCAPTCHA site key (see getCaptchaSiteKey).

Product pages and generated JSON (reference)

Product MDX often imports src/content-data/.../*.json, e.g. src/pages/product/autoanalytics-new/book-a-demo.mdxsrc/content-data/autoanalytics-new/book-a-demo.json. Editing docs/... alone does not update the live page until you regenerate JSON and reload; see Part D in the step-by-step above.

  • src/components/HeroWithForm/index.js — passes formType into HeroForm.
  • src/components/HeroWithForm/HeroForm.jsgetHeroWithFormHandler + submit.
  • src/components/BootcampHero/api.jsAPI_CONFIG, getters, getHeroWithFormHandler, submit helpers.
  • docs/autoanalytics-new/book-a-demo.md — example frontmatter for HeroWithForm.